private void buttonOptimize_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
             calcStats cStat = new calcStats();
             long strSamp, sgSamp, sgSamp1, sgSamp2;
             double combWtCV, strCV, strCalcError, sgCV, sgCalcError, totVolume;
             // get sale volume
             double tVolume = cdStratumStats.Sum(P => P.TotalVolume);
             if (tVolume == 0)
             {
            MessageBox.Show("No volume. Cannot calculate sample sizes.", "Warning");
            return;
             }
             if (mySale.DefaultUOM == "01")
            totVolume = tVolume * 1000.0;
             else
            totVolume = tVolume * 100.0;
             // get weighted sale cv
             double saleCV = 0;
             long strSamp1 = 0;
             long strSamp2 = 0;
             double sumError = 0;
             double sumVolume = 0;
             double tStrVol;
             foreach (StratumStatsDO thisStrStats in cdStratumStats)
             {
            if (mySale.DefaultUOM == "01")
               tStrVol = thisStrStats.TotalVolume * 1000.0;
            else
               tStrVol = thisStrStats.TotalVolume * 100.0;

            int stage = cStat.isTwoStage(thisStrStats.Method);
            // single stage wted CV
            if (stage == 10 || stage == 11 || stage == 21)
            {
               saleCV += thisStrStats.WeightedCV1 * (tStrVol / totVolume);
            }
            // 2 stage wted CV
            else
            {
               combWtCV = (thisStrStats.WeightedCV1 + thisStrStats.WeightedCV2) / 2.0;
               saleCV += combWtCV * (tStrVol / totVolume);
            }
             }
             if (saleCV == 0)
             {
            MessageBox.Show("Cannot calculate weighted sale CV.", "Warning");
            return;
             }

             //float saleCV = cdStratumStats.Sum(P => ((P.WeightedCV1 * P.TotalVolume)/totVolume));
             double saleOptError = Convert.ToSingle(numericUpDown1.Value);
             // calculate sale level sample size
             long saleCalcSamples = cStat.getSampleSize(saleOptError, saleCV);
             // calculate sale error using t-value of 2
             double saleCalcError = cStat.getSampleError(saleCV, saleCalcSamples, 2.0);
             // correct sample size using correct t-value
             double saleSamples = cStat.checkTValueError(saleCV, saleCalcSamples, saleCalcError);

             // prorate to strata
             foreach (StratumStatsDO thisStrStats in cdStratumStats)
             {
            int stage = cStat.isTwoStage(thisStrStats.Method);
            long strSample1 = 0;
            long strSample2 = 0;
            double wtErr = 0;
            float acres = thisStrStats.TotalAcres;
            float stTpa = thisStrStats.TreesPerAcre;
            long stN = (long)Math.Ceiling(stTpa * acres);
            // single stage wted CV
            if (mySale.DefaultUOM == "01")
               tStrVol = thisStrStats.TotalVolume * 1000.0;
            else
               tStrVol = thisStrStats.TotalVolume * 100.0;

            if (stage == 10 || stage == 21)
            {
               strCV = thisStrStats.WeightedCV1 * (tStrVol / totVolume);
               strSamp = Convert.ToInt32((strCV / saleCV) * saleSamples);
               strCalcError = cStat.getSampleError(thisStrStats.WeightedCV1, strSamp, 2.0);
               // correct for t-value
               strSamp1 = cStat.checkTValueError(thisStrStats.WeightedCV1, strSamp, strCalcError);
            }
            else if (stage == 11)
            {
               strCV = thisStrStats.WeightedCV1 * (tStrVol / totVolume);
               strSamp = Convert.ToInt32((strCV / saleCV) * saleSamples);
               strCalcError = cStat.getSampleError(thisStrStats.WeightedCV1, strSamp, 2.0);
               // correct for t-value
               strSamp1 = cStat.checkTValueError(thisStrStats.WeightedCV1, strSamp, strCalcError, stN);
            }
            // 2 stage wted CV
            else
            {
               combWtCV = (thisStrStats.WeightedCV1 + thisStrStats.WeightedCV2) / 2.0;
               strCV = combWtCV * (tStrVol / totVolume);
               strSamp = Convert.ToInt32((strCV / saleCV) * saleSamples);
               strCalcError = cStat.getSampleError(combWtCV, strSamp, 2.0);
               cStat.getTwoStageSampleSize(thisStrStats.WeightedCV1, thisStrStats.WeightedCV2, strCalcError);
               // correct for t-value
               strSamp2 = cStat.sampleSize2;
               strSamp1 = cStat.checkTValueError2Stage(thisStrStats.WeightedCV1, thisStrStats.WeightedCV2, cStat.sampleSize1, cStat.sampleSize2, strCalcError);
            }
            List<SampleGroupStatsDO> mySgStats = new List<SampleGroupStatsDO>(cdDAL.Read<SampleGroupStatsDO>("SampleGroupStats", "Where StratumStats_CN = ?", thisStrStats.StratumStats_CN));
            long sgSamp2Stage1 = 0;
            long sgSamp2Stage2 = 0;
            foreach (SampleGroupStatsDO thisSgStats in mySgStats)
            {
               float sgTpa = thisSgStats.TreesPerAcre;
               long sgN = (long)Math.Ceiling(sgTpa * acres);
               // prorate to sample groups
               if (stage == 11)
               {
                  sgCV = thisSgStats.CV1 * (thisSgStats.VolumePerAcre / thisStrStats.VolumePerAcre);
                  sgSamp = Convert.ToInt32((sgCV / thisStrStats.WeightedCV1) * strSamp1);
                  sgCalcError = cStat.getSampleError(thisSgStats.CV1, sgSamp, 2.0);
                  // correct for t-value
                  sgSamp1 = cStat.checkTValueError(thisSgStats.CV1, sgSamp, sgCalcError, sgN);
                  if (sgSamp1 < 3) sgSamp1 = 3;
                  sgSamp2 = 0;
                  sgCalcError = cStat.getSampleError(thisSgStats.CV1, sgSamp1, 0, sgN);
               }
               else if (stage == 21)
               {
                  sgCV = thisSgStats.CV1 * (thisSgStats.VolumePerAcre / thisStrStats.VolumePerAcre);
                  sgSamp = Convert.ToInt32((sgCV / thisStrStats.WeightedCV1) * strSamp1);
                  sgCalcError = cStat.getSampleError(thisSgStats.CV1, sgSamp, 2.0);
                  // correct for t-value
                  sgSamp1 = cStat.checkTValueError(thisSgStats.CV1, sgSamp, sgCalcError);
                  if (sgSamp1 < 3) sgSamp1 = 3;
                  sgSamp2 = (long)(thisSgStats.TreesPerPlot * sgSamp1);

                  sgCalcError = cStat.getSampleError(thisSgStats.CV1, sgSamp1, 0);
               }
               else if (stage == 10)
               {
                  sgSamp1 = Convert.ToInt32(thisSgStats.TreesPerAcre * thisStrStats.TotalAcres);
                  sgSamp2 = 0;
                  sgCalcError = 0;
               }
               else
               {
                  sgCV = thisSgStats.CV2 * (thisSgStats.VolumePerAcre / thisStrStats.VolumePerAcre);
                  sgSamp2 = Convert.ToInt32((sgCV / thisStrStats.WeightedCV2) * strSamp2);
                  if (sgSamp2 < 3) sgSamp2 = 3;
                  sgCV = thisSgStats.CV1 * (thisSgStats.VolumePerAcre / thisStrStats.VolumePerAcre);
                  sgSamp1 = Convert.ToInt32((sgCV / thisStrStats.WeightedCV1) * strSamp1);
                  if (sgSamp1 < 3) sgSamp1 = 3;

                  if (stage == 12)
                  {
                     if (sgSamp2 > sgSamp1) sgSamp1 = sgSamp2;
                  }
                  else
                  {
                     if (sgSamp1 > sgSamp2Stage1) sgSamp2Stage1 = sgSamp1;
                  }

                  thisSgStats.SampleSize1 = sgSamp1;
                  thisSgStats.SampleSize2 = sgSamp2;
                  sgCalcError = cStat.getTwoStageError(thisSgStats.CV1, thisSgStats.CV2, sgSamp1, sgSamp2);
               }
               thisSgStats.SampleSize1 = sgSamp1;
               thisSgStats.SampleSize2 = sgSamp2;
               // update errors, frequency, KZ, BigBAF
               if (thisStrStats.Method == "STR")
               {
                  thisSgStats.SamplingFrequency = Convert.ToInt32((thisSgStats.TreesPerAcre * thisStrStats.TotalAcres) / sgSamp1);
                  strSample1 += sgSamp1;
               }
               else if (thisStrStats.Method == "S3P")
               {
                  thisSgStats.SamplingFrequency = Convert.ToInt32((thisSgStats.TreesPerAcre * thisStrStats.TotalAcres) / sgSamp1);
                  strSample1 += sgSamp1;
                  strSample2 += sgSamp2;
               }
               else if (thisStrStats.Method == "100")
               {
                  thisSgStats.SamplingFrequency = 1;
                  strSample1 += sgSamp1;
               }
               else if (thisStrStats.Method == "3P")
               {
                  thisSgStats.KZ = Convert.ToInt32((thisSgStats.VolumePerAcre * thisStrStats.TotalAcres) / sgSamp1);
                  strSample1 += sgSamp1;
               }
               else if (thisStrStats.Method == "S3P")
               {
                  if (thisSgStats.TreesPerAcre > 0)
                     thisSgStats.KZ = Convert.ToInt32(((thisSgStats.VolumePerAcre / thisSgStats.TreesPerAcre * sgSamp1) / sgSamp2));
                  else
                     thisSgStats.KZ = 1;
                  strSample1 += sgSamp1;
                  strSample2 += sgSamp2;
               }
               else if (thisStrStats.Method == "PNT" || thisStrStats.Method == "FIX")
               {
                  strSample1 = sgSamp1;
                  strSample2 = sgSamp2;

               }
               // calc sg error
               if(stage != 22)
               {
                  if (stage == 11)
                  {
                    thisSgStats.SgError = Convert.ToSingle(Math.Round(cStat.getSampleError(thisSgStats.CV1,sgSamp1, 0, sgN), 2));
                  }
                  else if (stage == 21)
                  {
                     thisSgStats.SgError = Convert.ToSingle(Math.Round(cStat.getSampleError(thisSgStats.CV1, sgSamp1, 0), 2));
                  }
                  else if (stage == 12 || stage == 22)
                  {
                     thisSgStats.SgError = Convert.ToSingle(Math.Round(cStat.getTwoStageError(thisSgStats.CV1, thisSgStats.CV2, sgSamp1, sgSamp2), 2));
                  }
                  // calc combined stratum error
                  wtErr += (double)Math.Pow((thisSgStats.SgError * (thisSgStats.VolumePerAcre * thisStrStats.TotalAcres)), 2);
               }
               thisSgStats.Save();
            }
            if (stage == 22)
            {
               //loop back through
               foreach (SampleGroupStatsDO thisSgStats in mySgStats)
               {
                  // set each sample size to sgSamp2Stage
                  strSample1 = sgSamp2Stage1;
                  sgSamp2Stage2 = thisSgStats.SampleSize2;
                  strSample2 += sgSamp2Stage2;
                  // set frequencies
                  if (thisStrStats.Method == "FCM")
                  {
                     thisSgStats.SamplingFrequency = Convert.ToInt32((thisSgStats.TreesPerPlot * sgSamp2Stage1) / sgSamp2Stage2);
                  }
                  else if (thisStrStats.Method == "PCM")
                  {
                     thisSgStats.SamplingFrequency = Convert.ToInt32((thisSgStats.TreesPerPlot * sgSamp2Stage1) / sgSamp2Stage2);
                     thisSgStats.BigBAF = Convert.ToSingle(thisSgStats.SamplingFrequency * thisStrStats.BasalAreaFactor);
                  }
                  else if (thisStrStats.Method == "P3P")
                  {
                     thisSgStats.KZ = Convert.ToInt32((thisSgStats.TreesPerPlot * sgSamp2Stage1 * thisSgStats.AverageHeight) / sgSamp2Stage2);
                  }
                  else if (thisStrStats.Method == "F3P" || thisStrStats.Method == "3PPNT")
                  {
                     if (thisSgStats.TreesPerAcre > 0)
                        thisSgStats.KZ = Convert.ToInt32((thisSgStats.TreesPerPlot * sgSamp2Stage1 * (thisSgStats.VolumePerAcre / thisSgStats.TreesPerAcre)) / sgSamp2Stage2);
                     else
                        thisSgStats.KZ = 1;
                  }
                  thisSgStats.SampleSize1 = sgSamp2Stage1;
                  thisSgStats.SgError = Convert.ToSingle(Math.Round(cStat.getTwoStageError(thisSgStats.CV1, thisSgStats.CV2, sgSamp2Stage1, sgSamp2Stage2), 2));
               // calc combined stratum error
                  thisSgStats.Save();
                  wtErr += (double)Math.Pow((thisSgStats.SgError * (thisSgStats.VolumePerAcre * thisStrStats.TotalAcres)), 2);
               }
            }

            // Update Stratum
            if(mySale.DefaultUOM == "01")
               thisStrStats.StrError = (float)(Math.Sqrt(wtErr) / (tStrVol));
            else
               thisStrStats.StrError = (float)(Math.Sqrt(wtErr) / (tStrVol));

            thisStrStats.SampleSize1 = strSample1;
            thisStrStats.SampleSize2 = strSample2;
            if (stage > 20)
            {
               thisStrStats.PlotSpacing = (int)Math.Floor(Math.Sqrt((thisStrStats.TotalAcres * 43560) / strSample1));
            }
            thisStrStats.Save();
            sumError += (double)Math.Pow((tStrVol * thisStrStats.StrError),2);
            sumVolume += tStrVol;
             }
             // Update Sale Error and Cost
             getSaleError();
             //double saleError = Math.Sqrt(sumError) / sumVolume;
             //textBoxError.Text = (Math.Round(saleError, 2)).ToString();
             //textBoxVolume.Text = (Math.Round(tVolume, 0)).ToString();

             Cursor.Current = this.Cursor;
             return;
        }