Exemple #1
0
        // Calculate manages calculations that need to be run for each time step
        public void Calculate
        (
            double PanelTilt                        // The angle between the surface tilt of the module and the ground [radians]
            , double Clearance                      // Array ground clearance [m]
            , double HDif                           // Diffuse horizontal irradiance [W/m2]
            , double TDifRef                        // Front reflected diffuse irradiance [W/m2]
            , double HGlo                           // Horizontal global irradiance [W/m2]
            , double[] frontGroundGHI               // Global irradiance for each of the ground segments to front of the row [W/m2]
            , double[] rearGroundGHI                // Global irradiance for each of the ground segments to rear of the row [W/m2]
            , double aveGroundGHI                   // Average global irradiance on ground segment to the rear of row [W/m2]
            , int month                             // Current month, used for getting albedo value [#]
            , double backSH                         // Fraction of the back surface of the PV array that is unshaded [#]
            , double TDir                           // Back tilted beam irradiance [W/m2]
            , DateTime ts                           // Time stamp analyzed, used for printing .csv files
        )
        {
            // For tracking systems, panel tilt and ground clearance will change at each time step
            itsPanelTilt = PanelTilt;
            itsClearance = Clearance / itsArrayBW;           // Convert to panel slope lengths

            int numGroundSegs = Util.NUM_GROUND_SEGS;

            double h = Math.Sin(itsPanelTilt);               // Vertical height of sloped PV panel [panel slope lengths]
            double b = Math.Cos(itsPanelTilt);               // Horizontal distance from front of panel to back of panel [panel slope lengths]

            // Calculate x, y coordinates of bottom and top edges of PV row behind the current PV row so that portions of sky and ground viewed by
            // the PV cell may be determined. Coordinates are relative to (0,0) being the ground point below the lower front edge of current PV row.
            // The row behind the current row is in the positive x direction.
            double bottomX = itsPitch;                       // x value for point on bottom edge of PV panel behind current row
            double bottomY = itsClearance;                   // y value for point on bottom edge of PV panel behind current row
            double topX    = bottomX + b;                    // x value for point on top edge of PV panel behind current row
            double topY    = bottomY + h;                    // y value for point on top edge of PV panel behind current row

            // Get albedo value for the month
            Albedo = itsMonthlyAlbedo[month];

            // Accumulate diffuse, reflected, and beam irradiance components for each cell row over its field of view of PI radians
            for (int i = 0; i < numCellRows; i++)
            {
                double cellX = b * (i + 0.5) / numCellRows;                                     // x value for location of cell
                double cellY = itsClearance + h * (i + 0.5) / numCellRows;                      // y value for location of cell

                double elevUp   = 0.0;                                                          // Elevation angle from PV cell to top of PV panel
                double elevDown = 0.0;                                                          // Elevation angle from PV cell to bottom of PV panel
                if (itsRowType == RowType.INTERIOR)
                {
                    elevUp   = Math.Atan((topY - cellY) / (topX - cellX));
                    elevDown = Math.Atan((cellY - bottomY) / (bottomX - cellX));
                }

                int stopSky     = Convert.ToInt32((itsPanelTilt - elevUp) * Util.RTOD);         // Last whole degree in arc range that sees sky; first is 0 [degrees]
                int startGround = Convert.ToInt32((itsPanelTilt + elevDown) * Util.RTOD);       // First whole degree in arc range that sees ground; last is 180 [degrees]

                // Compute sky diffuse component
                backDif[i] = RadiationProc.GetViewFactor(0, stopSky * Util.DTOR) * HDif;

                // Compute front surface reflected component
                if (itsRowType == RowType.INTERIOR)
                {
                    backFroRef[i] = RadiationProc.GetViewFactor(stopSky * Util.DTOR, startGround * Util.DTOR) * TDifRef;
                }

                backGroRef[i] = 0;
                // Add ground reflected component
                for (int j = startGround; j < 180; j++)
                {
                    // Get start and ending elevations for this (j, j + 1) pair
                    double startElevDown = elevDown + (j - startGround) * Util.DTOR;
                    double stopElevDown  = elevDown + (j + 1 - startGround) * Util.DTOR;

                    // Projection onto ground in positive x direction
                    double projX2 = cellX + cellY / Math.Tan(startElevDown);
                    double projX1 = cellX + cellY / Math.Tan(stopElevDown);

                    // Initialize and get actualGroundGHI value
                    double actualGroundGHI = 0;
                    if (Math.Abs(projX1 - projX2) > 0.99 * itsPitch)
                    {
                        if (itsRowType == RowType.SINGLE)
                        {
                            // Use measured GHI if projection approximates or exceeds the pitch
                            actualGroundGHI = HGlo;
                        }
                        else
                        {
                            // Use average GHI if projection approximates or exceeds the pitch
                            actualGroundGHI = aveGroundGHI;
                        }
                    }
                    else
                    {
                        // Normalize projections and multiply by n
                        projX1 = numGroundSegs * projX1 / itsPitch;
                        projX2 = numGroundSegs * projX2 / itsPitch;

                        if (itsRowType == RowType.SINGLE && ((Math.Abs(projX1) > numGroundSegs - 1) || (Math.Abs(projX2) > numGroundSegs - 1)))
                        {
                            // Use measured GHI if projection exceeds the pitch
                            actualGroundGHI = HGlo;
                        }
                        else
                        {
                            while (projX1 < -numGroundSegs || projX2 < -numGroundSegs)
                            {
                                projX1 += numGroundSegs;
                                projX2 += numGroundSegs;
                            }
                            while (projX1 >= numGroundSegs || projX2 >= numGroundSegs)
                            {
                                projX1 -= numGroundSegs;
                                projX2 -= numGroundSegs;
                            }

                            // Determine indices (truncate values) for use with groundGHI arrays
                            int index1 = Convert.ToInt32(Math.Floor(projX1 + numGroundSegs) - numGroundSegs);
                            int index2 = Convert.ToInt32(Math.Floor(projX2 + numGroundSegs) - numGroundSegs);

                            if (index1 == index2)
                            {
                                // Use single value if projection falls within a single segment of ground
                                if (index1 < 0)
                                {
                                    actualGroundGHI = frontGroundGHI[index1 + numGroundSegs];
                                }
                                else
                                {
                                    actualGroundGHI = rearGroundGHI[index1];
                                }
                            }
                            else
                            {
                                // Sum the irradiances on the ground if the projection falls across multiple segments
                                for (int k = index1; k <= index2; k++)
                                {
                                    if (k == index1)
                                    {
                                        if (k < 0)
                                        {
                                            actualGroundGHI += frontGroundGHI[k + numGroundSegs] * (k + 1.0 - projX1);
                                        }
                                        else
                                        {
                                            actualGroundGHI += rearGroundGHI[k] * (k + 1.0 - projX1);
                                        }
                                    }
                                    else if (k == index2)
                                    {
                                        if (k < 0)
                                        {
                                            actualGroundGHI += frontGroundGHI[k + numGroundSegs] * (projX2 - k);
                                        }
                                        else
                                        {
                                            actualGroundGHI += rearGroundGHI[k] * (projX2 - k);
                                        }
                                    }
                                    else
                                    {
                                        if (k < 0)
                                        {
                                            actualGroundGHI += frontGroundGHI[k + numGroundSegs];
                                        }
                                        else
                                        {
                                            actualGroundGHI += rearGroundGHI[k];
                                        }
                                    }
                                }
                                // Get irradiance on ground in the 1 degree field of view
                                actualGroundGHI /= projX2 - projX1;
                            }
                        }
                    }
                    backGroRef[i] += RadiationProc.GetViewFactor(j * Util.DTOR, (j + 1) * Util.DTOR) * actualGroundGHI * Albedo;
                }

                double cellShade = 0.0;
                if (itsRowType == RowType.INTERIOR)
                {
                    // Cell is fully shaded if >= 1, fully unshaded if <= 0, otherwise fractionally shaded
                    cellShade = (1.0 - backSH) * numCellRows - i;
                    cellShade = Math.Min(cellShade, 1.0);
                    cellShade = Math.Max(cellShade, 0.0);
                }

                // Compute beam component, corrected for back shading
                backDir[i] = TDir * (1.0 - cellShade);

                // Correct each component for AOI and structure shading losses
                backDif[i]    = backDif[i] * IAMDif * (1.0 - structLossFactor);
                backFroRef[i] = backFroRef[i] * IAMRef * (1.0 - structLossFactor);
                backGroRef[i] = backGroRef[i] * IAMRef * (1.0 - structLossFactor);
                backDir[i]    = backDir[i] * IAMDir * (1.0 - structLossFactor);

                // Sum all components to get global back irradiance
                backGlo[i] = backDif[i] + backFroRef[i] + backGroRef[i] + backDir[i];
            }

            BDif    = 0;
            BFroRef = 0;
            BGroRef = 0;
            BDir    = 0;

            double maxGlo = backGlo[0];
            double minGlo = backGlo[0];

            for (int i = 0; i < numCellRows; i++)
            {
                // Calculate mean irradiance components
                BDif    += backDif[i] / numCellRows;
                BFroRef += backFroRef[i] / numCellRows;
                BGroRef += backGroRef[i] / numCellRows;
                BDir    += backDir[i] / numCellRows;

                // Find the max and min global irradiance values
                maxGlo = Math.Max(maxGlo, backGlo[i]);
                minGlo = Math.Min(minGlo, backGlo[i]);
            }
            BGlo = BDif + BFroRef + BGroRef + BDir;

            // Calculate the homogeneity of values as the range normalized by the sum
            IrrInhomogeneity = (BGlo > 0) ? (maxGlo - minGlo) / BGlo : 0;

            // Option to print details of the model in .csv files. Only recommended for single day simulations.
            // PrintModel(ts);
        }
