// Main method - compute dummy stub.
        public Data ComputeDummy(Data Data)
        {
            /// Get your needed input data here

            // Example - get rig state and blovk height
            DataValues rigStates    = util.FindDataColumn(Data, "Rig_State");
            DataValues blockHeights = util.FindDataColumn(Data, "Block_Height");

            // Define you data output channels here
            // Create an output data column to store results back into Data
            DataValues Output = new DataValues();

            Output.Name  = "Your output data column name";
            Output.Units = "Your output data units";

            // Create data array storage for output
            Output.DataColumn = new List <DataValue>();


            // Put you calculation logic here

            // Example do dummy calculation - remember to cast values to the proper type (string, double, int, ....)
            double dummy = 0;

            foreach (DataValue dv in blockHeights.DataColumn)
            {
                DateTime t   = Convert.ToDateTime(dv.Timestamp);
                double   val = Convert.ToDouble(dv.Value);

                dummy = dummy + val;

                /// Store result back into Data
                Output.DataColumn.Add(new DataValue(t, dummy.ToString()));
            }

            // or

            for (int i = 0; i < blockHeights.DataColumn.Count; i++)
            {
                DateTime t        = Convert.ToDateTime(blockHeights.DataColumn[i].Timestamp);
                double   val      = Convert.ToDouble(blockHeights.DataColumn[i].Value);
                string   rigState = RigStateDummy[Convert.ToInt32(rigStates.DataColumn[i].Value)];

                if (rigState == "Drilling")
                {
                    dummy = dummy + val;
                }
                else
                {
                    dummy = dummy - val;
                }

                /// Put you output back into Data
                Output.DataColumn.Add(new DataValue(t, dummy.ToString()));
            }

            // Return the updated Data to the master routines
            Data.DataList.Add(Output);
            return(Data);
        }
        // Main method - compute ROP from changes into block height in time, using a rig state (rotary drilling, slide drilling, or
        // oscillate slide drilling) to determine if the bit depth needs to be calculated.  Currently this uses a temporary single state
        // (enumeration = 2, which should be drilling)
        public Data ComputeBitDepth(Data Data)
        {
            // Find the Rig State data column
            DataValues blockHeight = utility.FindDataColumn(Data, "Block_Height");
            DataValues rigStates   = utility.FindDataColumn(Data, "Rig_State");

            // Create output
            DataValues bitDepth = new DataValues();

            bitDepth.Name  = "Bit_Depth";
            bitDepth.Units = blockHeight.Units;
            bitDepth.Raw   = false;
            double oldBitDepth    = 0;
            double oldBlockHeight = 0;

            // Create data array storage for output
            bitDepth.DataColumn = new List <DataValue>();

            /// do the algorithm
            for (int i = 0; i < blockHeight.DataColumn.Count; i++)
            {
                // Get calculation values
                DateTime t        = Convert.ToDateTime(blockHeight.DataColumn[i].Timestamp);
                double   val      = Convert.ToDouble(blockHeight.DataColumn[i].Value);
                string   rigState = RigStateBitDepth[Convert.ToInt32(rigStates.DataColumn[i].Value)];
                double   bd       = 0;

                if (i == 0)
                {
                    // Trap first time through algorithm - need at least two values to compute ROP
                    bd             = 0;
                    oldBitDepth    = 0;
                    oldBlockHeight = val;
                }
                else if (val == -999.25)
                {
                    // Trap schlumberger null value
                    bd = val;
                }
                else
                {
                    // Compute ROP
                    if (rigState == "Drilling" || rigState == "Reaming" || rigState == "TripIn" || rigState == "TripOut")
                    {
                        bd          = oldBitDepth + (oldBlockHeight - val);
                        oldBitDepth = bd;
                    }
                    else
                    {
                        bd = oldBitDepth;
                    }
                    oldBlockHeight = val;
                }

                /// Put you output back into Data
                bitDepth.DataColumn.Add(new DataValue(t, bd.ToString()));
            }
            Data.DataList.Add(bitDepth);
            return(Data);
        }
        // Main method - compute ROP from changes into block height in time, using a rig state (rotary drilling, slide drilling, or
        // oscillate slide drilling) to determine if the bit depth needs to be calculated.  Currently this uses a temporary single state
        // (enumeration = 2, which should be drilling)
        public Data ComputeBitDepth(Data Data)
        {
            // Find the Rig State data column
            DataValues blockHeight = utility.FindDataColumn( Data, "Block_Height");
            DataValues rigStates = utility.FindDataColumn(Data, "Rig_State");

            // Create output 
            DataValues bitDepth = new DataValues();
            bitDepth.Name = "Bit_Depth";
            bitDepth.Units = blockHeight.Units;
            bitDepth.Raw = false;
            double oldBitDepth = 0;
            double oldBlockHeight = 0;

            // Create data array storage for output
            bitDepth.DataColumn = new List<DataValue>();

            /// do the algorithm
            for (int i = 0; i < blockHeight.DataColumn.Count; i++)
            {
                // Get calculation values
                DateTime t = Convert.ToDateTime(blockHeight.DataColumn[i].Timestamp);
                double val = Convert.ToDouble(blockHeight.DataColumn[i].Value);
                string rigState = RigStateBitDepth[Convert.ToInt32(rigStates.DataColumn[i].Value)];
                double bd = 0;

                if (i == 0)
                {
                    // Trap first time through algorithm - need at least two values to compute ROP
                    bd = 0;
                    oldBitDepth = 0;
                    oldBlockHeight = val;
                }
                else if (val == -999.25)
                {
                    // Trap schlumberger null value
                    bd = val;
                }
                else
                {
                    // Compute ROP
                    if (rigState == "Drilling" || rigState == "Reaming" || rigState == "TripIn" || rigState == "TripOut")
                    {
                        bd = oldBitDepth + (oldBlockHeight - val);
                        oldBitDepth = bd;
                    }
                    else
                    {
                        bd = oldBitDepth;
                    }
                    oldBlockHeight = val;
                }

                /// Put you output back into Data
                bitDepth.DataColumn.Add(new DataValue(t, bd.ToString()));
            }
            Data.DataList.Add(bitDepth);
            return (Data);
        }
        // Main method - compute dummy stub.  
        public Data ComputeDummy(Data Data)
        {
            /// Get your needed input data here

                // Example - get rig state and blovk height
                DataValues rigStates = util.FindDataColumn(Data, "Rig_State");
                DataValues blockHeights = util.FindDataColumn(Data, "Block_Height");

            // Define you data output channels here
                // Create an output data column to store results back into Data
                DataValues Output = new DataValues();
                Output.Name = "Your output data column name";
                Output.Units = "Your output data units";

                // Create data array storage for output
                Output.DataColumn = new List<DataValue>();


            // Put you calculation logic here

                // Example do dummy calculation - remember to cast values to the proper type (string, double, int, ....)
                double dummy = 0;
                foreach (DataValue dv in blockHeights.DataColumn)
                {
                    DateTime t = Convert.ToDateTime(dv.Timestamp);
                    double val = Convert.ToDouble(dv.Value);

                    dummy = dummy + val;

                    /// Store result back into Data
                    Output.DataColumn.Add(new DataValue(t, dummy.ToString()));
                }

                // or

                for (int i = 0; i < blockHeights.DataColumn.Count; i++)
                {
                    DateTime t = Convert.ToDateTime(blockHeights.DataColumn[i].Timestamp);
                    double val = Convert.ToDouble(blockHeights.DataColumn[i].Value);
                    string rigState = RigStateDummy[Convert.ToInt32(rigStates.DataColumn[i].Value)];

                    if (rigState == "Drilling")
                    {
                        dummy = dummy + val;
                    }
                    else
                    {
                        dummy = dummy - val;
                    }

                    /// Put you output back into Data
                    Output.DataColumn.Add(new DataValue(t, dummy.ToString()));
                }

            // Return the updated Data to the master routines
            Data.DataList.Add(Output);
            return (Data);
        }
 public void SetPlot(DataValues dv)
 {
     /// Ah, the fun begins - lets play with the Microsoft chart options -- Added in case of thread collisons
     if (plotChart.InvokeRequired)
     {
         SetPlotCallback d = new SetPlotCallback(SetPlot);
         this.Invoke(d, new object[] { dv });
     }
     else
     {
         MakePlot(dv);
     }
 }
