/// <summary> Normalizes PDF and CDF such that area under curve adds to 100 </summary>
        public void Normalize_Dists(ref ExceedanceCurve thisCurve)
        {
            double pdfSum = 0;

            if (thisCurve.distSize <= 1)
            {
                return;
            }

            double pdfInt = (thisCurve.upperBound - thisCurve.lowerBound) / (thisCurve.distSize - 1);

            for (int i = 0; i < thisCurve.distSize; i++)
            {
                pdfSum = pdfSum + thisCurve.probDist[i];
            }

            pdfSum = pdfSum * pdfInt;

            if (pdfSum > 0)
            {
                for (int i = 0; i < thisCurve.distSize; i++)
                {
                    thisCurve.probDist[i] = thisCurve.probDist[i] / pdfSum;
                }
            }

            thisCurve.cumulDist[0] = thisCurve.probDist[0] * pdfInt;

            for (int i = 1; i < thisCurve.distSize; i++) // Cumulative distribution function (CDF) of normal distribution = sum of PDF for all x <= X
            {
                thisCurve.cumulDist[i] = thisCurve.cumulDist[i - 1] + thisCurve.probDist[i] * pdfInt;
            }
        }
        /// <summary> Calculates the probability density function from the cumulative distribution function </summary>
        public void Calc_PDF_from_CDF(ref ExceedanceCurve thisExceed)
        {
            double distInt = (thisExceed.upperBound - thisExceed.lowerBound) / (thisExceed.distSize - 1);

            thisExceed.probDist[0] = thisExceed.cumulDist[0] * distInt;

            if (distInt == 0)
            {
                return;
            }

            for (int i = 1; i < thisExceed.distSize - 1; i++)
            {
                thisExceed.probDist[i] = (thisExceed.cumulDist[i + 1] - thisExceed.cumulDist[i]) / distInt;
            }
        }
        /// <summary> Deletes specified exceedance curve from list </summary>
        public void Delete_Exceed(string Delete_Exceed_str)
        {
            ExceedanceCurve[] newCurves = new ExceedanceCurve[Num_Exceed() - 1];
            int newCrvInd = 0;

            foreach (ExceedanceCurve theseExceed in exceedCurves)
            {
                if (theseExceed.exceedStr != Delete_Exceed_str)
                {
                    newCurves[newCrvInd] = theseExceed;
                    newCrvInd++;
                }
            }

            exceedCurves = newCurves;
        }
        /// <summary> Gets performance factor for specified exceedance curve with specified X-value (0 - 1) </summary>
        /// <returns> Returns performance factor </returns>
        public double Get_PF_Value(double val, ExceedanceCurve thisCurve)
        {
            double Exceed_Val = 0;

            for (int i = 0; i < thisCurve.distSize - 1; i++)
            {
                if (val <= thisCurve.cumulDist[i + 1] && val >= thisCurve.cumulDist[i])
                {
                    Exceed_Val = thisCurve.xVals[i];
                    break;
                }
            }

            if (Exceed_Val == 0)
            {
                Exceed_Val = thisCurve.xVals[0];
            }

            return(Exceed_Val);
        }
        /// <summary> Calculates weighted average probability and cumulative distribution with specified mean, SD and weights of defined modes </summary>
        public void CalculateProbDist(ref ExceedanceCurve thisCurve)
        {
            double X_int;
            int    numModes = thisCurve.modes.Length;

            if (numModes == 0)
            {
                return;
            }

            if (thisCurve.upperBound > thisCurve.lowerBound && thisCurve.upperBound != thisCurve.lowerBound)
            {
                X_int = (thisCurve.upperBound - thisCurve.lowerBound) / (thisCurve.distSize - 1);
            }
            else
            {
                return;
            }

            // Reset PDF
            Array.Resize(ref thisCurve.probDist, thisCurve.probDist.Length);

            for (int i = 0; i < thisCurve.distSize; i++)
            {
                thisCurve.xVals[i] = thisCurve.lowerBound + X_int * i;

                for (int j = 0; j < numModes; j++)
                {
                    double thisMean   = thisCurve.modes[j].mean;
                    double thisSD     = thisCurve.modes[j].SD;
                    double thisWeight = thisCurve.modes[j].weight;

                    // Probability density function of normal distribution
                    thisCurve.probDist[i] = thisCurve.probDist[i] + thisWeight *
                                            (1 / Math.Pow((2 * Math.Pow(thisSD, 2) * Math.PI), 0.5) * Math.Pow(Math.E, -(Math.Pow((thisCurve.xVals[i] - thisMean), 2) / (2 * Math.Pow(thisSD, 2)))));
                }
            }
        }
        /// <summary> Used when importing CDF from a .CSV file. Fills in all Performance factors by interpolating between points in file. </summary>
        public void Interpolate_CDF(ref ExceedanceCurve thisCurve, double[,] Imported_CDF)
        {
            thisCurve.lowerBound = Imported_CDF[0, 0];
            thisCurve.upperBound = Imported_CDF[Imported_CDF.GetUpperBound(0), 0];

            int numPts = Imported_CDF.GetUpperBound(0) + 1;

            double Delta_X = (thisCurve.upperBound - thisCurve.lowerBound) / (thisCurve.distSize - 1);

            for (int i = 0; i < thisCurve.distSize; i++)
            {
                thisCurve.xVals[i] = thisCurve.lowerBound + i * Delta_X;

                for (int j = 0; j < numPts - 1; j++)
                {
                    if ((thisCurve.xVals[i] >= Imported_CDF[j, 0]) && (thisCurve.xVals[i] <= Imported_CDF[j + 1, 0]))
                    {
                        // interpolate between points
                        thisCurve.cumulDist[i] = Imported_CDF[j, 1] + (thisCurve.xVals[i] - Imported_CDF[j, 0]) / (Imported_CDF[j + 1, 0] - Imported_CDF[j, 0]) * (Imported_CDF[j + 1, 1] - Imported_CDF[j, 1]);
                        break;
                    }
                }
            }
        }
        /// <summary> Imports exeedance curves </summary>
        public void ImportExceedCurves(Continuum thisInst)
        {
            if (thisInst.ofdExceedCurves.ShowDialog() == DialogResult.OK)
            {
                string       fileName = thisInst.ofdExceedCurves.FileName;
                StreamReader sr       = new StreamReader(fileName);

                sr.ReadLine(); // Header
                sr.ReadLine(); // Date
                sr.ReadLine(); // Blank

                ExceedanceCurve[] importedCurves = new ExceedanceCurve[0];
                int curveCount = 0;

                while (sr.EndOfStream == false)
                {
                    try
                    {
                        // Read in exceed curve name
                        string exceedName = sr.ReadLine();
                        curveCount++;
                        string[] exceedNameStrs = exceedName.Split(',');
                        Array.Resize(ref importedCurves, curveCount);
                        importedCurves[curveCount - 1].exceedStr = exceedNameStrs[0];

                        // Read in lower bound
                        string   lwrBound  = sr.ReadLine();
                        string[] lwrBounds = lwrBound.Split(',');
                        importedCurves[curveCount - 1].lowerBound = Convert.ToDouble(lwrBounds[1]) / 100;

                        // Read in lower bound
                        string   uprBound  = sr.ReadLine();
                        string[] uprBounds = uprBound.Split(',');
                        importedCurves[curveCount - 1].upperBound = Convert.ToDouble(uprBounds[1]) / 100;

                        // Read in modes
                        string   thisMode = sr.ReadLine();
                        string[] modeNum  = thisMode.Split(',', ' ');
                        int      numModes = 0;

                        while (modeNum[0] == "Mode")
                        {
                            numModes++;

                            if (numModes == 1)
                            {
                                importedCurves[curveCount - 1].modes = new Mode_Def[1];
                            }
                            else
                            {
                                Array.Resize(ref importedCurves[curveCount - 1].modes, numModes);
                            }

                            // Read in mode mean
                            string   meanStr  = sr.ReadLine();
                            string[] meanStrs = meanStr.Split(',');
                            importedCurves[curveCount - 1].modes[numModes - 1].mean = Convert.ToSingle(meanStrs[2]) / 100;

                            // Read in mode SD
                            string   sdStr  = sr.ReadLine();
                            string[] sdStrs = sdStr.Split(',');
                            importedCurves[curveCount - 1].modes[numModes - 1].SD = Convert.ToSingle(sdStrs[2]) / 100;

                            // Read in mode weight
                            string   weightStr  = sr.ReadLine();
                            string[] weightStrs = weightStr.Split(',');
                            importedCurves[curveCount - 1].modes[numModes - 1].weight = Convert.ToSingle(weightStrs[2]) / 100;

                            thisMode = sr.ReadLine();
                            modeNum  = thisMode.Split(',', ' ');
                        }

                        // Read in performance factors (x values)
                        string[] pf = modeNum; // modeNum holds the performance factor array

                        if (numModes == 0)
                        {
                            string allPFs = sr.ReadLine();
                            pf = allPFs.Split(',');
                        }

                        int distSize = pf.Length - 2; // Minus due to "PF" at the beginning and one empty space at end
                        Array.Resize(ref importedCurves[curveCount - 1].xVals, distSize);
                        Array.Resize(ref importedCurves[curveCount - 1].probDist, distSize);
                        Array.Resize(ref importedCurves[curveCount - 1].cumulDist, distSize);
                        importedCurves[curveCount - 1].distSize = distSize;

                        for (int i = 0; i < distSize; i++)
                        {
                            importedCurves[curveCount - 1].xVals[i] = Convert.ToDouble(pf[i + 1]) / 100;
                        }

                        string allPDFs = sr.ReadLine();
                        pf = allPDFs.Split(',');

                        // Read in PDFs
                        for (int i = 0; i < distSize; i++)
                        {
                            importedCurves[curveCount - 1].probDist[i] = Convert.ToDouble(pf[i + 1]);
                        }

                        string allCDFs = sr.ReadLine();
                        pf = allCDFs.Split(',');

                        // Read in CDFs
                        for (int i = 0; i < distSize; i++)
                        {
                            importedCurves[curveCount - 1].cumulDist[i] = Convert.ToDouble(pf[i + 1]);
                        }

                        // Empty line before next
                        sr.ReadLine();
                    }
                    catch
                    {
                        MessageBox.Show("Error reading in exceedance curves.", "Continuum 3");
                        sr.Close();
                        return;
                    }
                }

                thisInst.turbineList.exceed.exceedCurves = importedCurves;

                sr.Close();
            }
        }