Exemple #2
0
        double farmACMinVoltageLoss = 0;                        // Loss of power when voltage of the array is too small and forces the inverters to 'shut off' and when inverter is not operating at MPP [W]

        // Calculate method
        public void Calculate(
            RadiationProc RadProc,                              // Radiation related data
            SimMeteo SimMet                                     // Meteological data from inputfile
            )
        {
            // Reset Losses
            for (int i = 0; i < SimPVA.Length; i++)
            {
                SimInv[i].LossPMinThreshold = 0;
                SimInv[i].LossClipping      = 0;
                SimInv[i].LossLowVoltage    = 0;
                SimInv[i].LossHighVoltage   = 0;
            }

            // Calculating solar panel shading
            SimShading.Calculate(RadProc.SimSun.Zenith, RadProc.SimSun.Azimuth, RadProc.SimHorizonShading.TDir, RadProc.SimHorizonShading.TDif, RadProc.SimHorizonShading.TRef, RadProc.SimTracker.SurfSlope, RadProc.SimTracker.SurfAzimuth);

            // Calculating spectral model effects
            SimSpectral.Calculate(SimMet.HGlo, RadProc.SimSun.NExtra, RadProc.SimSun.Zenith);

            try
            {
                // Calculate PV Array Output for inputs read in this loop
                for (int j = 0; j < ReadFarmSettings.SubArrayCount; j++)
                {
                    // Adjust the IV Curve based on based on Temperature and Irradiance
                    SimPVA[j].CalcIVCurveParameters(SimMet.TGlo, SimShading.ShadTDir, SimShading.ShadTDif, SimShading.ShadTRef, RadProc.SimTilter.IncidenceAngle, SimMet.TAmbient, SimMet.WindSpeed, SimMet.TModMeasured, SimMet.MonthOfYear, SimSpectral.clearnessCorrection);

                    // Check Inverter status to determine if the Inverter is ON or OFF
                    GetInverterStatus(j);

                    // If inverter is off set appropriate variables to 0 and recalculate array in open circuit voltage
                    if (!SimInv[j].isON)
                    {
                        SimInv[j].ACPwrOut = 0;
                        SimInv[j].IOut     = 0;
                        SimPVA[j].CalcAtOpenCircuit();
                        SimPVA[j].Calculate(false, SimPVA[j].Voc);
                    }

                    //performing AC wiring calculations
                    SimACWiring[j].Calculate(SimInv[j]);

                    // Assigning the outputs to the dictionary
                    ReadFarmSettings.Outputlist["SubArray_Current" + (j + 1).ToString()]     = SimPVA[j].IOut;
                    ReadFarmSettings.Outputlist["SubArray_Voltage" + (j + 1).ToString()]     = SimPVA[j].VOut;
                    ReadFarmSettings.Outputlist["SubArray_Power" + (j + 1).ToString()]       = SimPVA[j].POut / 1000;
                    ReadFarmSettings.Outputlist["SubArray_Current_Inv" + (j + 1).ToString()] = SimInv[j].IOut;
                    ReadFarmSettings.Outputlist["SubArray_Voltage_Inv" + (j + 1).ToString()] = SimInv[j].itsOutputVoltage;
                    ReadFarmSettings.Outputlist["SubArray_Power_Inv" + (j + 1).ToString()]   = SimInv[j].ACPwrOut / 1000;
                }

                //Calculating total farm output and total ohmic loss
                farmACOutput    = 0;
                farmACOhmicLoss = 0;
                for (int i = 0; i < SimInv.Length; i++)
                {
                    farmACOutput    += SimInv[i].ACPwrOut;
                    farmACOhmicLoss += SimACWiring[i].ACWiringLoss;
                }

                SimTransformer.Calculate(farmACOutput - farmACOhmicLoss);

                // Calculating outputs that will be assigned for this interval
                // Shading each component of the Tilted radiaton
                // Using horizon affected tilted radiation
                ShadGloLoss   = (RadProc.SimTilter.TGlo - SimShading.ShadTGlo) - RadProc.SimHorizonShading.LossGlo;
                ShadGloFactor = (RadProc.SimTilter.TGlo > 0 ? SimShading.ShadTGlo / RadProc.SimTilter.TGlo : 1);
                ShadBeamLoss  = RadProc.SimHorizonShading.TDir - SimShading.ShadTDir;
                ShadDiffLoss  = RadProc.SimTilter.TDif > 0 ? RadProc.SimHorizonShading.TDif - SimShading.ShadTDif : 0;
                ShadRefLoss   = RadProc.SimTilter.TRef > 0 ? RadProc.SimHorizonShading.TRef - SimShading.ShadTRef : 0;

                //Calculating total farm level variables. Cleaning them so they are non-cumulative.
                farmDC                  = 0;
                farmDCCurrent           = 0;
                farmDCMismatchLoss      = 0;
                farmDCModuleQualityLoss = 0;
                farmDCOhmicLoss         = 0;
                farmDCSoilingLoss       = 0;
                farmDCTemp              = 0;
                farmTotalModules        = 0;
                farmPNomDC              = 0;
                farmPNomAC              = 0;
                farmACPMinThreshLoss    = 0;
                farmACClippingPower     = 0;
                farmACMaxVoltageLoss    = 0;
                farmACMinVoltageLoss    = 0;
                farmPnom                = 0;
                farmTempLoss            = 0;
                farmRadLoss             = 0;

                for (int i = 0; i < SimPVA.Length; i++)
                {
                    farmDC                  += SimPVA[i].POut;
                    farmDCCurrent           += SimPVA[i].IOut;
                    farmDCMismatchLoss      += Math.Max(0, SimPVA[i].MismatchLoss);
                    farmDCModuleQualityLoss += SimPVA[i].ModuleQualityLoss;
                    farmDCOhmicLoss         += SimPVA[i].OhmicLosses;
                    farmDCSoilingLoss       += SimPVA[i].SoilingLoss;
                    farmDCTemp              += SimPVA[i].TModule * SimPVA[i].itsNumModules;
                    farmTotalModules        += SimPVA[i].itsNumModules;
                    farmPNomDC              += SimPVA[i].itsPNomDCArray;
                    farmPNomAC              += SimInv[i].itsPNomArrayAC;
                    farmACPMinThreshLoss    += SimInv[i].LossPMinThreshold;
                    farmACClippingPower     += SimInv[i].LossClipping;
                    farmACMaxVoltageLoss    += SimInv[i].LossHighVoltage;
                    farmACMinVoltageLoss    += SimInv[i].LossLowVoltage;
                    farmPnom                += (SimPVA[i].itsPNom * SimPVA[i].itsNumModules) * SimPVA[i].TGloEff / 1000;
                    farmTempLoss            += SimPVA[i].tempLoss;
                    farmRadLoss             += SimPVA[i].radLoss;
                }

                // Averages all PV Array temperature values
                farmDCTemp /= farmTotalModules;
                farmModuleTempAndAmbientTempDiff = farmDCTemp - SimMet.TAmbient;
                farmDCEfficiency = (RadProc.SimTilter.TGlo > 0 ? farmDC / (RadProc.SimTilter.TGlo * farmArea) : 0) * 100;
                farmPNomDC       = Utilities.ConvertWtokW(farmPNomDC);
                farmPNomAC       = Utilities.ConvertWtokW(farmPNomAC);

                farmOverAllEff = (RadProc.SimTilter.TGlo > 0 && SimTransformer.POut > 0 ? SimTransformer.POut / (RadProc.SimTilter.TGlo * farmArea) : 0) * 100;
                farmPR         = RadProc.SimTilter.TGlo > 0 && farmPNomDC > 0 && SimTransformer.POut > 0 ? SimTransformer.POut / RadProc.SimTilter.TGlo / farmPNomDC : 0;
                farmSysIER     = (SimTransformer.itsPNom - SimTransformer.POut) / (RadProc.SimTilter.TGlo * 1000);
            }
            catch (Exception ce)
            {
                ErrorLogger.Log(ce, ErrLevel.FATAL);
            }

            // Assigning Outputs for this class.
            AssignOutputs();
        }