Exemple #6
0
        // These methods interact with Data to return information about data traces or columns
        // These are effectively the memory management for Data

        // This method returns an data column (header and values) based on the input column name
        public DataValues FindDataColumn(Data Data, string name)
        {
            DataValues Column = null;

            // For each data column find a match of the of column name and requested column name
            // if there is a match, break out of the search and return the data column
            foreach (DataValues dv in Data.DataList)
            {
                if (dv.Name.ToLower() == name.ToLower())
                {
                    Column = dv;
                    break;
                }
            }
            return(Column);
        }
        private void PlotButtonClick(object sender, MouseEventArgs e)
        {
            // This is the callback for a pushed button.  Using MouseButtonClick to indentify left click (add trace to main plot) and right click
            // (spawn stand-alone plot of trace).
            MouseEventArgs me  = (MouseEventArgs)e;
            Button         btn = (Button)sender;

            // Left click - add to main plot
            if (me.Button == MouseButtons.Left)
            {
                if (btn.Name == btn.Text)
                {
                    btn.Text = btn.Text + ".";
                    DataValues dv    = util.FindDataColumn(Data, btn.Name);
                    int        Index = util.FindDataColumnIndex(Data, btn.Name);
                    btn.BackColor = Color.FromName(PlotColor[Index % 10]);
                    SetPlot(dv);
                }
                else
                {
                    btn.Text      = btn.Name;
                    btn.BackColor = SystemColors.Control;
                    foreach (Series s in plotChart.Series)
                    {
                        if (s.Name == btn.Name)
                        {
                            plotChart.Series.Remove(s);
                            break;
                        }
                    }
                }
            }
            else
            {
                /// Right click - spawn plot
                SpawnPlot(btn);
            }
        }
        public void MakePlot(DataValues dv)
        {
            /// Build main graph

            /// Create series (data) to be input as data to plot and add series to the plot
            Series series = new Series(dv.Name);

            plotChart.Series.Add(series);

            /// Set line properies - type, color, width
            /// Use color table mod 10 to repeat color table
            plotChart.Series[dv.Name].ChartType   = SeriesChartType.FastLine;
            plotChart.Series[dv.Name].BorderWidth = 2;
            int index = util.FindDataColumnIndex(Data, dv.Name);

            plotChart.Series[dv.Name].Color = Color.FromName(PlotColor[index % 10]);

            /// Convert DateTime stamp to seconds
            ///
            /// Get timestamp of first data sample and use as Time zero - the value to be subtracted from each timestamp
            DateTime origin = dv.DataColumn[0].Timestamp;
            double   od     = Convert.ToDouble(origin.Ticks / 10000000);

            /// For each value - change the string value to a double and timestamp to seconds
            for (int i = 0; i < dv.DataColumn.Count; i++)
            {
                double val = Convert.ToDouble(Convert.ToDateTime(dv.DataColumn[i].Timestamp).Ticks / 10000000) - od;
                double rc  = Convert.ToDouble(dv.DataColumn[i].Value);

                /// Add data to plot series - skip if -999.25 Schlumberger null
                if (rc != -999.25)
                {
                    plotChart.Series[dv.Name].Points.AddXY(val, rc);
                }
            }
        }
