public void ConvertToStruct2() { TSDateValueStruct tsdvs = new TSDateValueStruct { Date = date2, Value = val2 }; TimeSeriesValue tsv = new TimeSeriesValue { Date = date2, Value = val2 }; TSDateValueStruct actual = ((TSDateValueStruct)(tsv)); Assert.AreEqual(tsdvs, actual); }
public void ConvertFromStruct2() { TSDateValueStruct tsdvs = new TSDateValueStruct { Date = date2, Value = val2 }; TimeSeriesValue tsv = new TimeSeriesValue { Date = date2, Value = val2 }; TimeSeriesValue actual = ((TimeSeriesValue)(tsdvs)); Assert.IsTrue(tsv.ValueEquals(actual)); }
public void WriteTraceIrregular() { DateTime startDate = DateTime.Parse("2/10/2000"); DateTime endDate = DateTime.Parse("2/10/2002"); int timeStepCount = 40; int id, traceNumber = 27; String extraParamNames = "TimeSeriesType, Unit_Id, RunGUID, VariableType, VariableName, RunElementGUID"; String extraParamValues = "0, 1, 'A0101010-AAAA-BBBB-2222-3E3E3E3E3E3E', 0, 'eraseme', '00000000-0000-0000-0000-000000000000'"; id = _lib.WriteParametersIrregular(_connxNumber, GetSbyte(_paramTableName), GetSbyte(_traceTableName), timeStepCount, startDate, endDate, GetSbyte(extraParamNames), GetSbyte(extraParamValues)); TSDateValueStruct[] dateValArray = new TSDateValueStruct[timeStepCount], testDateValArray = new TSDateValueStruct[timeStepCount]; double x = 10.0; double y = 1.0; DateTime curDate = startDate; for (int i = 0; i < timeStepCount; i++) { dateValArray[i].Value = x; dateValArray[i].Date = curDate; x *= 1.2; y += 0.5; curDate = curDate.AddDays(y); } // The method being tested _lib.WriteTraceIrregular(_connxNumber, GetSbyte(_paramTableName), GetSbyte(_traceTableName), id, traceNumber, dateValArray); String comm = String.Format("select * from {0} where TimeSeries_Id={1} and TraceNumber={2}", _traceTableName, id, traceNumber); // SqlDataAdapter object will use the query to fill the DataTable using (SqlDataAdapter adp = new SqlDataAdapter(comm, _connx)) { DataTable dTable = new DataTable(); // Execute the query to fill the DataTable object adp.Fill(dTable); DataRow row = dTable.Rows[0]; byte[] blob = row.Field<byte[]>("ValueBlob"); TSBlobCoder.ConvertBlobToArrayIrregular(timeStepCount, false, 0, startDate, startDate, blob, testDateValArray, TSBlobCoder.currentCompressionCode); // for (int i = 0; i < timeStepCount; i++) Assert.AreEqual(dateValArray[i], testDateValArray[i]); } }
public void ReadDatesValuesRegular() { DateTime startDate = DateTime.Parse("1/10/1996"); DateTime endDate = DateTime.Parse("2/10/2002"); int timeStepCount = 70; TSDateCalculator.TimeStepUnitCode timeStepUnit = TSDateCalculator.TimeStepUnitCode.Hour; short timeStepQuantity = 6; int id, traceNumber = 13; String extraParamNames = "TimeSeriesType, Unit_Id, RunGUID, VariableType, VariableName, RunElementGUID"; String extraParamValues = "0, 1, 'A0101010-AAAA-BBBB-2222-3E3E3E3E3E3E', 0, 'eraseme', '00000000-0000-0000-0000-000000000000'"; id = _lib.WriteParametersRegular(_connxNumber, GetSbyte(_paramTableName), GetSbyte(_traceTableName), (short)timeStepUnit, timeStepQuantity, timeStepCount, startDate, GetSbyte(extraParamNames), GetSbyte(extraParamValues)); double[] valArray = new double[timeStepCount]; TSDateValueStruct[] dateValArray = new TSDateValueStruct[timeStepCount], testDateValArray = new TSDateValueStruct[timeStepCount]; double x = 5.25; DateTime curDate = startDate; for (int i = 0; i < timeStepCount; i++) { valArray[i] = x; dateValArray[i].Value = x; dateValArray[i].Date = curDate; x += 1.75; curDate = TSDateCalculator.IncrementDate(curDate, timeStepUnit, timeStepQuantity, 1); } _lib.WriteTraceRegular(_connxNumber, GetSbyte(_paramTableName), GetSbyte(_traceTableName), id, traceNumber, valArray); // The method being tested _lib.ReadDatesValues(_connxNumber, GetSbyte(_paramTableName), GetSbyte(_traceTableName), id, traceNumber, timeStepCount, ref testDateValArray, startDate, endDate); // for (int i = 0; i < timeStepCount; i++) Assert.AreEqual(dateValArray[i], testDateValArray[i]); }
public void ReadDatesValuesIrregular() { DateTime startDate = DateTime.Parse("8/10/1999"); DateTime endDate = DateTime.Parse("2/10/2002"); int timeStepCount = 40; int id, traceNumber = 4; String extraParamNames = "TimeSeriesType, Unit_Id, RunGUID, VariableType, VariableName, RunElementGUID"; String extraParamValues = "0, 1, 'A0101010-AAAA-BBBB-2222-3E3E3E3E3E3E', 0, 'eraseme', '00000000-0000-0000-0000-000000000000'"; id = _lib.WriteParametersIrregular(_connxNumber, GetSbyte(_paramTableName), GetSbyte(_traceTableName), timeStepCount, startDate, endDate, GetSbyte(extraParamNames), GetSbyte(extraParamValues)); TSDateValueStruct[] dateValArray = new TSDateValueStruct[timeStepCount], testDateValArray = new TSDateValueStruct[timeStepCount]; double x = 10.0; double y = 1.0; DateTime curDate = startDate; for (int i = 0; i < timeStepCount; i++) { dateValArray[i].Value = x; dateValArray[i].Date = curDate; x *= 1.5; y += 0.25; curDate = curDate.AddDays(y); } _lib.WriteTraceIrregular(_connxNumber, GetSbyte(_paramTableName), GetSbyte(_traceTableName), id, traceNumber, dateValArray); // The method being tested _lib.ReadDatesValues(_connxNumber, GetSbyte(_paramTableName), GetSbyte(_traceTableName), id, traceNumber, timeStepCount, ref testDateValArray, startDate, endDate); // for (int i = 0; i < timeStepCount; i++) Assert.AreEqual(dateValArray[i], testDateValArray[i]); }
public void ErrorHandling2() { _lib.ResetErrorHandler(); TSDateValueStruct[] dateValStructArray = new TSDateValueStruct[10]; // This should cause an error _lib.ReadDatesValues(_connxNumber, GetSbyte("TableThatDoesNotExist"), GetSbyte("TableThatWillNeverExist"), 3, -33, 10, ref dateValStructArray, DateTime.Parse("1/10/1996"), DateTime.Parse("1/10/1996")); Assert.IsTrue(_lib.GetHasError(), "GetHasError should have returned True after an error was triggered"); sbyte[] errorMessage = new sbyte[4096]; String errorString; fixed (sbyte* pErrorMessage = &errorMessage[0]) { _lib.GetErrorMessage(pErrorMessage); errorString = new String(pErrorMessage); } Assert.IsTrue(errorString.Length > 0); }
/// <summary> /// This method reads the given XML file and stores each of the timeseries described /// therein to the database. For each timeseries that it stores, it adds an item to /// list 'tsImportList', which records metadata of the timeseries that is not processed /// directly by TimeSeriesLibrary. Therefore, the process that calls TimeSeriesLibrary /// can process tsImportList to complete the importation of the timeseries. /// </summary> /// <param name="xmlFileName">Name of the file that will be read. If xmlText is null, /// then this parameter must be non-null, and vice-versa.</param> /// <param name="xmlText">The text of an XML file that will be read. If xmlFileName is null, /// then this parameter must be non-null, and vice-versa.</param> /// <param name="tsImportList">List of TSImport objects that this function records for /// each series that is imported. This method appends the list.</param> /// <param name="shouldStoreToDatabase">If true, then this method will write the timeseries from /// the XML file to database. If false, then this method does not write to database.</param> /// <param name="shouldRecordDetails">If true, then this method stores the BLOB and detailed /// elements to the list of TSImport objects. If false, then this method does not store /// the BLOB to the TSImport object, and all fields that TimeSeriesLibrary does not process /// are stored to the TSImport object's UnprocessedElements field.</param> /// <returns>The number of time series records that were successfully stored</returns> public int ReadAndStore( String xmlFileName, String xmlText, List <TSImport> tsImportList, Boolean shouldStoreToDatabase, Boolean shouldRecordDetails) { String s; // ephemeral String object int numTs = 0; // The # of time series successfuly processed by this method TSDateCalculator.TimeStepUnitCode TimeStepUnit = TSDateCalculator.TimeStepUnitCode.Day; // to be read from XML short TimeStepQuantity = 1; // to be read from XML DateTime StartDate = _defaultTime; // to be read from XML double[] valueArray = null; // to be read from XML var elementNames = new List <String> { "TimeSeries", "Pattern" }; // Flags will indicate if the XML is missing any data Boolean foundTimeStepUnit, foundTimeStepQuantity, foundStartDate, foundValueArray; // Error checks if (xmlFileName == null && xmlText == null) { throw new TSLibraryException(ErrCode.Enum.Xml_Memory_File_Exclusion, "The method's xmlFileName and xmlText parameters can not both be null."); } if (xmlFileName != null && xmlText != null) { throw new TSLibraryException(ErrCode.Enum.Xml_Memory_File_Exclusion, "The method's xmlFileName and xmlText parameters can not both be non-null."); } if (shouldStoreToDatabase && TSConnection == null) { throw new TSLibraryException(ErrCode.Enum.Xml_Connection_Not_Initialized, "The method is directed to store results to database, " + "but a database connection has not been assigned in the constructor."); } // Initialize a Stream object for the XmlReader object to read from. This method can // be called with either the file name of an XML file, or with a string containing the // complete text of the XML to be parsed. The type of Stream object that we initialize // depends on which parameter the method was called with. Stream xmlStream; if (xmlFileName == null) { xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xmlText)); ReportedFileName = "The given XML text "; } else { xmlStream = new FileStream(xmlFileName, FileMode.Open); ReportedFileName = "The XML file '" + xmlFileName + "' "; } try { // Loop once for "TimeSeries" and once for "Pattern". Note that the approach of looping // through the entire file twice seems undesirable, but no better option was evident because // methods of XmlReader such as 'ReadToNextSibling' do not have an equivalent that could // seek *either* "TimeSeries" or "Pattern". foreach (String elementName in elementNames) { Boolean isPattern = elementName == "Pattern"; // Start at the beginning of the XML file xmlStream.Seek(0, SeekOrigin.Begin); // This XmlReader object opens the XML file and parses it for us. The 'using' // statement ensures that the XmlReader's resources are properly disposed. using (XmlReader xmlReader = XmlReader.Create(xmlStream)) { // All of the data that we'll read is contained inside an element named 'Import' try { if (!xmlReader.ReadToFollowing("Import")) { throw new TSLibraryException(ErrCode.Enum.Xml_File_Empty, ReportedFileName + "does not contain an <Import> element."); } } catch { throw new TSLibraryException(ErrCode.Enum.Xml_File_Empty, ReportedFileName + "does not contain an <Import> element."); } // The file must contain at least one element named 'TimeSeries'. Move to the first // such element now. if (!xmlReader.ReadToDescendant(elementName)) { // if no such element is found then there is nothing to process in this iteration // of the loop. After the loop is finished, an exception is thrown if no elements // were read. continue; } // do-while loop through all elements named 'TimeSeries'. There will be one iteration // of this loop for each timeseries in the XML file. do { // Get a new XmlReader object that can not read outside // of the current 'TimeSeries' element. XmlReader oneSeriesXmlReader = xmlReader.ReadSubtree(); // A new TSImport object will store properties of this time series // that the TimeSeriesLibrary is not designed to handle. TSImport tsImport = new TSImport(shouldRecordDetails) { IsPattern = isPattern }; // Flags will indicate if the XML is missing any data foundTimeStepUnit = foundTimeStepQuantity = foundStartDate = foundValueArray = false; // This default trace number will be used if the "Trace" attribute is not used on a <Data> // element. The default trace value may be reassigned if a <TraceNumber> element is read. int defaultTraceNumber = 1; // Collection of Strings that hold the unparsed DataSeries. The key of the // Dictionary is the trace number of the DataSeries Dictionary <int, String> DataStrings = new Dictionary <int, String>(); // advance the reader past the outer element oneSeriesXmlReader.ReadStartElement(); // Read one timeseries from XML while (oneSeriesXmlReader.Read()) { Boolean binaryEncoded = false; // If the current position of the reader is on an element's start tag (e.g. <Name>) if (oneSeriesXmlReader.NodeType == XmlNodeType.Element) { // Note that XML standard is case sensitive switch (oneSeriesXmlReader.Name) { case "Name": // <Name> is not processed by TimeSeriesLibrary. Record it on a list // so another module can process the <Name> field. Presumably, // the process will distinguish timeseries based on the <Name> field. tsImport.Name = oneSeriesXmlReader.ReadElementContentAsString(); break; case "StartDate": // TimeSeriesLibrary will store <StartDate> to the data table s = oneSeriesXmlReader.ReadElementContentAsString(); if (!TimeExtensions.TryParse(s, out StartDate, _defaultTime)) { throw new TSLibraryException(ErrCode.Enum.Xml_File_StartDate_Unreadable, ReportedFileName + "contains unreadable StartDate element value " + s); } foundStartDate = true; break; case "TimeStepUnit": // TimeSeriesLibrary will store <TimeStepUnit> to the data table s = oneSeriesXmlReader.ReadElementContentAsString(); TimeStepUnit = ParseTimeStepUnit(s); foundTimeStepUnit = true; // If it is an irregular time series if (TimeStepUnit == TSDateCalculator.TimeStepUnitCode.Irregular) { // <TimeStepQuantity> and <StartDate> are unnecessary // and irrelevant to irregular time series foundTimeStepQuantity = true; foundStartDate = true; } break; case "TimeStepQuantity": // TimeSeriesLibrary will store <TimeStepQuantity> to the data table s = oneSeriesXmlReader.ReadElementContentAsString(); TimeStepQuantity = ParseTimeStepQuantity(s); foundTimeStepQuantity = true; break; case "Data": // <Data> may have a TraceNumber attribute int traceNumber = 0; s = oneSeriesXmlReader.GetAttribute("Trace"); if (int.TryParse(s, out traceNumber) == false) { traceNumber = 0; } if (DataStrings.ContainsKey(traceNumber)) { throw new TSLibraryException(ErrCode.Enum.Xml_File_Inconsistent, ReportedFileName + "contains a time series with more than " + "one trace number " + traceNumber.ToString()); } // <Data> contains a whitespace-deliminted string of values // that comprise the time series s = oneSeriesXmlReader.ReadElementContentAsString(); // add the unparsed string to a dictionary // where the trace number is the dictionary key DataStrings.Add(traceNumber, s); foundValueArray = true; break; case "Encoding": // The default is that <Data> contains decimal text. // However, the <Encoding> element may specify that it is // Base64 encoded. s = oneSeriesXmlReader.ReadElementContentAsString(); if (s == "Base64" || s == "base64") { binaryEncoded = true; } break; case "Apart": // <Apart> contains the A part of record name from a HECDSS file tsImport.SetAPart(oneSeriesXmlReader); break; case "Bpart": // <Bpart> contains the B part of record name from a HECDSS file tsImport.SetBPart(oneSeriesXmlReader); break; case "Cpart": // <Cpart> contains the C part of record name from a HECDSS file tsImport.SetCPart(oneSeriesXmlReader); break; case "Epart": // <Epart> contains the E part of record name from a HECDSS file tsImport.SetEPart(oneSeriesXmlReader); break; case "Units": // <Units> contains the name of the units of measurement for the time series values tsImport.SetUnits(oneSeriesXmlReader); break; case "TimeSeriesType": // <TimeSeriesType> contains the text name of the time series type, // [PER-AVER | PER-CUM | INST-VAL | INST-CUM] tsImport.SetTimeSeriesType(oneSeriesXmlReader); break; case "TraceNumber": // <TraceNumber> contains the trace number for an ensemble defaultTraceNumber = tsImport.GetTraceNumber(oneSeriesXmlReader); break; case "MultiplicationFactor": tsImport.SetMultiplicationFactor(oneSeriesXmlReader); break; default: // Any other tags are simply copied to the String object // 'UnprocessedElements'. Here they are stored with // the enclosing tags (e.g. "<Units>CFS</Units>"). tsImport.AddUnprocessedElement(oneSeriesXmlReader.ReadOuterXml()); break; } } } // This XmlReader object was created with the ReadSubtree() method so that it would only // be able to read the current time series element. We have now reached the end of the // time series element, so the XmlReader should be closed. oneSeriesXmlReader.Close(); // The record can not be saved to the table if information for some of the fields is missing. // These flags indicate whether each of the required fields was found in the XML file. if (!(foundTimeStepUnit && foundTimeStepQuantity && foundStartDate && foundValueArray)) { // One or more required fields were missing, so we'll throw an exception. String errorList, nameString; if (tsImport.Name == "") { nameString = "unnamed time series"; } else { nameString = "time series named '" + tsImport.Name + "'"; } errorList = "Some required subelements were missing from " + nameString + " in " + ReportedFileName + "\n"; if (!foundStartDate) { errorList += "\n<StartDate> was not found"; } if (!foundTimeStepUnit) { errorList += "\n<TimeStepUnit> was not found"; } if (!foundTimeStepQuantity) { errorList += "\n<TimeStepQuantity> was not found"; } if (!foundValueArray) { errorList += "\n<Data> was not found"; } throw new TSLibraryException(ErrCode.Enum.Xml_File_Incomplete, errorList); } // Now that we've established that all fields have been read, we can parse the // string of timeseries values into an array, and save the array to the database. if (TimeStepUnit == TSDateCalculator.TimeStepUnitCode.Irregular) { // IRREGULAR TIME SERIES // The TS object is used to save one record to the database table TS ts = new TS(TSConnection, TableName, TraceTableName); foreach (KeyValuePair <int, String> keyValuePair in DataStrings) { int traceNumber = keyValuePair.Key; if (traceNumber == 0) { traceNumber = defaultTraceNumber; } // Split the big data string into an array of strings. // The date/time/value triplets will be all collated together. String[] stringArray = keyValuePair.Value .Split(new char[] { }, StringSplitOptions.RemoveEmptyEntries); // We'll use this date/value structure to build each item of the date/value array TSDateValueStruct tsv = new TSDateValueStruct(); // allocate the array of date/value pairs TSDateValueStruct[] dateValueArray = new TSDateValueStruct[stringArray.Length / 3]; // Loop through the array of strings, 3 elements at a time for (int i = 2; i < stringArray.Length; i += 3) { s = stringArray[i - 2] + " " + stringArray[i - 1]; tsv.Date = DateTime.Parse(s); tsv.Value = double.Parse(stringArray[i]); dateValueArray[i / 3] = tsv; } if (tsImport.TraceList.Count == 0) { // Ignore whatever was entered in the StartDate element, since it // might conflict with the date/value entries StartDate = dateValueArray[0].Date; // Write parameters to the database and record values in the TSImport object ts.WriteParametersIrregular(shouldStoreToDatabase, tsImport, dateValueArray.Count(), StartDate, dateValueArray.Last().Date, null, null); } else { if (StartDate != ts.BlobStartDate) { throw new TSLibraryException(ErrCode.Enum.Xml_File_Inconsistent, ReportedFileName + "contains a time series " + "with traces that do not overlay each other."); } } ts.WriteTraceIrregular(0, shouldStoreToDatabase, tsImport, traceNumber, dateValueArray); } tsImport.RecordFromTS(ts); // Done with the TS object. ts = null; } else { // REGULAR TIME SERIES // The TS object is used to save one record to the database table TS ts = new TS(TSConnection, TableName, TraceTableName); foreach (KeyValuePair <int, String> keyValuePair in DataStrings) { int traceNumber = keyValuePair.Key; if (traceNumber == 0) { traceNumber = defaultTraceNumber; } // Fancy LINQ statement turns the String object into an array of double[] valueArray = keyValuePair.Value .Split(new char[] { }, StringSplitOptions.RemoveEmptyEntries) .Select(z => double.Parse(z)).ToArray(); if (tsImport.TraceList.Count == 0) { // Write to the database and record values in the TSImport object ts.WriteParametersRegular(shouldStoreToDatabase, tsImport, (short)TimeStepUnit, TimeStepQuantity, valueArray.Count(), StartDate, null, null); } ts.WriteTraceRegular(0, shouldStoreToDatabase, tsImport, traceNumber, valueArray); } tsImport.RecordFromTS(ts); // Done with the TS object. ts = null; } // the TSImport object contains data for this timeseries that TSLibrary does not process. // Add the TSImport object to a list that the calling process can read and use. tsImportList.Add(tsImport); numTs++; } while (xmlReader.ReadToNextSibling(elementName)); } } if (numTs == 0) { throw new TSLibraryException(ErrCode.Enum.Xml_File_Empty, ReportedFileName + " does not contain any " + elementNames.Select(ss => "<" + ss + ">").ToStringWithConjunc("or") + " element".Pluralize(elementNames.Count) + "."); } } catch (XmlException e) { // An XmlException was caught somewhere in the lifetime of the object xmlReader, // so we can presumably say there was an error in how the XML file was formatted. // The information from the XmlException object is included in the error message // that we throw here, and the XmlException is included as an inner exception. throw new TSLibraryException(ErrCode.Enum.Xml_File_Malformed, ReportedFileName + "is malformed.\n\n" + e.Message, e); } finally { // Disposing the Stream object ensures that the file is closed, if applicable. // This is put into the 'finally' clause so that we can ensure that the Stream // is closed no matter how we exit this method. xmlStream.Dispose(); } return(numTs); }
/// <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); }
/// <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; }
public void WriteTraceIrregular( int connectionNumber, sbyte* pParamTableName, sbyte* pTraceTableName, int id, int traceNumber, TSDateValueStruct[] dateValueArray) { try { // Convert from simple character byte array to .Net String object String paramTableName = new String(pParamTableName); String traceTableName = new String(pTraceTableName); // Get the connection that we'll pass along. SqlConnection connx = GetConnectionFromId(connectionNumber); // Construct new TS object with SqlConnection object and table name TS ts = new TS(connx, TSLib.ConnxObject, paramTableName, traceTableName); ts.WriteTraceIrregular(id, true, null, traceNumber, dateValueArray); } catch (Exception e) { ErrorMessage = e.Message; } }
public int ReadDatesValues( int connectionNumber, sbyte *pParamTableName, sbyte *pTraceTableName, int id, int traceNumber, int nReqValues, ref TSDateValueStruct[] dateValueArray, DateTime reqStartDate, DateTime reqEndDate) { try { // Convert from simple character byte array to .Net String object String paramTableName = new String(pParamTableName); String traceTableName = new String(pTraceTableName); // Get the connection that we'll pass along. SqlConnection connx = GetConnectionFromId(connectionNumber); // Construct new TS object with SqlConnection object and table name TS ts = new TS(connx, TSLib.ConnxObject, paramTableName, traceTableName); int nValuesRead = 0; // Read the parameters of the time series so that we'll know if it's regular or irregular if (!ts.IsInitialized) ts.Initialize(id); // The operations will differ for regular and irregular time series if (ts.TimeStepUnit == TSDateCalculator.TimeStepUnitCode.Irregular) { // IRREGULAR TIME SERIES // Read the date/value array from the database nValuesRead = ts.ReadValuesIrregular(id, traceNumber, nReqValues, dateValueArray, reqStartDate, reqEndDate); } else { // REGULAR TIME SERIES // Allocate an array to hold the time series' data values double[] valueArray = new double[nReqValues]; // Read the data values from the database nValuesRead = ts.ReadValuesRegular(id, traceNumber, nReqValues, valueArray, reqStartDate, reqEndDate); // 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. ts.FillDateArray(id, nValuesRead, dateArray, reqStartDate); // Loop through all values, filling the array of date/value pairs from the // primitive array of dates and primitive array of values. int i; for (i = 0; i < nValuesRead; i++) { dateValueArray[i].Date = dateArray[i]; dateValueArray[i].Value = valueArray[i]; // So far we have ignored the requested end date. However, at this // stage we won't make the list any longer than was requested by the caller. if (dateValueArray[i].Date >= reqEndDate) { i++; break; } } nValuesRead = i; } return nValuesRead; } catch (Exception e) { ErrorMessage = e.Message; return 0; } }