Exemple #3
0
        // Method to start the simulation software run.
        public void Simulate(XmlDocument SiteSettings, String _Input = null, String _Output = null)
        {
            // Adding timer to calculate elapsed time for the simulation.
            Stopwatch timeTaken = new Stopwatch();

            timeTaken.Start();

            // Delete error log just before simulation
            if (File.Exists(Application.StartupPath + "/ErrorLog.txt"))
            {
                File.Delete(Application.StartupPath + "/ErrorLog.txt");
            }

            // ReadFarmSettings reads the overall configuration of the farm
            ReadFarmSettings.doc = SiteSettings;

            // Obtain IO File names, either from the command prompt, or from .CSYX
            if ((_Input == null) && (_Output == null))
            {
                ReadFarmSettings.AssignIOFileNames();
            }
            else
            {
                ReadFarmSettings.SimInputFile  = _Input;
                ReadFarmSettings.SimOutputFile = _Output;
            }

            // Collecting input and output file locations and Input/Output file location
            ReadFarmSettings.GetSimulationMode();

            // Inform user about site configuration:
            Console.WriteLine("Status: Configuring parameters");

            // Creating the SimMeteo Object to process the input file, and streamWriter to Write to the Output File
            try
            {
                // Reading and assigning the input file schema before configuring the inputs
                ReadFarmSettings.AssignInputFileSchema();

                // Instantiating the relevant simulation class based on the simulation mode
                switch (ReadFarmSettings.SystemMode)
                {
                case "ASTME2848Regression":
                    SimASTM = new ASTME2848();
                    SimASTM.Config();
                    break;

                case "GridConnected":
                    // Assign the Sub-Array Count for grid connected systems.
                    ReadFarmSettings.AssignSubArrayCount();
                    SimGridSys = new GridConnectedSystem();
                    SimGridSys.Config();
                    goto case "Radiation";

                case "Radiation":
                    SimRadProc = new RadiationProc();
                    SimRadProc.Config();
                    break;

                default:
                    ErrorLogger.Log("Invalid Simulation mode found. CASSYS will exit.", ErrLevel.FATAL);
                    break;
                }

                // Reading and assigning the input file schema and the output file schema
                ReadFarmSettings.AssignOutputFileSchema();

                // Notifying user of the Configuration status
                if (ErrorLogger.numWarnings == 0)
                {
                    Console.WriteLine("Status: Configuration OK.");
                }
                else
                {
                    Console.WriteLine("Status: There were problems encountered during configuration.");
                    Console.WriteLine("        Please see the error log file for details.");
                    Console.WriteLine("        CASSYS has configured parameters with default values.");
                }

                try
                {
                    // Read through the input file and perform calculations
                    Console.Write("Status: Simulation Running");

                    // Creating the input file parser
                    SimMeteo SimMeteoParser = new SimMeteo();
                    SimMeteoParser.Config();

                    // Create StreamWriter
                    if (ReadFarmSettings.outputMode == "str")
                    {
                        // Assigning Headers to output String
                        OutputString = ReadFarmSettings.OutputHeader.TrimEnd(',') + '\n';
                    }
                    // Create StreamWriter and write output to .csv file
                    else if (ReadFarmSettings.outputMode == "csv")
                    {
                        // If in batch mode, use the appending overload of StreamWriter
                        if ((File.Exists(ReadFarmSettings.SimOutputFile)) && (ReadFarmSettings.batchMode))
                        {
                            OutputFileWriter = new StreamWriter(ReadFarmSettings.SimOutputFile, true);
                        }
                        else
                        {
                            // Writing the headers to the new output file.
                            OutputFileWriter = new StreamWriter(ReadFarmSettings.SimOutputFile);

                            // Writing the headers to the new output file.
                            OutputFileWriter.WriteLine(ReadFarmSettings.OutputHeader);
                        }
                    }
                    // The following is executed if using iterative mode
                    else
                    {
                        // Row for output header created only during first simulation run
                        if (ReadFarmSettings.runNumber == 1)
                        {
                            ReadFarmSettings.outputTable.Rows.InsertAt(ReadFarmSettings.outputTable.NewRow(), 0);
                        }

                        // Placing output header in data table
                        ReadFarmSettings.outputTable.Rows[0][ReadFarmSettings.runNumber - 1] = ReadFarmSettings.OutputHeader.TrimEnd(',');
                    }

                    // Read through the Input File and perform the relevant simulation
                    while (!SimMeteoParser.InputFileReader.EndOfData)
                    {
                        SimMeteoParser.Calculate();

                        // If input file line could not be read, go to next line
                        if (!SimMeteoParser.inputRead)
                        {
                            continue;
                        }

                        // running required calculations based on simulation mode
                        switch (ReadFarmSettings.SystemMode)
                        {
                        case "ASTME2848Regression":
                            SimASTM.Calculate(SimMeteoParser);
                            break;

                        case "GridConnected":
                            SimRadProc.Calculate(SimMeteoParser);
                            SimGridSys.Calculate(SimRadProc, SimMeteoParser);
                            LossDiagram.Calculate();
                            break;

                        case "Radiation":
                            SimRadProc.Calculate(SimMeteoParser);
                            break;

                        default:
                            ErrorLogger.Log("Invalid Simulation mode found. CASSYS will exit.", ErrLevel.FATAL);
                            break;
                        }
                        // Only create output string in DLL mode, as creating string causes significant lag
                        if (ReadFarmSettings.outputMode == "str")
                        {
                            OutputString += String.Join(",", GetOutputLine()) + "\n";
                        }
                        // Write to output file
                        else if (ReadFarmSettings.outputMode == "csv")
                        {
                            try
                            {
                                // Assembling and writing the line containing all output values
                                OutputFileWriter.WriteLine(String.Join(",", GetOutputLine()));
                            }
                            catch (IOException ex)
                            {
                                ErrorLogger.Log(ex, ErrLevel.WARNING);
                            }
                        }
                        // Using Iterative Mode: Writes output to a datatable
                        else
                        {
                            // Create row if this is the first simulation run
                            if (ReadFarmSettings.runNumber == 1)
                            {
                                ReadFarmSettings.outputTable.Rows.InsertAt(ReadFarmSettings.outputTable.NewRow(), ReadFarmSettings.outputTable.Rows.Count);
                            }

                            // Write output values to data table
                            ReadFarmSettings.outputTable.Rows[ErrorLogger.iterationCount][ReadFarmSettings.runNumber - 1] = String.Join(",", GetOutputLine());
                        }
                    }

                    if (ReadFarmSettings.outputMode == "str")
                    {
                        // Trim newline character from the end of output
                        OutputString = OutputString.TrimEnd('\r', '\n');
                    }
                    // Write output to .csv file
                    else if (ReadFarmSettings.outputMode == "csv")
                    {
                        try
                        {
                            // Clean out the buffer of the writer to ensure all entries are written to the output file.
                            OutputFileWriter.Flush();
                            OutputFileWriter.Dispose();
                            SimMeteoParser.InputFileReader.Dispose();
                        }
                        catch (IOException ex)
                        {
                            ErrorLogger.Log(ex, ErrLevel.WARNING);
                        }
                    }

                    // If simulation done for Grid connected mode then write the calculated loss values to temp output file
                    if (ReadFarmSettings.SystemMode == "GridConnected")
                    {
                        LossDiagram.AssignLossOutputs();
                    }

                    timeTaken.Stop();

                    Console.WriteLine("");
                    Console.WriteLine("Status: Complete. Simulation took " + timeTaken.ElapsedMilliseconds / 1000D + " seconds.");
                }
                catch (IOException)
                {
                    ErrorLogger.Log("The output file name " + ReadFarmSettings.SimOutputFile + " is not accesible or is not available at the location provided.", ErrLevel.FATAL);
                }
            }
            catch (Exception ex)
            {
                ErrorLogger.Log("CASSYS encountered an unexpected error: " + ex.Message, ErrLevel.FATAL);
            }
        }