Exemple #9
0
        // Main method - compute bit depth from changes into block height in time, using a rig state (rotary drilling, slide drilling, or
        // oscillate slide drilling) to determine if the ROP needs to be calculated.  Currently this uses a temporary single state
        // (enumeration = 2, which should be drilling)
        public Data ComputeRop(Data Data)
        {
            // Find the Rig State data column
            DataValues rigStates = util.FindDataColumn(Data, "Rig_State");

            // If we have rig state proceed
            if (rigStates != null)
            {
                // Find the block height column, if it exists proceed
                DataValues blockHeights = util.FindDataColumn(Data, "Block_Height");
                if (blockHeights != null)
                {
                    // Computation algorithm
                    // If the rig state is "2" then compute ROP from the current and previous block heights and timestamps
                    // We keep the previous block height and timestamp in startXXX variables and the current sample in endXXX

                    // Create output space
                    double outRop = 0;

                    // load the first values of block height and its' timestamp into the startXXX varaible for initialization
                    double   startBlockHeight = Convert.ToDouble(blockHeights.DataColumn[0].Value);
                    DateTime startTime        = blockHeights.DataColumn[0].Timestamp;

                    //

                    // Create an output data column to store results back into Data
                    DataValues DataValues = new DataValues();
                    DataValues.Name       = "Computed_ROP Approach 1";
                    DataValues.Units      = "ft/hr";
                    DataValues.DataColumn = new List <DataValue>();
                    DataValues.DataColumn.Add(new DataValue(startTime, outRop.ToString()));

                    // Main computation Loop
                    // For each data array index, extract the values of rig state, block height, and the timestamp
                    // If the state is Drilling, then use current and previous value of block height and timestamp to compute ROP
                    for (int i = 1; i < rigStates.DataColumn.Count; i++)
                    {
                        // Extract the values of rig state, block height, and the timestamp
                        string rigState = string.Empty;
                        try
                        {
                            rigState = RigStateROP[Convert.ToInt32(rigStates.DataColumn[i].Value)];
                        }
                        catch
                        {
                            rigState = string.Empty;
                        }
                        double   endBlockHeight = Convert.ToDouble(blockHeights.DataColumn[i].Value);
                        DateTime endTime        = blockHeights.DataColumn[i].Timestamp;

                        // If we are "drilling, compute ROP, else ROP = 0
                        if (rigState == "Drilling")
                        {
                            /// Trap schlumberger null
                            if (endBlockHeight == -999.25)
                            {
                                outRop = 0;
                            }
                            else
                            {
                                // Compute the difference in time in seconds, and convert the number to a double
                                int    diff = (endTime - startTime).Seconds;
                                double div  = Convert.ToDouble(Convert.ToDouble(diff));

                                // Error trap for two samples with the same timestamp, compute ROP
                                if (div != 0)
                                {
                                    outRop = 3600 * (endBlockHeight - startBlockHeight) / div;
                                }
                            }

                            // Trap to catch bad rig state values
                            //if (outRop < 0)
                            //{
                            //    outRop = 0;
                            //}
                        }
                        else
                        {
                            // Wrong rig state for ROP calc
                            outRop = 0;
                        }

                        //Final trap throw out ROP < 0
                        if (outRop < 0)
                        {
                            outRop = 0;
                        }

                        // Take the calculated ROP and append the value to the Data column values
                        DataValues.DataColumn.Add(new DataValue(endTime, outRop.ToString()));
                        startTime        = endTime;
                        startBlockHeight = endBlockHeight;
                    }

                    // Add the newly created ROP column to Data
                    DataValues.Raw = false;
                    if (util.FindIfDataColumnExists(Data, DataValues.Name))
                    {
                        DataValues.Name = util.GenerateVersonedName(Data, DataValues.Name);
                    }
                    Data.DataList.Add(DataValues);
                }
                else
                {
                    /// no block height found
                }
            }
            else
            {
                /// no rig state found
            }

            return(Data);
        }
        private void SpawnPlot(Button btn)
        {
            // make same plot as the master plot, but in a new window.  Must add all the settings that are hidden in the Visual GUI
            Form      spawn  = new Form();
            Panel     p      = new Panel();
            Chart     chart  = new Chart();
            ChartArea ca     = new ChartArea();
            Legend    legend = new Legend();
            Title     title  = new Title();

            /// Set Form values
            spawn.Text   = "SPE DSA-TS DQA Surface Derived Data Calculations - Spawned Plot";
            spawn.Height = 600;
            spawn.Width  = 800;

            /// Set Panel values
            p.Dock = DockStyle.Fill;

            /// Set Chart Area values
            ca.Name          = "chartArea";
            ca.AxisX.Title   = "Elapsed Time in Seconds";
            ca.AxisX.Minimum = 0;

            // Legion values
            legend.Name        = "Data Trace";
            legend.LegendStyle = LegendStyle.Column;
            legend.TableStyle  = LegendTableStyle.Tall;

            // Title values
            title.Text = "Rig Data Display in Seconds";

            // Link chart elements into the main chart
            chart.ChartAreas.Add(ca);
            chart.Legends.Add(legend);
            chart.Titles.Add(title);

            /// Set Chart values
            chart.Dock = DockStyle.Fill;
            System.Windows.Forms.DataVisualization.Charting.Cursor cursorX = null;
            System.Windows.Forms.DataVisualization.Charting.Cursor cursorY = null;
            cursorX                = chart.ChartAreas["chartArea"].CursorX;
            cursorX.Interval       = 1;
            cursorY                = chart.ChartAreas["chartArea"].CursorY;
            cursorX.LineWidth      = 2;
            cursorY.LineWidth      = 2;
            cursorX.LineDashStyle  = ChartDashStyle.DashDot;
            cursorY.LineDashStyle  = ChartDashStyle.DashDot;
            cursorX.LineColor      = Color.Red;
            cursorY.LineColor      = Color.Red;
            cursorX.SelectionColor = Color.Yellow;
            cursorY.SelectionColor = Color.Yellow;

            // Enable end user interactivity
            chart.ChartAreas["chartArea"].CursorX.IsUserEnabled          = true;
            chart.ChartAreas["chartArea"].CursorX.IsUserSelectionEnabled = true;
            chart.ChartAreas["chartArea"].CursorY.IsUserEnabled          = true;
            chart.ChartAreas["chartArea"].CursorY.IsUserSelectionEnabled = true;

            /// Get data to display
            DataValues dv    = util.FindDataColumn(Data, btn.Name);
            int        index = util.FindDataColumnIndex(Data, dv.Name);

            /// Create Series
            Series series = new Series(dv.Name);

            chart.Series.Add(series);
            /// Set line properies - type, color, width
            /// Use color table mod 10 to repeat color table
            chart.Series[dv.Name].ChartType   = SeriesChartType.FastLine;
            chart.Series[dv.Name].BorderWidth = 2;
            chart.Series[dv.Name].Color       = Color.FromName(PlotColor[index % 10]);

            /// Convert DateTime stamp to seconds
            ///
            /// Get timestamp of first data sample and use as Time zero - the value to be subtracted from each timestamp
            DateTime origin = dv.DataColumn[0].Timestamp;
            double   od     = Convert.ToDouble(origin.Ticks / 10000000);

            /// For each value - change the string value to a double and timestamp to seconds
            for (int i = 0; i < dv.DataColumn.Count; i++)
            {
                double val = Convert.ToDouble(Convert.ToDateTime(dv.DataColumn[i].Timestamp).Ticks / 10000000) - od;
                double rc  = Convert.ToDouble(dv.DataColumn[i].Value);

                /// Add data to plot series - skip if -999.25 Schlumberger null
                if (rc != -999.25)
                {
                    chart.Series[dv.Name].Points.AddXY(val, rc);
                }
            }

            p.Controls.Add(chart);
            spawn.Controls.Add(p);
            chart.Show();
            spawn.Show();
        }
        // This region contains the code for reading, writing and manipulating the Data
        #region CSV file IO

        private void ReadInputCSV(string filename)
        {
            // Opens the input CSV data file and stores it in a temporary string, then parses the string into
            // data columns, by first reading the file header, then loads the data into Data the application
            // memory space.  Data contains each trace,  which is data vector, array, or column.  Each
            // sample in a data column consists of a data value, timestamp pair.  Column name and units are
            // stored in the data column header.

            // Read the filename from the DataInputFile textbox, open the file and read it into a string
            string rawData = File.ReadAllText(filename);

            // Remove carriage return issues and break the raw data string into  lines
            rawData = rawData.Replace('\n', '\r');
            string[] lines = rawData.Split(new char[] { '\r' }, StringSplitOptions.RemoveEmptyEntries);

            // Determine the number of rows and columns in the inoput data
            int rows    = lines.Length;
            int columns = lines[0].Split(',').Length;

            // Transfer the string based values into Data, the master app database
            // Create Data root and root stub for the data columns (arrays)
            if (columns > 0)
            {
                Data = new Data();
                List <DataValues> DataValues = new List <DataValues>();
                Data.DataList = DataValues;
            }

            // Read Column Names and allocate space for each column of the data array

            // Assumes that there are two header lines - the first for names , the second for units
            string[] line     = lines[0].Split(',');
            string[] unitLine = lines[1].Split(',');

            // Read the first two lines, then for each column read the data column name and units,
            // then create and link each data column in Data
            for (int i = 0; i < columns; i++)
            {
                DataValues dv = new DataValues();
                dv.Name  = line[i].ToString();
                dv.Units = unitLine[i].ToString();

                dv.DataColumn = new List <DataValue>();
                Data.DataList.Add(dv);
            }

            // Now that the columns names are stored in Data, find the DateTime column
            // We need to find this column as each data value has a timestamp associated with it.
            //
            // A more effiecent way of doing this is to find a data samples index in the Data array,
            // then lookup the index in the timestamp array to find the associated timestamp for the sample.
            // However, we intend to have some form of graphic display, so having a value, timestamp pair
            // will be more efficient for plots and charts
            int tsIndex = util.FindDataColumnIndex(Data, "DateTime");

            // Now read the remaining lines into the data columns
            // Start at the third line in the data file
            for (int i = 2; i < rows; i++)
            {
                line = lines[i].Split(',');

                // For each data row read the input columns and create a data value
                for (int j = 0; j < columns; j++)
                {
                    DataValue dv = new DataValue();
                    dv.Timestamp = Convert.ToDateTime(line[tsIndex].ToString());
                    dv.Value     = line[j].ToString();
                    Data.DataList[j].DataColumn.Add(dv);
                }
            }
        }
        // Main method - compute bit depth from changes into block height in time, using a rig state (rotary drilling, slide drilling, or
        // oscillate slide drilling) to determine if the ROP needs to be calculated.  Currently this uses a temporary single state
        // (enumeration = 2, which should be drilling)
        public Data ComputeRop(Data Data)
        {
            // Find the Rig State data column
            DataValues rigStates = util.FindDataColumn(Data, "Rig_State");

            // If we have rig state proceed
            if (rigStates != null)
            {
                // Find the block height column, if it exists proceed
                DataValues blockHeights = util.FindDataColumn(Data, "Block_Height");
                if (blockHeights != null)
                {
                    // Computation algorithm
                    // If the rig state is "2" then compute ROP from the current and previous block heights and timestamps
                    // We keep the previous block height and timestamp in startXXX variables and the current sample in endXXX 

                    // Create output space
                    double outRop = 0;

                    // load the first values of block height and its' timestamp into the startXXX varaible for initialization
                    double startBlockHeight = Convert.ToDouble(blockHeights.DataColumn[0].Value);
                    DateTime startTime = blockHeights.DataColumn[0].Timestamp;

                    //

                    // Create an output data column to store results back into Data
                    DataValues DataValues = new DataValues();
                    DataValues.Name = "Computed_ROP Approach 1";
                    DataValues.Units = "ft/hr";
                    DataValues.DataColumn = new List<DataValue>();
                    DataValues.DataColumn.Add(new DataValue(startTime, outRop.ToString()));

                    // Main computation Loop
                    // For each data array index, extract the values of rig state, block height, and the timestamp
                    // If the state is Drilling, then use current and previous value of block height and timestamp to compute ROP
                    for (int i = 1; i < rigStates.DataColumn.Count; i++)
                    {
                        // Extract the values of rig state, block height, and the timestamp
                        string rigState = string.Empty;
                        try
                        {
                            rigState = RigStateROP[Convert.ToInt32( rigStates.DataColumn[i].Value)];
                        }
                        catch
                        {
                            rigState = string.Empty;
                        }
                        double endBlockHeight = Convert.ToDouble(blockHeights.DataColumn[i].Value);
                        DateTime endTime = blockHeights.DataColumn[i].Timestamp;

                        // If we are "drilling, compute ROP, else ROP = 0
                        if (rigState == "Drilling")
                        {
                            /// Trap schlumberger null
                            if (endBlockHeight == -999.25)
                            {
                                outRop = 0;
                            }
                            else
                            {
                                // Compute the difference in time in seconds, and convert the number to a double
                                int diff = (endTime - startTime).Seconds;
                                double div = Convert.ToDouble(Convert.ToDouble(diff));

                                // Error trap for two samples with the same timestamp, compute ROP
                                if (div != 0)
                                {
                                    outRop = 3600 * (endBlockHeight - startBlockHeight) / div;
                                }
                            }

                            // Trap to catch bad rig state values
                            //if (outRop < 0)
                            //{
                            //    outRop = 0;
                            //}
                        }
                        else
                        {
                            // Wrong rig state for ROP calc
                            outRop = 0;
                        }

                        //Final trap throw out ROP < 0
                        if (outRop < 0)
                        {
                            outRop = 0;
                        }

                        // Take the calculated ROP and append the value to the Data column values
                        DataValues.DataColumn.Add(new DataValue(endTime, outRop.ToString()));
                        startTime = endTime;
                        startBlockHeight = endBlockHeight;
                    }

                    // Add the newly created ROP column to Data
                    DataValues.Raw = false;
                    if (util.FindIfDataColumnExists(Data, DataValues.Name))
                    {
                        DataValues.Name = util.GenerateVersonedName(Data, DataValues.Name);
                    }
                    Data.DataList.Add(DataValues);
                }
                else
                {
                    /// no block height found
                }
            }
            else
            {
                /// no rig state found
            }

            return (Data);
        }
        public void MakePlot(DataValues dv)
        {
            /// Build main graph

            /// Create series (data) to be input as data to plot and add series to the plot
            Series series = new Series(dv.Name);
            plotChart.Series.Add(series);

            /// Set line properies - type, color, width
            /// Use color table mod 10 to repeat color table
            plotChart.Series[dv.Name].ChartType = SeriesChartType.FastLine;
            plotChart.Series[dv.Name].BorderWidth = 2;
            int index = util.FindDataColumnIndex(Data, dv.Name);
            plotChart.Series[dv.Name].Color = Color.FromName(PlotColor[index%10]);

            /// Convert DateTime stamp to seconds
            /// 
            /// Get timestamp of first data sample and use as Time zero - the value to be subtracted from each timestamp
            DateTime origin = dv.DataColumn[0].Timestamp;
            double od = Convert.ToDouble(origin.Ticks/10000000);

            /// For each value - change the string value to a double and timestamp to seconds
            for (int i = 0; i <  dv.DataColumn.Count; i++)
            {
                double val = Convert.ToDouble(Convert.ToDateTime(dv.DataColumn[i].Timestamp).Ticks/10000000) - od;
                double rc = Convert.ToDouble(dv.DataColumn[i].Value);

                /// Add data to plot series - skip if -999.25 Schlumberger null
                if (rc != -999.25)
                {
                    plotChart.Series[dv.Name].Points.AddXY(val, rc);
                }
            }
        }
 public void SetPlot(DataValues dv )
 {
     /// Ah, the fun begins - lets play with the Microsoft chart options -- Added in case of thread collisons
     if (plotChart.InvokeRequired)
     {
         SetPlotCallback d = new SetPlotCallback(SetPlot);
         this.Invoke(d, new object[] { dv });
     }
     else
     {
         MakePlot(dv);
     }
 }
        // This region contains the code for reading, writing and manipulating the Data
        #region CSV file IO

        private void ReadInputCSV(string filename)
        {
            // Opens the input CSV data file and stores it in a temporary string, then parses the string into
            // data columns, by first reading the file header, then loads the data into Data the application
            // memory space.  Data contains each trace,  which is data vector, array, or column.  Each
            // sample in a data column consists of a data value, timestamp pair.  Column name and units are
            // stored in the data column header.

            // Read the filename from the DataInputFile textbox, open the file and read it into a string
            string rawData = File.ReadAllText(filename);

            // Remove carriage return issues and break the raw data string into  lines
            rawData = rawData.Replace('\n', '\r');
            string[] lines = rawData.Split(new char[] { '\r' }, StringSplitOptions.RemoveEmptyEntries);

            // Determine the number of rows and columns in the inoput data
            int rows = lines.Length;
            int columns = lines[0].Split(',').Length;

            // Transfer the string based values into Data, the master app database
            // Create Data root and root stub for the data columns (arrays)
            if (columns > 0)
            {
                Data = new Data();
                List<DataValues> DataValues = new List<DataValues>();
                Data.DataList = DataValues;
            }

            // Read Column Names and allocate space for each column of the data array

            // Assumes that there are two header lines - the first for names , the second for units
            string[] line = lines[0].Split(',');
            string[] unitLine = lines[1].Split(',');

            // Read the first two lines, then for each column read the data column name and units, 
            // then create and link each data column in Data 
            for (int i = 0; i < columns; i++)
            {
                DataValues dv = new DataValues();
                dv.Name = line[i].ToString();
                dv.Units = unitLine[i].ToString();

                dv.DataColumn = new List<DataValue>();
                Data.DataList.Add(dv);
            }

            // Now that the columns names are stored in Data, find the DateTime column
            // We need to find this column as each data value has a timestamp associated with it.
            //
            // A more effiecent way of doing this is to find a data samples index in the Data array,
            // then lookup the index in the timestamp array to find the associated timestamp for the sample.
            // However, we intend to have some form of graphic display, so having a value, timestamp pair
            // will be more efficient for plots and charts
            int tsIndex = util.FindDataColumnIndex(Data, "DateTime");
            
            // Now read the remaining lines into the data columns
            // Start at the third line in the data file
            for (int i = 2; i < rows; i++)
            {
                line = lines[i].Split(',');

                // For each data row read the input columns and create a data value
                for (int j = 0; j < columns; j++)
                {
                    DataValue dv = new DataValue();
                    dv.Timestamp = Convert.ToDateTime(line[tsIndex].ToString());
                    dv.Value = line[j].ToString();
                    Data.DataList[j].DataColumn.Add(dv);
                }
            }
        }