LCOV - code coverage report
Current view: top level - EnergyPlus - WindTurbine.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 322 515 62.5 %
Date: 2024-08-23 23:50:59 Functions: 6 6 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cassert>
      50             : #include <cmath>
      51             : 
      52             : // ObjexxFCL Headers
      53             : #include <ObjexxFCL/Array.functions.hh>
      54             : #include <ObjexxFCL/Fmath.hh>
      55             : #include <ObjexxFCL/string.functions.hh>
      56             : 
      57             : // EnergyPlus Headers
      58             : #include <EnergyPlus/CommandLineInterface.hh>
      59             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      60             : #include <EnergyPlus/DataEnvironment.hh>
      61             : #include <EnergyPlus/DataHVACGlobals.hh>
      62             : #include <EnergyPlus/DataIPShortCuts.hh>
      63             : #include <EnergyPlus/FileSystem.hh>
      64             : #include <EnergyPlus/General.hh>
      65             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      66             : #include <EnergyPlus/OutputProcessor.hh>
      67             : #include <EnergyPlus/Psychrometrics.hh>
      68             : #include <EnergyPlus/ScheduleManager.hh>
      69             : #include <EnergyPlus/StringUtilities.hh>
      70             : #include <EnergyPlus/UtilityRoutines.hh>
      71             : #include <EnergyPlus/WindTurbine.hh>
      72             : 
      73             : namespace EnergyPlus {
      74             : 
      75             : // (ref: Object: Generator:WindTurbine)
      76             : 
      77             : namespace WindTurbine {
      78             :     // Module containing the data for wind turbine system
      79             : 
      80             :     // MODULE INFORMATION:
      81             :     //       AUTHOR         Daeho Kang
      82             :     //       DATE WRITTEN   October 2009
      83             :     //       MODIFIED       na
      84             :     //       RE-ENGINEERED  na
      85             : 
      86             :     // PURPOSE OF THIS MODULE:
      87             :     // This module is to calculate the electrical power output that wind turbine systems produce.
      88             :     // Both horizontal and vertical axis wind turbine systems are modeled.
      89             : 
      90             :     // REFERENCES:
      91             :     // Sathyajith Mathew. 2006. Wind Energy: Fundamental, Resource Analysis and Economics. Springer,
      92             :     //     Chap. 2, pp. 11-15
      93             :     // Mazharul Islam, David S.K. Ting, and Amir Fartaj. 2008. Aerodynamic Models for Darrieus-type sSraight-bladed
      94             :     //     Vertical Axis Wind Turbines. Renewable & Sustainable Energy Reviews, Volume 12, pp.1087-1109
      95             : 
      96             :     constexpr std::array<std::string_view, static_cast<int>(ControlType::Num)> ControlNamesUC{
      97             :         "FIXEDSPEEDFIXEDPITCH",
      98             :         "FIXEDSPEEDVARIABLEPITCH",
      99             :         "VARIABLESPEEDFIXEDPITCH",
     100             :         "VARIABLESPEEDVARIABLEPITCH",
     101             :     };
     102             : 
     103             :     constexpr std::array<std::string_view, static_cast<int>(RotorType::Num)> RotorNamesUC{
     104             :         "HORIZONTALAXISWINDTURBINE",
     105             :         "VERTICALAXISWINDTURBINE",
     106             :     };
     107             : 
     108       16236 :     void SimWindTurbine(EnergyPlusData &state,
     109             :                         [[maybe_unused]] GeneratorType const GeneratorType, // Type of Generator
     110             :                         std::string const &GeneratorName,                   // User specified name of Generator
     111             :                         int &GeneratorIndex,                                // Generator index
     112             :                         bool const RunFlag,                                 // ON or OFF
     113             :                         [[maybe_unused]] Real64 const WTLoad                // Electrical load on WT (not used)
     114             :     )
     115             :     {
     116             : 
     117             :         // SUBROUTINE INFORMATION:
     118             :         //       AUTHOR         Daeho Kang
     119             :         //       DATE WRITTEN   October 2009
     120             :         //       MODIFIED       na
     121             :         //       RE-ENGINEERED  na
     122             : 
     123             :         // PURPOSE OF THIS SUBROUTINE:
     124             :         // This subroutine manages the simulation of wind turbine component.
     125             :         // This drivers manages the calls to all of the other drivers and simulation algorithms.
     126             : 
     127             :         // Using/Aliasing
     128             : 
     129             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     130             :         int WindTurbineNum;
     131             :         // Obtains and allocates heat balance related parameters from input
     132             : 
     133       16236 :         if (state.dataWindTurbine->GetInputFlag) {
     134           1 :             GetWindTurbineInput(state);
     135           1 :             state.dataWindTurbine->GetInputFlag = false;
     136             :         }
     137             : 
     138       16236 :         if (GeneratorIndex == 0) {
     139           3 :             WindTurbineNum = Util::FindItemInList(GeneratorName, state.dataWindTurbine->WindTurbineSys);
     140           3 :             if (WindTurbineNum == 0) {
     141           0 :                 ShowFatalError(state, format("SimWindTurbine: Specified Generator not one of Valid Wind Turbine Generators {}", GeneratorName));
     142             :             }
     143           3 :             GeneratorIndex = WindTurbineNum;
     144             :         } else {
     145       16233 :             WindTurbineNum = GeneratorIndex;
     146       16233 :             int NumWindTurbines = (int)state.dataWindTurbine->WindTurbineSys.size();
     147       16233 :             if (WindTurbineNum > NumWindTurbines || WindTurbineNum < 1) {
     148           0 :                 ShowFatalError(state,
     149           0 :                                format("SimWindTurbine: Invalid GeneratorIndex passed={}, Number of Wind Turbine Generators={}, Generator name={}",
     150             :                                       WindTurbineNum,
     151             :                                       NumWindTurbines,
     152             :                                       GeneratorName));
     153             :             }
     154       16233 :             if (GeneratorName != state.dataWindTurbine->WindTurbineSys(WindTurbineNum).Name) {
     155           0 :                 ShowFatalError(state,
     156           0 :                                format("SimMWindTurbine: Invalid GeneratorIndex passed={}, Generator name={}, stored Generator Name for that index={}",
     157             :                                       WindTurbineNum,
     158             :                                       GeneratorName,
     159           0 :                                       state.dataWindTurbine->WindTurbineSys(WindTurbineNum).Name));
     160             :             }
     161             :         }
     162             : 
     163       16236 :         InitWindTurbine(state, WindTurbineNum);
     164             : 
     165       16236 :         CalcWindTurbine(state, WindTurbineNum, RunFlag);
     166             : 
     167       16236 :         ReportWindTurbine(state, WindTurbineNum);
     168       16236 :     }
     169             : 
     170       16236 :     void GetWTGeneratorResults(EnergyPlusData &state,
     171             :                                [[maybe_unused]] GeneratorType const GeneratorType, // Type of Generator
     172             :                                int const GeneratorIndex,                           // Generator number
     173             :                                Real64 &GeneratorPower,                             // Electrical power
     174             :                                Real64 &GeneratorEnergy,                            // Electrical energy
     175             :                                Real64 &ThermalPower,
     176             :                                Real64 &ThermalEnergy)
     177             :     {
     178             : 
     179             :         // SUBROUTINE INFORMATION:
     180             :         //       AUTHOR         B. Griffith
     181             :         //       DATE WRITTEN   Aug. 2008
     182             :         //       MODIFIED       D Kang, October 2009 for Wind Turbine
     183             :         //       RE-ENGINEERED  na
     184             : 
     185             :         // PURPOSE OF THIS SUBROUTINE:
     186             :         // This subroutine provides a "get" method to collect results for individual electic load centers.
     187             : 
     188       16236 :         GeneratorPower = state.dataWindTurbine->WindTurbineSys(GeneratorIndex).Power;
     189       16236 :         GeneratorEnergy = state.dataWindTurbine->WindTurbineSys(GeneratorIndex).Energy;
     190             : 
     191             :         // Thermal energy is ignored
     192       16236 :         ThermalPower = 0.0;
     193       16236 :         ThermalEnergy = 0.0;
     194       16236 :     }
     195             : 
     196           1 :     void GetWindTurbineInput(EnergyPlusData &state)
     197             :     {
     198             : 
     199             :         // SUBROUTINE INFORMATION:
     200             :         //       AUTHOR         Daeho Kang
     201             :         //       DATE WRITTEN   October 2009
     202             :         //       MODIFIED       na
     203             :         //       RE-ENGINEERED  na
     204             : 
     205             :         // PURPOSE OF THIS SUBROUTINE:
     206             :         // This subroutine gets input data for wind turbine components
     207             :         // and stores it in the wind turbine data structure.
     208             : 
     209             :         // Using/Aliasing
     210             : 
     211             :         using ScheduleManager::GetScheduleIndex;
     212             : 
     213             :         // SUBROUTINE PARAMETER DEFINITIONS:
     214           1 :         static std::string const CurrentModuleObject("Generator:WindTurbine");
     215           1 :         Real64 constexpr SysEffDefault(0.835); // Default value of overall system efficiency
     216           1 :         Real64 constexpr MaxTSR(12.0);         // Maximum tip speed ratio
     217           1 :         Real64 constexpr DefaultPC(0.25);      // Default power coefficient
     218           1 :         Real64 constexpr MaxPowerCoeff(0.59);  // Maximum power coefficient
     219           1 :         Real64 constexpr DefaultH(50.0);       // Default of height for local wind speed
     220             : 
     221             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     222           1 :         bool ErrorsFound(false); // If errors detected in input
     223             :         int WindTurbineNum;      // Wind turbine number
     224             :         int NumAlphas;           // Number of Alphas for each GetobjectItem call
     225             :         int NumNumbers;          // Number of Numbers for each GetobjectItem call
     226             :         int NumArgs;
     227             :         int IOStat;
     228           1 :         Array1D_string cAlphaArgs;     // Alpha input items for object
     229           1 :         Array1D_string cAlphaFields;   // Alpha field names
     230           1 :         Array1D_string cNumericFields; // Numeric field names
     231           1 :         Array1D<Real64> rNumericArgs;  // Numeric input items for object
     232           1 :         Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
     233           1 :         Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
     234             : 
     235             :         // Initializations and allocations
     236           1 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
     237           1 :         cAlphaArgs.allocate(NumAlphas);
     238           1 :         cAlphaFields.allocate(NumAlphas);
     239           1 :         cNumericFields.allocate(NumNumbers);
     240           1 :         rNumericArgs.dimension(NumNumbers, 0.0);
     241           1 :         lAlphaBlanks.dimension(NumAlphas, true);
     242           1 :         lNumericBlanks.dimension(NumNumbers, true);
     243             : 
     244           1 :         int NumWindTurbines = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     245             : 
     246           1 :         state.dataWindTurbine->WindTurbineSys.allocate(NumWindTurbines);
     247             : 
     248           4 :         for (WindTurbineNum = 1; WindTurbineNum <= NumWindTurbines; ++WindTurbineNum) {
     249             : 
     250           6 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     251             :                                                                      CurrentModuleObject,
     252             :                                                                      WindTurbineNum,
     253           3 :                                                                      state.dataIPShortCut->cAlphaArgs,
     254             :                                                                      NumAlphas,
     255           3 :                                                                      state.dataIPShortCut->rNumericArgs,
     256             :                                                                      NumNumbers,
     257             :                                                                      IOStat,
     258             :                                                                      lNumericBlanks,
     259             :                                                                      lAlphaBlanks,
     260             :                                                                      cAlphaFields,
     261             :                                                                      cNumericFields);
     262           3 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), CurrentModuleObject, ErrorsFound);
     263             : 
     264           3 :             auto &windTurbine = state.dataWindTurbine->WindTurbineSys(WindTurbineNum);
     265             : 
     266           3 :             windTurbine.Name = state.dataIPShortCut->cAlphaArgs(1); // Name of wind turbine
     267             : 
     268           3 :             windTurbine.Schedule = state.dataIPShortCut->cAlphaArgs(2); // Get schedule
     269           3 :             if (lAlphaBlanks(2)) {
     270           0 :                 windTurbine.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
     271             :             } else {
     272           3 :                 windTurbine.SchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
     273           3 :                 if (windTurbine.SchedPtr == 0) {
     274           0 :                     ShowSevereError(state,
     275           0 :                                     format("{}=\"{}\" invalid {}=\"{}\" not found.",
     276             :                                            CurrentModuleObject,
     277           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     278             :                                            cAlphaFields(2),
     279           0 :                                            state.dataIPShortCut->cAlphaArgs(2)));
     280           0 :                     ErrorsFound = true;
     281             :                 }
     282             :             }
     283             :             // Select rotor type
     284           3 :             windTurbine.rotorType =
     285           3 :                 static_cast<RotorType>(getEnumValue(WindTurbine::RotorNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(3))));
     286           3 :             if (windTurbine.rotorType == RotorType::Invalid) {
     287           0 :                 if (state.dataIPShortCut->cAlphaArgs(3).empty()) {
     288           0 :                     windTurbine.rotorType = RotorType::HorizontalAxis;
     289             :                 } else {
     290           0 :                     ShowSevereError(state,
     291           0 :                                     format("{}=\"{}\" invalid {}=\"{}\".",
     292             :                                            CurrentModuleObject,
     293           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     294             :                                            cAlphaFields(3),
     295           0 :                                            state.dataIPShortCut->cAlphaArgs(3)));
     296           0 :                     ErrorsFound = true;
     297             :                 }
     298             :             }
     299             : 
     300             :             // Select control type
     301           3 :             windTurbine.controlType =
     302           3 :                 static_cast<ControlType>(getEnumValue(WindTurbine::ControlNamesUC, Util::makeUPPER(state.dataIPShortCut->cAlphaArgs(4))));
     303           3 :             if (windTurbine.controlType == ControlType::Invalid) {
     304           0 :                 if (state.dataIPShortCut->cAlphaArgs(4).empty()) {
     305           0 :                     windTurbine.controlType = ControlType::VariableSpeedVariablePitch;
     306             :                 } else {
     307           0 :                     ShowSevereError(state,
     308           0 :                                     format("{}=\"{}\" invalid {}=\"{}\".",
     309             :                                            CurrentModuleObject,
     310           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     311             :                                            cAlphaFields(4),
     312           0 :                                            state.dataIPShortCut->cAlphaArgs(4)));
     313           0 :                     ErrorsFound = true;
     314             :                 }
     315             :             }
     316             : 
     317           3 :             windTurbine.RatedRotorSpeed = state.dataIPShortCut->rNumericArgs(1); // Maximum rotor speed in rpm
     318           3 :             if (windTurbine.RatedRotorSpeed <= 0.0) {
     319           0 :                 if (lNumericBlanks(1)) {
     320           0 :                     ShowSevereError(state,
     321           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     322             :                                            CurrentModuleObject,
     323           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     324             :                                            cNumericFields(1)));
     325             :                 } else {
     326           0 :                     ShowSevereError(state,
     327           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     328             :                                            CurrentModuleObject,
     329           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     330             :                                            cNumericFields(1),
     331             :                                            rNumericArgs(1)));
     332             :                 }
     333           0 :                 ErrorsFound = true;
     334             :             }
     335             : 
     336           3 :             windTurbine.RotorDiameter = state.dataIPShortCut->rNumericArgs(2); // Rotor diameter in m
     337           3 :             if (windTurbine.RotorDiameter <= 0.0) {
     338           0 :                 if (lNumericBlanks(2)) {
     339           0 :                     ShowSevereError(state,
     340           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     341             :                                            CurrentModuleObject,
     342           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     343             :                                            cNumericFields(2)));
     344             :                 } else {
     345           0 :                     ShowSevereError(state,
     346           0 :                                     format("{}=\"{}\" invalid {}=[{:.1R}] must be greater than zero.",
     347             :                                            CurrentModuleObject,
     348           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     349             :                                            cNumericFields(2),
     350             :                                            rNumericArgs(2)));
     351             :                 }
     352           0 :                 ErrorsFound = true;
     353             :             }
     354             : 
     355           3 :             windTurbine.RotorHeight = state.dataIPShortCut->rNumericArgs(3); // Overall height of the rotor
     356           3 :             if (windTurbine.RotorHeight <= 0.0) {
     357           0 :                 if (lNumericBlanks(3)) {
     358           0 :                     ShowSevereError(state,
     359           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     360             :                                            CurrentModuleObject,
     361           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     362             :                                            cNumericFields(3)));
     363             :                 } else {
     364           0 :                     ShowSevereError(state,
     365           0 :                                     format("{}=\"{}\" invalid {}=[{:.1R}] must be greater than zero.",
     366             :                                            CurrentModuleObject,
     367           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     368             :                                            cNumericFields(3),
     369             :                                            rNumericArgs(3)));
     370             :                 }
     371           0 :                 ErrorsFound = true;
     372             :             }
     373             : 
     374           3 :             windTurbine.NumOfBlade = state.dataIPShortCut->rNumericArgs(4); // Total number of blade
     375           3 :             if (windTurbine.NumOfBlade == 0) {
     376           0 :                 ShowSevereError(state,
     377           0 :                                 format("{}=\"{}\" invalid {}=[{:.0R}] must be greater than zero.",
     378             :                                        CurrentModuleObject,
     379           0 :                                        state.dataIPShortCut->cAlphaArgs(1),
     380             :                                        cNumericFields(4),
     381             :                                        rNumericArgs(4)));
     382           0 :                 ErrorsFound = true;
     383             :             }
     384             : 
     385           3 :             windTurbine.RatedPower = state.dataIPShortCut->rNumericArgs(5); // Rated average power
     386           3 :             if (windTurbine.RatedPower == 0.0) {
     387           0 :                 if (lNumericBlanks(5)) {
     388           0 :                     ShowSevereError(state,
     389           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     390             :                                            CurrentModuleObject,
     391           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     392             :                                            cNumericFields(5)));
     393             :                 } else {
     394           0 :                     ShowSevereError(state,
     395           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     396             :                                            CurrentModuleObject,
     397           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     398             :                                            cNumericFields(5),
     399             :                                            rNumericArgs(5)));
     400             :                 }
     401           0 :                 ErrorsFound = true;
     402             :             }
     403             : 
     404           3 :             windTurbine.RatedWindSpeed = state.dataIPShortCut->rNumericArgs(6); // Rated wind speed
     405           3 :             if (windTurbine.RatedWindSpeed == 0.0) {
     406           0 :                 if (lNumericBlanks(6)) {
     407           0 :                     ShowSevereError(state,
     408           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     409             :                                            CurrentModuleObject,
     410           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     411             :                                            cNumericFields(6)));
     412             :                 } else {
     413           0 :                     ShowSevereError(state,
     414           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     415             :                                            CurrentModuleObject,
     416           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     417             :                                            cNumericFields(6),
     418             :                                            rNumericArgs(6)));
     419             :                 }
     420           0 :                 ErrorsFound = true;
     421             :             }
     422             : 
     423           3 :             windTurbine.CutInSpeed = state.dataIPShortCut->rNumericArgs(7); // Minimum wind speed for system operation
     424           3 :             if (windTurbine.CutInSpeed == 0.0) {
     425           0 :                 if (lNumericBlanks(7)) {
     426           0 :                     ShowSevereError(state,
     427           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     428             :                                            CurrentModuleObject,
     429           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     430             :                                            cNumericFields(7)));
     431             :                 } else {
     432           0 :                     ShowSevereError(state,
     433           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     434             :                                            CurrentModuleObject,
     435           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     436             :                                            cNumericFields(7),
     437             :                                            rNumericArgs(7)));
     438             :                 }
     439           0 :                 ErrorsFound = true;
     440             :             }
     441             : 
     442           3 :             windTurbine.CutOutSpeed = state.dataIPShortCut->rNumericArgs(8); // Minimum wind speed for system operation
     443           3 :             if (windTurbine.CutOutSpeed == 0.0) {
     444           0 :                 if (lNumericBlanks(8)) {
     445           0 :                     ShowSevereError(state,
     446           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     447             :                                            CurrentModuleObject,
     448           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     449             :                                            cNumericFields(8)));
     450           0 :                 } else if (windTurbine.CutOutSpeed <= windTurbine.RatedWindSpeed) {
     451           0 :                     ShowSevereError(state,
     452           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than {}=[{:.2R}].",
     453             :                                            CurrentModuleObject,
     454           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     455             :                                            cNumericFields(8),
     456             :                                            rNumericArgs(8),
     457             :                                            cNumericFields(6),
     458             :                                            rNumericArgs(6)));
     459             :                 } else {
     460           0 :                     ShowSevereError(state,
     461           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero",
     462             :                                            CurrentModuleObject,
     463           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     464             :                                            cNumericFields(8),
     465             :                                            rNumericArgs(8)));
     466             :                 }
     467           0 :                 ErrorsFound = true;
     468             :             }
     469             : 
     470           3 :             windTurbine.SysEfficiency = state.dataIPShortCut->rNumericArgs(9); // Overall wind turbine system efficiency
     471           3 :             if (lNumericBlanks(9) || windTurbine.SysEfficiency == 0.0 || windTurbine.SysEfficiency > 1.0) {
     472           0 :                 windTurbine.SysEfficiency = SysEffDefault;
     473           0 :                 ShowWarningError(state,
     474           0 :                                  format("{}=\"{}\" invalid {}=[{:.2R}].",
     475             :                                         CurrentModuleObject,
     476           0 :                                         state.dataIPShortCut->cAlphaArgs(1),
     477             :                                         cNumericFields(9),
     478           0 :                                         state.dataIPShortCut->rNumericArgs(9)));
     479           0 :                 ShowContinueError(state, format("...The default value of {:.3R} was assumed. for {}", SysEffDefault, cNumericFields(9)));
     480             :             }
     481             : 
     482           3 :             windTurbine.MaxTipSpeedRatio = state.dataIPShortCut->rNumericArgs(10); // Maximum tip speed ratio
     483           3 :             if (windTurbine.MaxTipSpeedRatio == 0.0) {
     484           0 :                 if (lNumericBlanks(10)) {
     485           0 :                     ShowSevereError(state,
     486           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     487             :                                            CurrentModuleObject,
     488           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     489             :                                            cNumericFields(10)));
     490             :                 } else {
     491           0 :                     ShowSevereError(state,
     492           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     493             :                                            CurrentModuleObject,
     494           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     495             :                                            cNumericFields(10),
     496             :                                            rNumericArgs(10)));
     497             :                 }
     498           0 :                 ErrorsFound = true;
     499             :             }
     500           3 :             if (windTurbine.SysEfficiency > MaxTSR) {
     501           0 :                 windTurbine.SysEfficiency = MaxTSR;
     502           0 :                 ShowWarningError(state,
     503           0 :                                  format("{}=\"{}\" invalid {}=[{:.2R}].",
     504             :                                         CurrentModuleObject,
     505           0 :                                         state.dataIPShortCut->cAlphaArgs(1),
     506             :                                         cNumericFields(10),
     507           0 :                                         state.dataIPShortCut->rNumericArgs(10)));
     508           0 :                 ShowContinueError(state, format("...The default value of {:.1R} was assumed. for {}", MaxTSR, cNumericFields(10)));
     509             :             }
     510             : 
     511           3 :             windTurbine.MaxPowerCoeff = state.dataIPShortCut->rNumericArgs(11); // Maximum power coefficient
     512           3 :             if (windTurbine.rotorType == RotorType::HorizontalAxis && windTurbine.MaxPowerCoeff == 0.0) {
     513           0 :                 if (lNumericBlanks(11)) {
     514           0 :                     ShowSevereError(state,
     515           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     516             :                                            CurrentModuleObject,
     517           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     518             :                                            cNumericFields(11)));
     519             :                 } else {
     520           0 :                     ShowSevereError(state,
     521           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     522             :                                            CurrentModuleObject,
     523           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     524             :                                            cNumericFields(11),
     525             :                                            rNumericArgs(11)));
     526             :                 }
     527           0 :                 ErrorsFound = true;
     528             :             }
     529           3 :             if (windTurbine.MaxPowerCoeff > MaxPowerCoeff) {
     530           0 :                 windTurbine.MaxPowerCoeff = DefaultPC;
     531           0 :                 ShowWarningError(state,
     532           0 :                                  format("{}=\"{}\" invalid {}=[{:.2R}].",
     533             :                                         CurrentModuleObject,
     534           0 :                                         state.dataIPShortCut->cAlphaArgs(1),
     535             :                                         cNumericFields(11),
     536           0 :                                         state.dataIPShortCut->rNumericArgs(11)));
     537           0 :                 ShowContinueError(state, format("...The default value of {:.2R} will be used. for {}", DefaultPC, cNumericFields(11)));
     538             :             }
     539             : 
     540           3 :             windTurbine.LocalAnnualAvgWS = state.dataIPShortCut->rNumericArgs(12); // Local wind speed annually averaged
     541           3 :             if (windTurbine.LocalAnnualAvgWS == 0.0) {
     542           0 :                 if (lNumericBlanks(12)) {
     543           0 :                     ShowWarningError(state,
     544           0 :                                      format("{}=\"{}\" invalid {} is necessary for accurate prediction but input is blank.",
     545             :                                             CurrentModuleObject,
     546           0 :                                             state.dataIPShortCut->cAlphaArgs(1),
     547             :                                             cNumericFields(12)));
     548             :                 } else {
     549           0 :                     ShowSevereError(state,
     550           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     551             :                                            CurrentModuleObject,
     552           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     553             :                                            cNumericFields(12),
     554             :                                            rNumericArgs(12)));
     555           0 :                     ErrorsFound = true;
     556             :                 }
     557             :             }
     558             : 
     559           3 :             windTurbine.HeightForLocalWS = state.dataIPShortCut->rNumericArgs(13); // Height of local meteorological station
     560           3 :             if (windTurbine.HeightForLocalWS == 0.0) {
     561           0 :                 if (windTurbine.LocalAnnualAvgWS == 0.0) {
     562           0 :                     windTurbine.HeightForLocalWS = 0.0;
     563             :                 } else {
     564           0 :                     windTurbine.HeightForLocalWS = DefaultH;
     565           0 :                     if (lNumericBlanks(13)) {
     566           0 :                         ShowWarningError(state,
     567           0 :                                          format("{}=\"{}\" invalid {} is necessary for accurate prediction but input is blank.",
     568             :                                                 CurrentModuleObject,
     569           0 :                                                 state.dataIPShortCut->cAlphaArgs(1),
     570             :                                                 cNumericFields(13)));
     571           0 :                         ShowContinueError(state, format("...The default value of {:.2R} will be used. for {}", DefaultH, cNumericFields(13)));
     572             :                     } else {
     573           0 :                         ShowSevereError(state,
     574           0 :                                         format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     575             :                                                CurrentModuleObject,
     576           0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     577             :                                                cNumericFields(13),
     578             :                                                rNumericArgs(13)));
     579           0 :                         ErrorsFound = true;
     580             :                     }
     581             :                 }
     582             :             }
     583             : 
     584           3 :             windTurbine.ChordArea = state.dataIPShortCut->rNumericArgs(14); // Chord area of a single blade for VAWTs
     585           3 :             if (windTurbine.rotorType == RotorType::VerticalAxis && windTurbine.ChordArea == 0.0) {
     586           0 :                 if (lNumericBlanks(14)) {
     587           0 :                     ShowSevereError(state,
     588           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     589             :                                            CurrentModuleObject,
     590           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     591             :                                            cNumericFields(14)));
     592             :                 } else {
     593           0 :                     ShowSevereError(state,
     594           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     595             :                                            CurrentModuleObject,
     596           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     597             :                                            cNumericFields(14),
     598             :                                            rNumericArgs(14)));
     599             :                 }
     600           0 :                 ErrorsFound = true;
     601             :             }
     602             : 
     603           3 :             windTurbine.DragCoeff = state.dataIPShortCut->rNumericArgs(15); // Blade drag coefficient
     604           3 :             if (windTurbine.rotorType == RotorType::VerticalAxis && windTurbine.DragCoeff == 0.0) {
     605           0 :                 if (lNumericBlanks(15)) {
     606           0 :                     ShowSevereError(state,
     607           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     608             :                                            CurrentModuleObject,
     609           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     610             :                                            cNumericFields(15)));
     611             :                 } else {
     612           0 :                     ShowSevereError(state,
     613           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     614             :                                            CurrentModuleObject,
     615           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     616             :                                            cNumericFields(15),
     617             :                                            rNumericArgs(15)));
     618             :                 }
     619           0 :                 ErrorsFound = true;
     620             :             }
     621             : 
     622           3 :             windTurbine.LiftCoeff = state.dataIPShortCut->rNumericArgs(16); // Blade lift coefficient
     623           3 :             if (windTurbine.rotorType == RotorType::VerticalAxis && windTurbine.LiftCoeff == 0.0) {
     624           0 :                 if (lNumericBlanks(16)) {
     625           0 :                     ShowSevereError(state,
     626           0 :                                     format("{}=\"{}\" invalid {} is required but input is blank.",
     627             :                                            CurrentModuleObject,
     628           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     629             :                                            cNumericFields(16)));
     630             :                 } else {
     631           0 :                     ShowSevereError(state,
     632           0 :                                     format("{}=\"{}\" invalid {}=[{:.2R}] must be greater than zero.",
     633             :                                            CurrentModuleObject,
     634           0 :                                            state.dataIPShortCut->cAlphaArgs(1),
     635             :                                            cNumericFields(16),
     636             :                                            rNumericArgs(16)));
     637             :                 }
     638           0 :                 ErrorsFound = true;
     639             :             }
     640             : 
     641           3 :             windTurbine.PowerCoeffs[0] = state.dataIPShortCut->rNumericArgs(17); // Empirical power coefficient C1
     642           3 :             if (lNumericBlanks(17)) {
     643           2 :                 windTurbine.PowerCoeffs[0] = 0.0;
     644             :             }
     645           3 :             windTurbine.PowerCoeffs[1] = state.dataIPShortCut->rNumericArgs(18); // Empirical power coefficient C2
     646           3 :             if (lNumericBlanks(18)) {
     647           2 :                 windTurbine.PowerCoeffs[1] = 0.0;
     648             :             }
     649           3 :             windTurbine.PowerCoeffs[2] = state.dataIPShortCut->rNumericArgs(19); // Empirical power coefficient C3
     650           3 :             if (lNumericBlanks(19)) {
     651           2 :                 windTurbine.PowerCoeffs[2] = 0.0;
     652             :             }
     653           3 :             windTurbine.PowerCoeffs[3] = state.dataIPShortCut->rNumericArgs(20); // Empirical power coefficient C4
     654           3 :             if (lNumericBlanks(20)) {
     655           2 :                 windTurbine.PowerCoeffs[3] = 0.0;
     656             :             }
     657           3 :             windTurbine.PowerCoeffs[4] = state.dataIPShortCut->rNumericArgs(21); // Empirical power coefficient C5
     658           3 :             if (lNumericBlanks(21)) {
     659           2 :                 windTurbine.PowerCoeffs[4] = 0.0;
     660             :             }
     661           3 :             windTurbine.PowerCoeffs[5] = state.dataIPShortCut->rNumericArgs(22); // Empirical power coefficient C6
     662           3 :             if (lNumericBlanks(22)) {
     663           2 :                 windTurbine.PowerCoeffs[5] = 0.0;
     664             :             }
     665             :         }
     666             : 
     667           1 :         cAlphaArgs.deallocate();
     668           1 :         cAlphaFields.deallocate();
     669           1 :         cNumericFields.deallocate();
     670           1 :         rNumericArgs.deallocate();
     671           1 :         lAlphaBlanks.deallocate();
     672           1 :         lNumericBlanks.deallocate();
     673             : 
     674           1 :         if (ErrorsFound) ShowFatalError(state, format("{} errors occurred in input.  Program terminates.", CurrentModuleObject));
     675             : 
     676           4 :         for (WindTurbineNum = 1; WindTurbineNum <= NumWindTurbines; ++WindTurbineNum) {
     677           3 :             auto &windTurbine = state.dataWindTurbine->WindTurbineSys(WindTurbineNum);
     678           6 :             SetupOutputVariable(state,
     679             :                                 "Generator Produced AC Electricity Rate",
     680             :                                 Constant::Units::W,
     681           3 :                                 windTurbine.Power,
     682             :                                 OutputProcessor::TimeStepType::System,
     683             :                                 OutputProcessor::StoreType::Average,
     684           3 :                                 windTurbine.Name);
     685           6 :             SetupOutputVariable(state,
     686             :                                 "Generator Produced AC Electricity Energy",
     687             :                                 Constant::Units::J,
     688           3 :                                 windTurbine.Energy,
     689             :                                 OutputProcessor::TimeStepType::System,
     690             :                                 OutputProcessor::StoreType::Sum,
     691           3 :                                 windTurbine.Name,
     692             :                                 Constant::eResource::ElectricityProduced,
     693             :                                 OutputProcessor::Group::Plant,
     694             :                                 OutputProcessor::EndUseCat::WindTurbine);
     695           6 :             SetupOutputVariable(state,
     696             :                                 "Generator Turbine Local Wind Speed",
     697             :                                 Constant::Units::m_s,
     698           3 :                                 windTurbine.LocalWindSpeed,
     699             :                                 OutputProcessor::TimeStepType::System,
     700             :                                 OutputProcessor::StoreType::Average,
     701           3 :                                 windTurbine.Name);
     702           6 :             SetupOutputVariable(state,
     703             :                                 "Generator Turbine Local Air Density",
     704             :                                 Constant::Units::kg_m3,
     705           3 :                                 windTurbine.LocalAirDensity,
     706             :                                 OutputProcessor::TimeStepType::System,
     707             :                                 OutputProcessor::StoreType::Average,
     708           3 :                                 windTurbine.Name);
     709           6 :             SetupOutputVariable(state,
     710             :                                 "Generator Turbine Tip Speed Ratio",
     711             :                                 Constant::Units::None,
     712           3 :                                 windTurbine.TipSpeedRatio,
     713             :                                 OutputProcessor::TimeStepType::System,
     714             :                                 OutputProcessor::StoreType::Average,
     715           3 :                                 windTurbine.Name);
     716           3 :             switch (windTurbine.rotorType) {
     717           2 :             case RotorType::HorizontalAxis: {
     718           4 :                 SetupOutputVariable(state,
     719             :                                     "Generator Turbine Power Coefficient",
     720             :                                     Constant::Units::None,
     721           2 :                                     windTurbine.PowerCoeff,
     722             :                                     OutputProcessor::TimeStepType::System,
     723             :                                     OutputProcessor::StoreType::Average,
     724           2 :                                     windTurbine.Name);
     725           2 :             } break;
     726           1 :             case RotorType::VerticalAxis: {
     727           2 :                 SetupOutputVariable(state,
     728             :                                     "Generator Turbine Chordal Component Velocity",
     729             :                                     Constant::Units::m_s,
     730           1 :                                     windTurbine.ChordalVel,
     731             :                                     OutputProcessor::TimeStepType::System,
     732             :                                     OutputProcessor::StoreType::Average,
     733           1 :                                     windTurbine.Name);
     734           2 :                 SetupOutputVariable(state,
     735             :                                     "Generator Turbine Normal Component Velocity",
     736             :                                     Constant::Units::m_s,
     737           1 :                                     windTurbine.NormalVel,
     738             :                                     OutputProcessor::TimeStepType::System,
     739             :                                     OutputProcessor::StoreType::Average,
     740           1 :                                     windTurbine.Name);
     741           2 :                 SetupOutputVariable(state,
     742             :                                     "Generator Turbine Relative Flow Velocity",
     743             :                                     Constant::Units::m_s,
     744           1 :                                     windTurbine.RelFlowVel,
     745             :                                     OutputProcessor::TimeStepType::System,
     746             :                                     OutputProcessor::StoreType::Average,
     747           1 :                                     windTurbine.Name);
     748           2 :                 SetupOutputVariable(state,
     749             :                                     "Generator Turbine Attack Angle",
     750             :                                     Constant::Units::deg,
     751           1 :                                     windTurbine.AngOfAttack,
     752             :                                     OutputProcessor::TimeStepType::System,
     753             :                                     OutputProcessor::StoreType::Average,
     754           1 :                                     windTurbine.Name);
     755           1 :             } break;
     756           0 :             default:
     757           0 :                 break;
     758             :             }
     759             :         }
     760           1 :     }
     761             : 
     762       16236 :     void InitWindTurbine(EnergyPlusData &state, int const WindTurbineNum)
     763             :     {
     764             : 
     765             :         // SUBROUTINE INFORMATION:
     766             :         //       AUTHOR         Daeho Kang
     767             :         //       DATE WRITTEN   Oct 2009
     768             :         //       MODIFIED       Linda K. Lawrie, December 2009 for reading stat file
     769             :         //       RE-ENGINEERED  na
     770             : 
     771             :         // PURPOSE OF THIS SUBROUTINE:
     772             :         // This subroutine reads monthly average wind speed from stat file and then
     773             :         // determines annual average wind speed. Differences between this TMY wind speed
     774             :         // and local wind speed that the user inputs are then factored.
     775             :         // IF the user has no local wind data and does not enter the local wind speed to be factored,
     776             :         // then the factor of 1 is assigned, so that wind speed estimated
     777             :         // at the particular rotor height is used with no factorization.
     778             :         // It also initializes module variables at each time step.
     779             : 
     780             :         static char const TabChr('\t'); // Tab character
     781             : 
     782             :         int mon;           // loop counter
     783             :         bool wsStatFound;  // logical noting that wind stats were found
     784             :         bool warningShown; // true if the <365 warning has already been shown
     785       16236 :         Array1D<Real64> MonthWS(12);
     786             :         Real64 LocalTMYWS; // Annual average wind speed at the rotor height
     787             : 
     788             :         // Estimate average annual wind speed once
     789       16236 :         if (state.dataWindTurbine->MyOneTimeFlag) {
     790           1 :             wsStatFound = false;
     791           1 :             Real64 AnnualTMYWS = 0.0;
     792           1 :             if (FileSystem::fileExists(state.files.inStatFilePath.filePath)) {
     793           2 :                 auto statFile = state.files.inStatFilePath.open(state, "InitWindTurbine");
     794         255 :                 while (statFile.good()) { // end of file
     795         255 :                     auto lineIn = statFile.readLine();
     796             :                     // reconcile line with different versions of stat file
     797         255 :                     size_t lnPtr = index(lineIn.data, "Wind Speed");
     798         255 :                     if (lnPtr == std::string::npos) continue;
     799             :                     // have hit correct section.
     800           8 :                     while (statFile.good()) { // find daily avg line
     801           8 :                         lineIn = statFile.readLine();
     802           8 :                         lnPtr = index(lineIn.data, "Daily Avg");
     803           8 :                         if (lnPtr == std::string::npos) continue;
     804             :                         // tab delimited file
     805           1 :                         lineIn.data.erase(0, lnPtr + 10);
     806           1 :                         MonthWS = 0.0;
     807           1 :                         wsStatFound = true;
     808           1 :                         warningShown = false;
     809          13 :                         for (mon = 1; mon <= 12; ++mon) {
     810          12 :                             lnPtr = index(lineIn.data, TabChr);
     811          12 :                             if (lnPtr != 1) {
     812          12 :                                 if ((lnPtr == std::string::npos) || (!stripped(lineIn.data.substr(0, lnPtr)).empty())) {
     813          12 :                                     if (lnPtr != std::string::npos) {
     814          12 :                                         bool error = false;
     815          12 :                                         MonthWS(mon) = Util::ProcessNumber(lineIn.data.substr(0, lnPtr), error);
     816             : 
     817          12 :                                         if (error) {
     818             :                                             // probably should throw some error here
     819             :                                         }
     820             : 
     821          12 :                                         lineIn.data.erase(0, lnPtr + 1);
     822             :                                     }
     823             :                                 } else { // blank field
     824           0 :                                     if (!warningShown) {
     825           0 :                                         ShowWarningError(state,
     826           0 :                                                          format("InitWindTurbine: read from {} file shows <365 days in weather file. Annual average "
     827             :                                                                 "wind speed used will be inaccurate.",
     828           0 :                                                                 state.files.inStatFilePath.filePath));
     829           0 :                                         lineIn.data.erase(0, lnPtr + 1);
     830           0 :                                         warningShown = true;
     831             :                                     }
     832             :                                 }
     833             :                             } else { // two tabs in succession
     834           0 :                                 if (!warningShown) {
     835           0 :                                     ShowWarningError(state,
     836           0 :                                                      format("InitWindTurbine: read from {} file shows <365 days in weather file. Annual average wind "
     837             :                                                             "speed used will be inaccurate.",
     838           0 :                                                             state.files.inStatFilePath.filePath));
     839           0 :                                     lineIn.data.erase(0, lnPtr + 1);
     840           0 :                                     warningShown = true;
     841             :                                 }
     842             :                             }
     843             :                         }
     844           1 :                         break;
     845             :                     }
     846           1 :                     if (wsStatFound) break;
     847         255 :                 }
     848           1 :                 if (wsStatFound) {
     849           1 :                     AnnualTMYWS = sum(MonthWS) / 12.0;
     850             :                 } else {
     851           0 :                     ShowWarningError(
     852             :                         state, "InitWindTurbine: stat file did not include Wind Speed statistics. TMY Wind Speed adjusted at the height is used.");
     853             :                 }
     854           1 :             } else { // No stat file
     855           0 :                 ShowWarningError(state, "InitWindTurbine: stat file missing. TMY Wind Speed adjusted at the height is used.");
     856             :             }
     857             : 
     858             :             // assign this value to all the wind turbines once here
     859           4 :             for (auto &wt : state.dataWindTurbine->WindTurbineSys) {
     860           3 :                 wt.AnnualTMYWS = AnnualTMYWS;
     861           1 :             }
     862             : 
     863           1 :             state.dataWindTurbine->MyOneTimeFlag = false;
     864             :         }
     865             : 
     866       16236 :         auto &windTurbine = state.dataWindTurbine->WindTurbineSys(WindTurbineNum);
     867             : 
     868             :         // Factor differences between TMY wind data and local wind data once
     869       16236 :         if (windTurbine.AnnualTMYWS > 0.0 && windTurbine.WSFactor == 0.0 && windTurbine.LocalAnnualAvgWS > 0) {
     870             :             // Convert the annual wind speed to the local wind speed at the height of the local station, then factor
     871           3 :             LocalTMYWS = windTurbine.AnnualTMYWS * state.dataEnvrn->WeatherFileWindModCoeff *
     872           3 :                          std::pow(windTurbine.HeightForLocalWS / state.dataEnvrn->SiteWindBLHeight, state.dataEnvrn->SiteWindExp);
     873           3 :             windTurbine.WSFactor = LocalTMYWS / windTurbine.LocalAnnualAvgWS;
     874             :         }
     875             :         // Assign factor of 1.0 if no stat file or no input of local average wind speed
     876       16236 :         if (windTurbine.WSFactor == 0.0) windTurbine.WSFactor = 1.0;
     877             : 
     878             :         // Do every time step initialization
     879       16236 :         windTurbine.Power = 0.0;
     880       16236 :         windTurbine.TotPower = 0.0;
     881       16236 :         windTurbine.PowerCoeff = 0.0;
     882       16236 :         windTurbine.TipSpeedRatio = 0.0;
     883       16236 :         windTurbine.ChordalVel = 0.0;
     884       16236 :         windTurbine.NormalVel = 0.0;
     885       16236 :         windTurbine.RelFlowVel = 0.0;
     886       16236 :         windTurbine.AngOfAttack = 0.0;
     887       16236 :         windTurbine.TanForce = 0.0;
     888       16236 :         windTurbine.NorForce = 0.0;
     889       16236 :         windTurbine.TotTorque = 0.0;
     890       16236 :     }
     891             : 
     892       16236 :     void CalcWindTurbine(EnergyPlusData &state,
     893             :                          int const WindTurbineNum,           // System is on
     894             :                          [[maybe_unused]] bool const RunFlag // System is on
     895             :     )
     896             :     {
     897             : 
     898             :         // SUBROUTINE INFORMATION:
     899             :         //       AUTHOR         Daeho Kang
     900             :         //       DATE WRITTEN   Octorber 2009
     901             :         //       MODIFIED       na
     902             :         //       RE-ENGINEERED  na
     903             : 
     904             :         // REFERENCES:
     905             :         // Sathyajith Mathew. 2006. Wind Energy: Fundamental, Resource Analysis and Economics. Springer,
     906             :         //     Chap. 2, pp. 11-15
     907             :         // Mazharul Islam, David S.K. Ting, and Amir Fartaj. 2008. Aerodynamic Models for Darrieus-type sSraight-bladed
     908             :         //     Vertical Axis Wind Turbines. Renewable & Sustainable Energy Reviews, Volume 12, pp.1087-1109
     909             : 
     910             :         using DataEnvironment::OutBaroPressAt;
     911             :         using DataEnvironment::OutDryBulbTempAt;
     912             :         using DataEnvironment::OutWetBulbTempAt;
     913             :         using Psychrometrics::PsyRhoAirFnPbTdbW;
     914             :         using Psychrometrics::PsyWFnTdbTwbPb;
     915             :         using ScheduleManager::GetCurrentScheduleValue;
     916             : 
     917       16236 :         Real64 constexpr MaxTheta(90.0);   // Maximum of theta
     918       16236 :         Real64 constexpr MaxDegree(360.0); // Maximum limit of outdoor air wind speed in m/s
     919       16236 :         Real64 constexpr SecInMin(60.0);
     920             : 
     921             :         Real64 LocalWindSpeed;   // Ambient wind speed at the specific height in m/s
     922             :         Real64 RotorH;           // Height of the rotor in m
     923             :         Real64 RotorD;           // Diameter of the rotor in m
     924             :         Real64 LocalHumRat;      // Local humidity ratio of the air at the specific height
     925             :         Real64 LocalAirDensity;  // Local density at the specific height in m
     926             :         Real64 PowerCoeff;       // Power coefficient
     927             :         Real64 SweptArea;        // Swept area of the rotor in m2
     928       16236 :         Real64 WTPower(0.0);     // Total Power generated by the turbine in the quasi-steady state in Watts
     929             :         Real64 Power;            // Actual power of the turbine in Watts
     930             :         Real64 TipSpeedRatio;    // Tip speed ratio (TSR)
     931             :         Real64 TipSpeedRatioAtI; // Tip speed ratio at the ith time step
     932             :         Real64 AzimuthAng;       // Azimuth angle of blades in degree
     933             :         Real64 ChordalVel;       // Chordal velocity component in m/s
     934             :         Real64 NormalVel;        // Normal velocity component in m/s
     935             :         Real64 AngOfAttack;      // Angle of attack of a single blade in degree
     936             :         Real64 RelFlowVel;       // Relative flow velocity component in m/s
     937             :         Real64 TanForce;         // Tangential force in N.m
     938             :         Real64 NorForce;         // Normal force in N.m
     939             :         Real64 RotorVel;         // Rotor velocity in m/s
     940             :         Real64 AvgTanForce;      // Average tangential force in N.m
     941             :         Real64 Constant;         // Constants within integrand of tangential force
     942             :         Real64 IntRelFlowVel;    // Integration of relative flow velocity
     943             :         Real64 TotTorque;        // Total torque for the number of blades
     944             :         Real64 Omega;            // Angular velocity of rotor in rad/s
     945             :         Real64 TanForceCoeff;    // Tnagential force coefficient
     946             :         Real64 NorForceCoeff;    // Normal force coefficient
     947             :         Real64 Period;           // Period of sine and cosine functions
     948             :         Real64 C1;               // Empirical power coefficient C1
     949             :         Real64 C2;               // Empirical power coefficient C2
     950             :         Real64 C3;               // Empirical power coefficient C3
     951             :         Real64 C4;               // Empirical power coefficient C4
     952             :         Real64 C5;               // Empirical power coefficient C5
     953             :         Real64 C6;               // Empirical power coefficient C6
     954             :         Real64 LocalTemp;        // Ambient air temperature at the height in degree C
     955             :         Real64 LocalPress;       // Local atmospheric pressure at the particular height in Pa
     956             :         Real64 InducedVel;       // Induced velocity on the rotor in m/s
     957             :         // unused REAL(r64) :: SysEfficiency     ! Overall wind turbine system efficiency including generator and inverter
     958             :         Real64 MaxPowerCoeff; // Maximum power coefficient
     959             :         Real64 RotorSpeed;    // Speed of rotors
     960             : 
     961       16236 :         auto &windTurbine = state.dataWindTurbine->WindTurbineSys(WindTurbineNum);
     962             :         // Estimate local velocity and density
     963       16236 :         RotorH = windTurbine.RotorHeight;
     964       16236 :         RotorD = windTurbine.RotorDiameter;
     965       16236 :         RotorSpeed = windTurbine.RatedRotorSpeed;
     966       16236 :         LocalTemp = OutDryBulbTempAt(state, RotorH);
     967       16236 :         LocalPress = OutBaroPressAt(state, RotorH);
     968       16236 :         LocalHumRat = PsyWFnTdbTwbPb(state, LocalTemp, OutWetBulbTempAt(state, RotorH), LocalPress);
     969       16236 :         LocalAirDensity = PsyRhoAirFnPbTdbW(state, LocalPress, LocalTemp, LocalHumRat);
     970       16236 :         LocalWindSpeed = DataEnvironment::WindSpeedAt(state, RotorH);
     971       16236 :         LocalWindSpeed /= windTurbine.WSFactor;
     972             : 
     973             :         // Check wind conditions for system operation
     974       32445 :         if (GetCurrentScheduleValue(state, windTurbine.SchedPtr) > 0 && LocalWindSpeed > windTurbine.CutInSpeed &&
     975       16209 :             LocalWindSpeed < windTurbine.CutOutSpeed) {
     976             : 
     977             :             // System is on
     978       16209 :             Period = 2.0 * Constant::Pi;
     979       16209 :             Omega = (RotorSpeed * Period) / SecInMin;
     980       16209 :             SweptArea = (Constant::Pi * pow_2(RotorD)) / 4;
     981       16209 :             TipSpeedRatio = (Omega * (RotorD / 2.0)) / LocalWindSpeed;
     982             : 
     983             :             // Limit maximum tip speed ratio
     984       16209 :             if (TipSpeedRatio > windTurbine.MaxTipSpeedRatio) {
     985       10815 :                 TipSpeedRatio = windTurbine.MaxTipSpeedRatio;
     986             :             }
     987             : 
     988       16209 :             switch (windTurbine.rotorType) {
     989       10806 :             case RotorType::HorizontalAxis: { // Horizontal axis wind turbine
     990       10806 :                 MaxPowerCoeff = windTurbine.MaxPowerCoeff;
     991             :                 // Check if empirical constants are available
     992       10806 :                 C1 = windTurbine.PowerCoeffs[0];
     993       10806 :                 C2 = windTurbine.PowerCoeffs[1];
     994       10806 :                 C3 = windTurbine.PowerCoeffs[2];
     995       10806 :                 C4 = windTurbine.PowerCoeffs[3];
     996       10806 :                 C5 = windTurbine.PowerCoeffs[4];
     997       10806 :                 C6 = windTurbine.PowerCoeffs[5];
     998             : 
     999       10806 :                 Real64 const LocalWindSpeed_3(pow_3(LocalWindSpeed));
    1000       10806 :                 if (C1 > 0.0 && C2 > 0.0 && C3 > 0.0 && C4 >= 0.0 && C5 > 0.0 && C6 > 0.0) {
    1001             :                     // Analytical approximation
    1002             :                     // Maximum power, i.e., rotor speed is at maximum, and pitch angle is zero
    1003             :                     // TipSpeedRatioAtI = 1.0 / ( ( 1.0 / ( TipSpeedRatio + 0.08 * PitchAngle ) ) - ( 0.035 / ( pow_3( PitchAngle ) + 1.0 ) ) );
    1004             :                     // //Tuned PitchAngle is zero
    1005        5403 :                     TipSpeedRatioAtI = TipSpeedRatio / (1.0 - (TipSpeedRatio * 0.035));
    1006             :                     // PowerCoeff = C1 * ( ( C2 / TipSpeedRatioAtI ) - ( C3 * PitchAngle ) - ( C4 * std::pow( PitchAngle, 1.5 ) ) - C5 ) * (
    1007             :                     // std::exp( -( C6 / TipSpeedRatioAtI ) ) ); //Tuned PitchAngle is zero
    1008        5403 :                     PowerCoeff = C1 * ((C2 / TipSpeedRatioAtI) - C5) * std::exp(-(C6 / TipSpeedRatioAtI));
    1009        5403 :                     if (PowerCoeff > MaxPowerCoeff) {
    1010           0 :                         PowerCoeff = MaxPowerCoeff;
    1011             :                     }
    1012        5403 :                     WTPower = 0.5 * LocalAirDensity * PowerCoeff * SweptArea * LocalWindSpeed_3;
    1013             :                 } else { // Simple approximation
    1014        5403 :                     WTPower = 0.5 * LocalAirDensity * SweptArea * LocalWindSpeed_3 * MaxPowerCoeff;
    1015        5403 :                     PowerCoeff = MaxPowerCoeff;
    1016             :                 }
    1017             :                 // Maximum of rated power
    1018       10806 :                 if (LocalWindSpeed >= windTurbine.RatedWindSpeed || WTPower > windTurbine.RatedPower) {
    1019           0 :                     WTPower = windTurbine.RatedPower;
    1020           0 :                     PowerCoeff = WTPower / (0.5 * LocalAirDensity * SweptArea * LocalWindSpeed_3);
    1021             :                 }
    1022             :                 // Recalculated Cp at the rated power
    1023       10806 :                 windTurbine.PowerCoeff = PowerCoeff;
    1024       10806 :             } break;
    1025        5403 :             case RotorType::VerticalAxis: { // Vertical axis wind turbine
    1026        5403 :                 RotorVel = Omega * (RotorD / 2.0);
    1027             :                 // Recalculated omega, if TSR is greater than the maximum
    1028        5403 :                 if (TipSpeedRatio >= windTurbine.MaxTipSpeedRatio) {
    1029        5403 :                     RotorVel = LocalWindSpeed * windTurbine.MaxTipSpeedRatio;
    1030        5403 :                     Omega = RotorVel / (RotorD / 2.0);
    1031             :                 }
    1032             : 
    1033        5403 :                 AzimuthAng = MaxDegree / windTurbine.NumOfBlade;
    1034             :                 // Azimuth angle between zero and 90 degree
    1035        5403 :                 if (AzimuthAng > MaxTheta) { // Number of blades is 2 or 3
    1036        5403 :                     AzimuthAng -= MaxTheta;
    1037        5403 :                     if (AzimuthAng == MaxTheta) { // 2 blades
    1038           0 :                         AzimuthAng = 0.0;
    1039             :                     }
    1040           0 :                 } else if (AzimuthAng == MaxTheta) { // 4 blades
    1041           0 :                     AzimuthAng = 0.0;
    1042             :                 }
    1043             : 
    1044        5403 :                 InducedVel = LocalWindSpeed * 2.0 / 3.0;
    1045             :                 // Velocity components
    1046        5403 :                 Real64 const sin_AzimuthAng(std::sin(AzimuthAng * Constant::DegToRadians));
    1047        5403 :                 Real64 const cos_AzimuthAng(std::cos(AzimuthAng * Constant::DegToRadians));
    1048        5403 :                 ChordalVel = RotorVel + InducedVel * cos_AzimuthAng;
    1049        5403 :                 NormalVel = InducedVel * sin_AzimuthAng;
    1050        5403 :                 RelFlowVel = std::sqrt(pow_2(ChordalVel) + pow_2(NormalVel));
    1051             : 
    1052             :                 // Angle of attack
    1053        5403 :                 AngOfAttack = std::atan((sin_AzimuthAng / ((RotorVel / LocalWindSpeed) / (InducedVel / LocalWindSpeed) + cos_AzimuthAng)));
    1054             : 
    1055             :                 // Force coefficients
    1056        5403 :                 Real64 const sin_AngOfAttack(std::sin(AngOfAttack * Constant::DegToRadians));
    1057        5403 :                 Real64 const cos_AngOfAttack(std::cos(AngOfAttack * Constant::DegToRadians));
    1058        5403 :                 TanForceCoeff = std::abs(windTurbine.LiftCoeff * sin_AngOfAttack - windTurbine.DragCoeff * cos_AngOfAttack);
    1059        5403 :                 NorForceCoeff = windTurbine.LiftCoeff * cos_AngOfAttack + windTurbine.DragCoeff * sin_AngOfAttack;
    1060             : 
    1061             :                 // Net tangential and normal forces
    1062        5403 :                 Real64 const RelFlowVel_2(pow_2(RelFlowVel));
    1063        5403 :                 Real64 const density_fac(0.5 * LocalAirDensity * windTurbine.ChordArea * RelFlowVel_2);
    1064        5403 :                 TanForce = TanForceCoeff * density_fac;
    1065        5403 :                 NorForce = NorForceCoeff * density_fac;
    1066        5403 :                 Constant = (1.0 / Period) * (TanForce / RelFlowVel_2);
    1067             : 
    1068             :                 // Relative flow velocity is the only function of theta in net tangential force
    1069             :                 // Integral of cos(theta) on zero to 2pi goes to zero
    1070             :                 // Integrate constants only
    1071        5403 :                 IntRelFlowVel = pow_2(RotorVel) * Period + pow_2(InducedVel) * Period;
    1072             : 
    1073             :                 // Average tangential force on a single blade
    1074        5403 :                 AvgTanForce = Constant * IntRelFlowVel;
    1075        5403 :                 TotTorque = windTurbine.NumOfBlade * AvgTanForce * (RotorD / 2.0);
    1076        5403 :                 WTPower = TotTorque * Omega;
    1077             : 
    1078             :                 // Check if power produced is greater than maximum or rated power
    1079        5403 :                 if (WTPower > windTurbine.RatedPower) {
    1080        5403 :                     WTPower = windTurbine.RatedPower;
    1081             :                 }
    1082             : 
    1083        5403 :                 windTurbine.ChordalVel = ChordalVel;
    1084        5403 :                 windTurbine.NormalVel = NormalVel;
    1085        5403 :                 windTurbine.RelFlowVel = RelFlowVel;
    1086        5403 :                 windTurbine.TanForce = TanForce;
    1087        5403 :                 windTurbine.NorForce = NorForce;
    1088        5403 :                 windTurbine.TotTorque = TotTorque;
    1089        5403 :             } break;
    1090           0 :             default: {
    1091           0 :                 assert(false);
    1092             :             } break;
    1093             :             }
    1094             : 
    1095       16209 :             if (WTPower > windTurbine.RatedPower) {
    1096           0 :                 WTPower = windTurbine.RatedPower;
    1097             :             }
    1098             : 
    1099             :             // Actual power generated by the wind turbine system
    1100       16209 :             Power = WTPower * windTurbine.SysEfficiency;
    1101             : 
    1102       16209 :             windTurbine.Power = Power;
    1103       16209 :             windTurbine.TotPower = WTPower;
    1104       16209 :             windTurbine.LocalWindSpeed = LocalWindSpeed;
    1105       16209 :             windTurbine.LocalAirDensity = LocalAirDensity;
    1106       16209 :             windTurbine.TipSpeedRatio = TipSpeedRatio;
    1107             : 
    1108             :         } else { // System is off
    1109          27 :             windTurbine.Power = 0.0;
    1110          27 :             windTurbine.TotPower = 0.0;
    1111          27 :             windTurbine.PowerCoeff = 0.0;
    1112          27 :             windTurbine.LocalWindSpeed = LocalWindSpeed;
    1113          27 :             windTurbine.LocalAirDensity = LocalAirDensity;
    1114          27 :             windTurbine.TipSpeedRatio = 0.0;
    1115          27 :             windTurbine.ChordalVel = 0.0;
    1116          27 :             windTurbine.NormalVel = 0.0;
    1117          27 :             windTurbine.RelFlowVel = 0.0;
    1118          27 :             windTurbine.AngOfAttack = 0.0;
    1119          27 :             windTurbine.TanForce = 0.0;
    1120          27 :             windTurbine.NorForce = 0.0;
    1121          27 :             windTurbine.TotTorque = 0.0;
    1122             :         }
    1123       16236 :     }
    1124             : 
    1125       16236 :     void ReportWindTurbine(EnergyPlusData &state, int const WindTurbineNum)
    1126             :     {
    1127             :         // SUBROUTINE INFORMATION:
    1128             :         //       AUTHOR         Daeho Kang
    1129             :         //       DATE WRITTEN   October 2009
    1130             :         //       MODIFIED       na
    1131             :         //       RE-ENGINEERED  na
    1132             : 
    1133             :         // PURPOSE OF THIS SUBROUTINE:
    1134             :         // This subroutine fills remaining report variables.
    1135             : 
    1136       16236 :         Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    1137       16236 :         auto &windTurbine = state.dataWindTurbine->WindTurbineSys(WindTurbineNum);
    1138             : 
    1139       16236 :         windTurbine.Energy = windTurbine.Power * TimeStepSysSec;
    1140       16236 :     }
    1141             : 
    1142             :     //*****************************************************************************************
    1143             : 
    1144             : } // namespace WindTurbine
    1145             : 
    1146             : } // namespace EnergyPlus

Generated by: LCOV version 1.14