/// <summary> /// This method writes a new record to the database table for a regular time series. /// The method will record extra parameters (other than those that are saved /// as class-level properties of this object) into the database record using the strings /// in the method parameters extraParamNames and extraParamValues. This method does not /// make any changes to the trace table. /// </summary> /// <param name="doWriteToDB">true if the method should actually save the timeseries to the database</param> /// <param name="tsImport">TSImport object into which the method will record values that it has computed. /// If this parameter is null, then the method will skip the recording of such paramters to an object.</param> /// <param name="timeStepUnit">TSDateCalculator.TimeStepUnitCode value for Minute,Hour,Day,Week,Month, or Year</param> /// <param name="timeStepQuantity">The number of the given unit that defines the time step. /// For instance, if the time step is 6 hours long, then this value is 6.</param> /// <param name="timeStepCount">The number of time steps in the time series</param> /// <param name="outStartDate">date of the first time step in the series</param> /// <param name="extraParamNames">A list of field names that the the method should fill, in addition /// to the fields that the TimeSeriesLibrary is designed to maintain. Every item in this list must /// be matched to an item in extraParamValues.</param> /// <param name="extraParamValues">A list of field values that the the method should fill, in addition /// to the fields that the TimeSeriesLibrary is designed to maintain. Every item in this list must /// be matched to an item in extraParamNames.</param> /// <returns>the primary key Id value of the new record that was created</returns> public unsafe int WriteParametersRegular( bool doWriteToDB, TSImport tsImport, short timeStepUnit, short timeStepQuantity, int timeStepCount, DateTime outStartDate, String extraParamNames, String extraParamValues) { ErrorCheckWriteValues(doWriteToDB, tsImport); // The method's parameters are used to compute the meta-parameters of this time series TSParameters.SetParametersRegular( (TSDateCalculator.TimeStepUnitCode)timeStepUnit, timeStepQuantity, timeStepCount, outStartDate, // new time series are always compressed by the current compression technique TSBlobCoder.currentCompressionCode); IsInitialized = true; // Compute the Checksum for this time series ensemble. Because this is a newly // written series, there are not yet any traces to incorporate into the checksum // (presumably those will be added later). Checksum = TSBlobCoder.ComputeChecksum(TSParameters, new List <ITimeSeriesTrace>()); // WriteParameters method will handle all of the database interaction if (doWriteToDB) { WriteParameters(extraParamNames, extraParamValues); } return(Id); }
/// <summary> /// Method reads the irregular time series matching the given ID and trace number, storing the dates and /// values into the given array of TSDateValueStruct (a struct containing the date/value pair). /// The method starts populating the array at the given start date, filling in no more than /// the number of values, that are requested, and not reading past the given end date /// </summary> /// <param name="id">ID id of the time series</param> /// <param name="traceNumber">number of the trace to read</param> /// <param name="nReqValues">number of values requested to read</param> /// <param name="dateValueArray">array requrested to fill with date/value pairs</param> /// <param name="reqStartDate">start date requested</param> /// <param name="reqEndDate">end date requested</param> /// <returns>The number of values actually filled into the array</returns> public unsafe int ReadValuesIrregular(int id, int traceNumber, int nReqValues, TSDateValueStruct[] dateValueArray, DateTime reqStartDate, DateTime reqEndDate) { // Initialize class fields other than the BLOB of data values if (!IsInitialized) { Initialize(id); } // This method can only process irregular-time-step series if (TimeStepUnit != TSDateCalculator.TimeStepUnitCode.Irregular) { throw new TSLibraryException(ErrCode.Enum.Record_Not_Irregular, String.Format("The method can only process irregular time series, but" + "the record with Id {0} is regular.", id)); } // If the end date requested by the caller is such that the stored time series // does not overlap, then we don't need to go any further. if (reqEndDate < BlobStartDate) { return(0); } // byte array (the BLOB) that will be read from the database. Byte[] blobData = null; // method ReadValues reads data from the database into the byte array int timeStepCount = ReadValues(id, traceNumber, ref blobData); // convert the byte array into date/value pairs return(TSBlobCoder.ConvertBlobToArrayIrregular(timeStepCount, true, nReqValues, reqStartDate, reqEndDate, blobData, dateValueArray, CompressionCode)); }
/// <summary> /// This method computes a Checksum for the timeseries. The input to the hash includes /// the list of parameters of the time series, and the list of checksums for each of the traces /// in the time series ensemble. The list of the traces' checksums are passed to this method /// within a list of ITimeSeriesTrace objects. This method does not modify the object given /// in the traceList parameter or assign any property values to any of its items. /// </summary> /// <param name="timeStepUnit">TSDateCalculator.TimeStepUnitCode value for Minute, Hour, Day, /// Week, Month, Year, or Irregular</param> /// <param name="timeStepQuantity">The number of the given unit that defines the time step. /// For instance, if the time step is 6 hours long, then this value is 6.</param> /// <param name="blobStartDate">Date of the first time step in the BLOB</param> /// <param name="traceList">a list of trace object whose checksums have already been computed.</param> /// <returns>the Checksum as a byte[16] array</returns> public byte[] ComputeChecksum( TSDateCalculator.TimeStepUnitCode timeStepUnit, short timeStepQuantity, DateTime blobStartDate, List <ITimeSeriesTrace> traceList) { return(TSBlobCoder.ComputeChecksum(timeStepUnit, timeStepQuantity, blobStartDate, traceList)); }
/// <summary> /// This method converts a List of TimeSeriesValue objects into a BLOB (byte array) of /// time series values and computes a checksum from the BLOB. This method assigns the new values /// of the ValueBlob, Checksum, EndDate, and TimeStepCount to the object given in the traceObject /// parameter. The TraceNumber property of the traceObject parameter must be set before calling /// this method. /// /// The entire List is converted into the BLOB--i.e., the method does not take any /// parameters for limiting the size of the List that is created. This method will /// throw exceptions if the meta-parameters that are passed in are not consistent /// with the List of TimeSeriesValue objects. /// </summary> /// <param name="timeStepUnit">TSDateCalculator.TimeStepUnitCode value for /// Minute, Hour, Day, Week, Month, Year, or Irregular</param> /// <param name="timeStepQuantity">The number of the given unit that defines the time step. /// For instance, if the time step is 6 hours long, then this value is 6.</param> /// <param name="timeStepCount">The number of time steps stored in the BLOB</param> /// <param name="blobStartDate">Date of the first time step in the BLOB</param> /// <param name="blobEndDate">Date of the last time step in the BLOB</param> /// <param name="dateValueList">A List of TimeSeriesValue objects that will be converted to a BLOB</param> /// <param name="traceObject">an object which contains the a TraceNumber property that is used to /// compute the checksum. The computed BLOB and checksum are both saved to the appropriate properties /// of this object.</param> /// <param name="compressionCode">a generation number that indicates what compression technique to use</param> /// <returns>The BLOB (byte array) of time series values that was created from dateValueList</returns> public byte[] ConvertListToBlobWithChecksum( TSDateCalculator.TimeStepUnitCode timeStepUnit, short timeStepQuantity, int timeStepCount, DateTime blobStartDate, DateTime blobEndDate, List <TimeSeriesValue> dateValueList, ITimeSeriesTrace traceObject, out int compressionCode) { // Error checks if (dateValueList.Count != timeStepCount) { throw new TSLibraryException(ErrCode.Enum.Checksum_Improper_Count); } if (dateValueList[0].Date != blobStartDate) { throw new TSLibraryException(ErrCode.Enum.Checksum_Improper_StartDate); } if (dateValueList.Last().Date != blobEndDate) { throw new TSLibraryException(ErrCode.Enum.Checksum_Improper_EndDate); } // When compressing, we always use the latest compression method compressionCode = TSBlobCoder.currentCompressionCode; // Assign properties to the Trace object if (traceObject.EndDate != blobEndDate) { traceObject.EndDate = blobEndDate; } if (traceObject.TimeStepCount != timeStepCount) { traceObject.TimeStepCount = timeStepCount; } // Convert the List dateValueList into a BLOB. if (timeStepUnit == TSDateCalculator.TimeStepUnitCode.Irregular) { // IRREGULAR TIME SERIES // The method in TSBlobCoder can only process an array of TSDateValueStruct. Therefore // we convert the List of objects to an Array of struct instances. TSDateValueStruct[] dateValueArray = dateValueList.Select(tsv => (TSDateValueStruct)tsv).ToArray(); // Let the method in TSBlobCoder class do all the work TSBlobCoder.ConvertArrayToBlobIrregular(dateValueArray, compressionCode, traceObject); } else { // REGULAR TIME SERIES // The method in TSBlobCoder can only process an array of double values. Therefore // we convert the List of date/value objects to an Array values. double[] valueArray = dateValueList.Select(dv => dv.Value).ToArray(); // Let the method in TSBlobCoder class do all the work TSBlobCoder.ConvertArrayToBlobRegular(valueArray, compressionCode, traceObject); } return(traceObject.ValueBlob); }
/// <summary> /// This method prepares a new record for the trace table for a regular time step series. /// The method converts the given valueArray into the BLOB that is actually stored in /// the table. The method computes the checksum of the trace, and computes a new checksum /// for the parameters table to reflect the fact that a new trace has been added to the ensemble. /// For both the insertion to the trace table and the update to the parameters table, this method /// only stores changes in DataTable objects--nothing is changed in the database. In order for /// the changes to be sent to the database, the method TSConnection.CommitNewTraceWrites must /// be called after WriteTraceRegular has been called for all new traces. /// </summary> /// <param name="id">identifying primary key value of the the parameters table for the record /// that this trace belongs to</param> /// <param name="doWriteToDB">true if the method should actually save the timeseries to the database</param> /// <param name="tsImport">TSImport object into which the method will record values that it has computed. /// If this parameter is null, then the method will skip the recording of such paramters to an object.</param> /// <param name="traceNumber">number of the trace to write</param> /// <param name="valueArray">The array of values to be written to the database</param> public unsafe void WriteTraceRegular(int id, bool doWriteToDB, TSImport tsImport, int traceNumber, double[] valueArray) { // Initialize class fields other than the BLOB of data values if (!IsInitialized) { Initialize(id, true); } // This method can only process regular-time-step series if (TimeStepUnit == TSDateCalculator.TimeStepUnitCode.Irregular) { throw new TSLibraryException(ErrCode.Enum.Record_Not_Regular, String.Format("The method can only process regular time series, but" + "the record with Id {0} is irregular.", id)); } // Create a trace object int timeStepCount = valueArray.Count(); ITimeSeriesTrace traceObject = new TSTrace { TraceNumber = traceNumber, TimeStepCount = timeStepCount, EndDate = TSDateCalculator.IncrementDate(BlobStartDate, TimeStepUnit, TimeStepQuantity, timeStepCount - 1) }; if (tsImport != null) { tsImport.TraceList.Add(traceObject); } else { TraceList.Add(traceObject); } // Convert the array of double values into a byte array...a BLOB TSBlobCoder.ConvertArrayToBlobRegular(valueArray, CompressionCode, traceObject); // Create a new record for the trace table // (but for now it is only stored in a DataTable object) if (doWriteToDB) { WriteTrace(traceObject); } // Compute a new checksum for the parameters table // (but for now it is only stored in a DataTable object) UpdateParametersChecksum(doWriteToDB, tsImport); }
/// <summary> /// This computes a new value for the Checksum field of the parameters table. It does not save /// this change to the database, but to a DataTable object. It is assumed that method /// TSConnection.CommitNewTraceWrites will be called later in order to send the changes to the /// database. If parameter 'toWriteToDB' is false, then this method can simply save the /// new Checksum value to the object given in the 'tsImport' parameter. /// </summary> /// <param name="toWriteToDB">true if the method should actually /// save the timeseries to the database</param> /// <param name="tsImport">TSImport object into which the method will record values /// that it has computed. If this parameter is null, then the method will skip the recording /// of such paramters to an object.</param> private void UpdateParametersChecksum(Boolean toWriteToDB, TSImport tsImport) { // The collection in variable 'traceObjects' contains one item for each trace for this // time series. The primary purpose of the list is to store the checksum for each trace, // since the checksum of the timeseries is computed from the list of checksums from each // of its traces. List <ITimeSeriesTrace> traceObjects; if (tsImport != null) { traceObjects = tsImport.TraceList; } else { traceObjects = TraceList; } // Compute the new checksum of the ensemble Checksum = TSBlobCoder.ComputeChecksum(TimeStepUnit, TimeStepQuantity, BlobStartDate, traceObjects); if (toWriteToDB) { DataTable dataTable; // Attempt to get the existing DataTable object from the collection that is kept by // the TSConnection object. If this fails, then we'll create a new DataTable. if (TSConnection.BulkCopyDataTables.TryGetValue(ParametersTableName, out dataTable) == false) { // Create the DataTable object and add columns that match the columns // of the database table. dataTable = new DataTable(); dataTable.Columns.Add("Id", typeof(int)); dataTable.Columns.Add("Checksum", typeof(byte[])); // Add the DataTable to a collection that is kept in the TSConnection object. TSConnection.BulkCopyDataTables.Add(ParametersTableName, dataTable); } dataTable.Rows.Add(Id, Checksum); } }
/// <summary> /// This method computes the checksum for an individual trace of a time series, where the time /// series is understood to be an ensemble of one or more traces. The checksum of a trace is /// computed from the trace number and from the BLOB that contains the values for each time /// step of the time series. /// </summary> /// <param name="traceNumber">the number for identifying the trace</param> /// <param name="valueBlob">the BLOB that contains the values for each time step /// of the time series.</param> public byte[] ComputeTraceChecksum(int traceNumber, byte[] valueBlob) { return(TSBlobCoder.ComputeTraceChecksum(traceNumber, valueBlob)); }
/// <summary> /// This private method creates a List of TimeSeriesValue objects from the given BLOB (byte array) /// of time series values. The method takes parameters for a maximum number of values, /// an earliest date, and a latest date, so that only a portion of the BLOB might be /// converted to the List. This method is designed to do the operations that are common between /// the public methods ConvertBlobToListLimited() and ConvertBlobToListAll(). /// </summary> /// <param name="timeStepUnit">TSDateCalculator.TimeStepUnitCode value for Minute,Hour,Day,Week,Month, Year, or Irregular</param> /// <param name="timeStepQuantity">The number of the given unit that defines the time step. /// For instance, if the time step is 6 hours long, then this value is 6. If timeStepUnit is /// Irregular, then this value is ignored.</param> /// <param name="timeStepCount">the number of time steps that are stored in the blob</param> /// <param name="blobStartDate">The DateTime value of the first time step in the BLOB. If /// timeStepUnit is Irregular, then this value is ignored.</param> /// <param name="applyLimits">If value is true, then nReqValues, reqStartDate, and reqEndDate will be /// used to limit the portion of the BLOB that is converted to dateValueList. If the value is false, then /// nReqValues, reqStartDate, and reqEndDate will be ignored.</param> /// <param name="nReqValues">The maximum number of time steps that should be added to dateValueList. /// If applyLimits==false, then this value is ignored.</param> /// <param name="reqStartDate">The earliest date that will be added to dateValueList. /// If applyLimits==false, then this value is ignored.</param> /// <param name="reqEndDate">The latest date that will be added to dateValueList. /// If applyLimits==false, then this value is ignored.</param> /// <param name="blobData">The BLOB (byte array) that this method will convert into a List</param> /// <param name="dateValueList">The List of TimeSeriesValues that this method will create from the BLOB.</param> /// <param name="compressionCode">a generation number that indicates what compression technique to use</param> /// <returns>The number of time steps added to dateValueList</returns> private unsafe int ConvertBlobToList( TSDateCalculator.TimeStepUnitCode timeStepUnit, short timeStepQuantity, int timeStepCount, DateTime blobStartDate, Boolean applyLimits, int nReqValues, DateTime reqStartDate, DateTime reqEndDate, Byte[] blobData, ref List <TimeSeriesValue> dateValueList, int compressionCode) { int nValuesRead = 0; if (timeStepUnit == TSDateCalculator.TimeStepUnitCode.Irregular) { // IRREGULAR TIME SERIES // If we're not limiting the output list (i.e., we're returning every time step from // the BLOB), then set the size of the intermediate array to match the size of the BLOB. if (applyLimits == false) { nReqValues = timeStepCount; } // Allocate an array of date/value pairs that TSBlobCoder method will fill TSDateValueStruct[] dateValueArray = new TSDateValueStruct[nReqValues]; // Method in the TSBlobCoder class does the real work nValuesRead = TSBlobCoder.ConvertBlobToArrayIrregular(timeStepCount, applyLimits, nReqValues, reqStartDate, reqEndDate, blobData, dateValueArray, compressionCode); // resize the array so that the List that we make from it will have exactly the right size if (nValuesRead != nReqValues) { Array.Resize <TSDateValueStruct>(ref dateValueArray, nValuesRead); } // Convert the array of date/value pairs into the List that will be used by the caller dateValueList = dateValueArray .Select(tsv => (TimeSeriesValue)tsv).ToList <TimeSeriesValue>(); } else { // REGULAR TIME SERIES // If we're not limiting the output list (i.e., we're returning every time step from // the BLOB), then set the size of the intermediate array to match the size of the BLOB. if (applyLimits == false) { nReqValues = timeStepCount; } // Allocate an array of values that TSBlobCoder method will fill double[] valueArray = new double[nReqValues]; // Method in the TSBlobCoder class does the real work nValuesRead = TSBlobCoder.ConvertBlobToArrayRegular(timeStepUnit, timeStepQuantity, timeStepCount, blobStartDate, applyLimits, nReqValues, reqStartDate, reqEndDate, blobData, valueArray, compressionCode); // Allocate an array to hold the time series' date values DateTime[] dateArray = new DateTime[nValuesRead]; // Fill the array with the date values corresponding to the time steps defined // for this time series in the database. TSDateCalculator.FillDateArray(timeStepUnit, timeStepQuantity, nValuesRead, dateArray, reqStartDate); // Allocate a List of date/value pairs that will be used by the caller dateValueList = new List <TimeSeriesValue>(nValuesRead); // Loop through all values, building the List of date/value pairs out of the // primitive array of dates and primitive array of values. int i; for (i = 0; i < nValuesRead; i++) { dateValueList.Add(new TimeSeriesValue { Date = dateArray[i], Value = valueArray[i] }); } nValuesRead = i; } return(nValuesRead); }