Exemple #4
0
        double CalcSkyViewDirection
        (
            double x                                            // Horizontal dimension in the row-to-row ground area
            , RowType rowType                                   // The position of the row being calculated relative to others [unitless]
            , double direction                                  // The direction in which to move along the x-axis [-1, 0, 1]
        )
        {
            double h = Math.Sin(itsPanelTilt);                  // Vertical height of sloped PV panel [panel slope lengths]
            double b = Math.Cos(itsPanelTilt);                  // Horizontal distance from front of panel to back of panel [panel slope lengths]

            double offset   = direction;                        // Initialize offset to begin at first unit of given direction
            double skyPatch = 0;                                // View factor for view of sky in single row-to-row area
            double skySum   = 0;                                // View factor for all sky views in given direction

            double angA  = 0;
            double angB  = 0;
            double angC  = 0;
            double angD  = 0;
            double beta1 = 0;                                   // Start of ground's field of view that sees the sky segment
            double beta2 = 0;                                   // End of ground's field of view that sees the sky segment

            // Sum sky view factors until sky view factor contributes <= 1% of sum
            // Only loop the calculation for rows extending forward or backward, so break loop when direction = 0.
            do
            {
                // Set back limiting angle to 0 since there is no row behind.
                if (rowType == RowType.LAST)
                {
                    beta1 = 0;
                }
                else
                {
                    // Angle from ground point to top of panel P
                    angA = Math.Atan2(h + itsClearance, (offset + 1) * itsPitch + b - x);
                    // Angle from ground point to bottom of panel P
                    angB = Math.Atan2(itsClearance, (offset + 1) * itsPitch - x);

                    beta1 = Math.Max(angA, angB);
                }

                // Set front limiting angle to PI since there is no row ahead.
                if (rowType == RowType.FIRST)
                {
                    beta2 = Math.PI;
                }
                else
                {
                    // Angle from ground point to top of panel Q
                    angC = Math.Atan2(h + itsClearance, offset * itsPitch + b - x);
                    // Angle from ground point to bottom of panel Q
                    angD = Math.Atan2(itsClearance, offset * itsPitch - x);

                    beta2 = Math.Min(angC, angD);
                }

                // If there is an opening in the sky through which the sun is seen, calculate view factor of sky patch
                skyPatch = (beta2 > beta1) ? RadiationProc.GetViewFactor(beta1, beta2) : 0;

                skySum += skyPatch;
                offset += direction;
            } while (offset != 0 && skyPatch > (0.01 * skySum));

            return(skySum);
        }
        double YearsSinceStart;                                 // Number of entire years since the beginning of the simulation

        // Calculate method
        public void Calculate
        (
            RadiationProc RadProc,                              // Radiation related data
            SimMeteo SimMet                                     // Meteological data from inputfile
        )
        {
            // Record number of years since start of simulation
            // This is used to calculate module ageing
            // Update StartTimeStamp if it has never been initialized
            if (StartTimeStamp == new DateTime())
            {
                StartTimeStamp = RadProc.TimeStampAnalyzed;
            }
            TimeSpan SimDelta = RadProc.TimeStampAnalyzed.Subtract(StartTimeStamp);

            YearsSinceStart = Math.Floor(SimDelta.Days / 365.25);

            // Reset Losses
            for (int i = 0; i < SimPVA.Length; i++)
            {
                SimInv[i].LossPMinThreshold = 0;
                SimInv[i].LossClipping      = 0;
                SimInv[i].LossLowVoltage    = 0;
                SimInv[i].LossHighVoltage   = 0;
            }

            // Calculating solar panel shading
            SimShading.Calculate(RadProc.SimSun.Zenith, RadProc.SimSun.Azimuth, RadProc.SimHorizonShading.TDir, RadProc.SimHorizonShading.TDif, RadProc.SimHorizonShading.TRef, RadProc.SimTracker.SurfSlope, RadProc.SimTracker.SurfAzimuth);

            if (RadProc.SimTracker.useBifacial)
            {
                // Calculating shading of ground beneath solar panels
                SimGround.Calculate(RadProc.SimSun.Zenith, RadProc.SimSun.Azimuth, RadProc.SimTracker.SurfSlope, RadProc.SimTracker.SurfAzimuth, RadProc.SimTracker.SurfClearance, RadProc.SimSplitter.HDir,
                                    RadProc.SimSplitter.HDif, RadProc.TimeStampAnalyzed);

                // Get front reflected diffuse irradiance, since it contributes to the back
                SimPVA[0].CalcEffectiveIrradiance(SimShading.ShadTDir, SimShading.ShadTDif, SimShading.ShadTRef, SimBackTilter.BGlo, RadProc.SimTilter.IncidenceAngle, SimMet.MonthOfYear, SimSpectral.clearnessCorrection);

                // Get incidence angle modifiers for components of irradiance
                SimPVA[0].CalcIAM(out SimBackTilter.IAMDir, out SimBackTilter.IAMDif, out SimBackTilter.IAMRef, RadProc.SimTilterOpposite.IncidenceAngle);

                // Calculate back side global irradiance
                SimBackTilter.Calculate(RadProc.SimTracker.SurfSlope, RadProc.SimTracker.SurfClearance, RadProc.SimSplitter.HDif, SimPVA[0].TDifRef, SimMet.HGlo, SimGround.frontGroundGHI, SimGround.rearGroundGHI, SimGround.aveGroundGHI,
                                        SimMet.MonthOfYear, SimShading.BackBeamSF, RadProc.SimTilterOpposite.TDir, RadProc.TimeStampAnalyzed);
            }
            else
            {
                SimBackTilter.BGlo = 0;
            }

            // Calculating spectral model effects
            SimSpectral.Calculate(SimMet.HGlo, RadProc.SimSun.NExtra, RadProc.SimSun.Zenith);

            try
            {
                // Calculate PV Array Output for inputs read in this loop
                for (int j = 0; j < ReadFarmSettings.SubArrayCount; j++)
                {
                    // Adjust the IV Curve based on Temperature and Irradiance.
                    SimPVA[j].CalcIVCurveParameters(SimMet.TGlo, SimShading.ShadTDir, SimShading.ShadTDif, SimShading.ShadTRef, SimBackTilter.BGlo, RadProc.SimTilter.IncidenceAngle, SimMet.TAmbient, SimMet.WindSpeed, SimMet.TModMeasured, SimMet.MonthOfYear, SimSpectral.clearnessCorrection);

                    // Check Inverter status to determine if the Inverter is ON or OFF
                    GetInverterStatus(j);

                    // If inverter is off set appropriate variables to 0 and recalculate array in open circuit voltage
                    if (!SimInv[j].isON)
                    {
                        SimInv[j].ACPwrOut = 0;
                        SimInv[j].IOut     = 0;
                        SimPVA[j].CalcAtOpenCircuit();
                        SimPVA[j].Calculate(false, SimPVA[j].Voc, YearsSinceStart);
                    }

                    //performing AC wiring calculations
                    SimACWiring[j].Calculate(SimInv[j]);

                    // Assigning the outputs to the dictionary
                    ReadFarmSettings.Outputlist["SubArray_Current" + (j + 1).ToString()]     = SimPVA[j].IOut;
                    ReadFarmSettings.Outputlist["SubArray_Voltage" + (j + 1).ToString()]     = SimPVA[j].VOut;
                    ReadFarmSettings.Outputlist["SubArray_Power" + (j + 1).ToString()]       = SimPVA[j].POut / 1000;
                    ReadFarmSettings.Outputlist["SubArray_Current_Inv" + (j + 1).ToString()] = SimInv[j].IOut;
                    ReadFarmSettings.Outputlist["SubArray_Voltage_Inv" + (j + 1).ToString()] = SimInv[j].itsOutputVoltage;
                    ReadFarmSettings.Outputlist["SubArray_Power_Inv" + (j + 1).ToString()]   = SimInv[j].ACPwrOut / 1000;
                }

                // Calculating total farm output and total ohmic loss
                farmACOutput    = 0;
                farmACOhmicLoss = 0;
                for (int i = 0; i < SimInv.Length; i++)
                {
                    farmACOutput    += SimInv[i].ACPwrOut;
                    farmACOhmicLoss += SimACWiring[i].ACWiringLoss;
                }

                SimTransformer.Calculate(farmACOutput - farmACOhmicLoss);

                // Calculating outputs that will be assigned for this interval
                // Shading each component of the Tilted radiaton
                // Using horizon affected tilted radiation
                ShadGloLoss   = (RadProc.SimTilter.TGlo - SimShading.ShadTGlo) - RadProc.SimHorizonShading.LossGlo;
                ShadGloFactor = (RadProc.SimTilter.TGlo > 0 ? SimShading.ShadTGlo / RadProc.SimTilter.TGlo : 1);
                ShadBeamLoss  = RadProc.SimHorizonShading.TDir - SimShading.ShadTDir;
                ShadDiffLoss  = RadProc.SimTilter.TDif > 0 ? RadProc.SimHorizonShading.TDif - SimShading.ShadTDif : 0;
                ShadRefLoss   = RadProc.SimTilter.TRef > 0 ? RadProc.SimHorizonShading.TRef - SimShading.ShadTRef : 0;

                //Calculating total farm level variables. Cleaning them so they are non-cumulative.
                farmDC                  = 0;
                farmDCCurrent           = 0;
                farmDCMismatchLoss      = 0;
                farmDCModuleQualityLoss = 0;
                farmDCModuleLIDLoss     = 0;
                farmDCModuleAgeingLoss  = 0;
                farmDCOhmicLoss         = 0;
                farmDCSoilingLoss       = 0;
                farmDCTemp              = 0;
                farmTotalModules        = 0;
                farmPNomDC              = 0;
                farmPNomAC              = 0;
                farmACPMinThreshLoss    = 0;
                farmACClippingPower     = 0;
                farmACMaxVoltageLoss    = 0;
                farmACMinVoltageLoss    = 0;
                farmPnom                = 0;
                farmTempLoss            = 0;
                farmRadLoss             = 0;

                for (int i = 0; i < SimPVA.Length; i++)
                {
                    farmDC                  += SimPVA[i].POut;
                    farmDCCurrent           += SimPVA[i].IOut;
                    farmDCMismatchLoss      += Math.Max(0, SimPVA[i].MismatchLoss);
                    farmDCModuleQualityLoss += SimPVA[i].ModuleQualityLoss;
                    farmDCModuleLIDLoss     += SimPVA[i].ModuleLIDLoss;
                    farmDCModuleAgeingLoss  += SimPVA[i].ModuleAgeingLoss;
                    farmDCOhmicLoss         += SimPVA[i].OhmicLosses;
                    farmDCSoilingLoss       += SimPVA[i].SoilingLoss;
                    farmDCTemp              += SimPVA[i].TModule * SimPVA[i].itsNumModules;
                    farmTotalModules        += SimPVA[i].itsNumModules;
                    farmPNomDC              += SimPVA[i].itsPNomDCArray;
                    farmPNomAC              += SimInv[i].itsPNomArrayAC;
                    farmACPMinThreshLoss    += SimInv[i].LossPMinThreshold;
                    farmACClippingPower     += SimInv[i].LossClipping;
                    farmACMaxVoltageLoss    += SimInv[i].LossHighVoltage;
                    farmACMinVoltageLoss    += SimInv[i].LossLowVoltage;
                    farmPnom                += (SimPVA[i].itsPNom * SimPVA[i].itsNumModules) * SimPVA[i].RadEff / 1000;
                    farmTempLoss            += SimPVA[i].tempLoss;
                    farmRadLoss             += SimPVA[i].radLoss;
                }

                // Averages all PV Array temperature values
                farmDCTemp /= farmTotalModules;
                farmModuleTempAndAmbientTempDiff = farmDCTemp - SimMet.TAmbient;
                farmDCEfficiency = (RadProc.SimTilter.TGlo > 0 ? farmDC / (RadProc.SimTilter.TGlo * farmArea) : 0) * 100;
                farmPNomDC       = Utilities.ConvertWtokW(farmPNomDC);
                farmPNomAC       = Utilities.ConvertWtokW(farmPNomAC);

                farmOverAllEff = (RadProc.SimTilter.TGlo > 0 && SimTransformer.POut > 0 ? SimTransformer.POut / (RadProc.SimTilter.TGlo * farmArea) : 0) * 100;
                farmPR         = RadProc.SimTilter.TGlo > 0 && farmPNomDC > 0 && SimTransformer.POut > 0 ? SimTransformer.POut / RadProc.SimTilter.TGlo / farmPNomDC : 0;
                farmSysIER     = (SimTransformer.itsPNom - SimTransformer.POut) / (RadProc.SimTilter.TGlo * 1000);
            }
            catch (Exception ce)
            {
                ErrorLogger.Log(ce, ErrLevel.FATAL);
            }

            // Assigning Outputs for this class.
            AssignOutputs();
        }