// 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); }
// This method checks for the existence of a column in Data. It is used primarily in checking/versioning the trace name, as multiple traces with the same name // will cause identity issues betwee traces of the same name public bool FindIfDataColumnExists(Data Data, string name) { bool retVal = false; foreach (DataValues dv in Data.DataList) { if (dv.Name.ToLower() == name.ToLower()) { retVal = true; break; } } return (retVal); }
// 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); }
// This method find the integer index associated with a requested column name public int FindDataColumnIndex(Data Data, string name) { // index counter to be output int i = 0; // Loop through the columns in Data, and if there is a match of column name and reqwuested column name, // then return the index of the column array. This is quite useful for locating the DateTime column. // It also eliminates a fixed position for the DateTime column in the input file foreach (DataValues dv in Data.DataList) { if (dv.Name.ToLower() == name.ToLower()) { break; } i++; } return (i); }
// 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); }
// This method checks to see if a trace of the same name already exisits in Data (case: when the same caluculation is run twice, the output will already // exist in Data, so we change the name so that the traces are distinguishable. public string GenerateVersonedName(Data Data, string name) { string retVal = string.Empty; string newName = string.Empty; int i = 1; bool tryAgain = true; while(tryAgain) { newName = name + " version " + i.ToString(); tryAgain = FindIfDataColumnExists(Data, newName); i++; } retVal = newName; return (retVal); }
// 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); } } }
private void ComputeBitDepthClick(object sender, EventArgs e) { // Bit Depth Approach 1 calculation try { ComputeBitDepthClass calc = new ComputeBitDepthClass(); Data = calc.ComputeBitDepth(Data); AddButtons("calculated"); } catch { } }