public double GetDataSimple(GekkoTime_1_2 t) { //for Normal or Timeless series, not Light //if out of bounds, a NaN is returned, no error is issued //this is fine if it is not an expression, for instance if it is taken directly from a databank return(GetData(t)); }
public int FromGekkoTimeToArrayIndex(GekkoTime_1_2 gt) { // ---------------------------------------------------------------------------- // OFFSET SAFE: dataOffsetLag is handled in GetAnchorPeriodPositionInArray() // ---------------------------------------------------------------------------- return(FromGekkoTimeToArrayIndexAbstract(gt, this.data.anchorPeriod, this.GetAnchorPeriodPositionInArray())); }
// ----------------------------------------------------------------------------- // ----------------- private methods ------------------------------------------- // ----------------------------------------------------------------------------- //Not intended for outside use public int GetArrayIndex(GekkoTime_1_2 gt) { // ---------------------------------------------------------------------------- // OFFSET SAFE: dataOffsetLag is handled in GetAnchorPeriodPositionInArray() // ---------------------------------------------------------------------------- int rv = FromGekkoTimeToArrayIndexAbstract(gt, new GekkoTime_1_2(this.freq, this.data.anchorPeriod.super, this.data.anchorPeriod.sub), this.GetAnchorPeriodPositionInArray()); return(rv); }
/// <summary> /// Gets the timeseries value corresponding to the given period. /// </summary> /// <param name="t">The period.</param> /// <returns>The value (double.NaN if missing)</returns> /// <exception cref="GekkoException">Exception if frequency of timeseries and period do not match.</exception> //smpl so that tooSmall/tooLarge error can be raised (set to null if irrelevant) //set smpl = null if tooSmall/tooLarge is irrelevant (no light series used) public double GetData(GekkoTime_1_2 t) { // ---------------------------------------------------------------------------- // OFFSET SAFE: dataOffsetLag is handled in GetArrayIndex() which is safe // ---------------------------------------------------------------------------- //Instead of GetData(null, t), please use GetDataNonLight(t) double rv = double.NaN; if (this.freq != t.freq) { FreqError(t); } if (this.data.GetDataArray_ONLY_INTERNAL_USE() == null) { //If no data has been added to the timeseries, NaN will always be returned. if (this.type == ESeriesType.ArraySuper) { G.Writeln2("*** ERROR: The variable '" + this.name + "' is an array-timeseries,"); G.Writeln(" but is used as a normal timeseries here (without []-indexer)", Color.Red); Program.ArrayTimeseriesTip(this.name); throw new GekkoException(); } else { goto End; } } if (this.type == ESeriesType.Timeless) { rv = this.data.GetDataArray_ONLY_INTERNAL_USE()[0]; goto End; } else { int index = GetArrayIndex(t); int tooSmall = 0; int tooLarge = 0; this.TooSmallOrTooLarge(index, out tooSmall, out tooLarge); if (tooSmall > 0 || tooLarge > 0) { goto End; //out of bounds, we return a missing value (NaN) } else { rv = this.data.GetDataArray_ONLY_INTERNAL_USE()[index]; goto End; } } End: //if (MissingZero(this)) //{ // if (G.isNumericalError(rv)) rv = 0d; //} return(rv); }
private int ResizeDataArray(GekkoTime_1_2 gt, bool adjustStartEndDates) { // ---------------------------------------------------------------------------- // OFFSET SAFE: dataOffsetLag is handled in GetArrayIndex() which is safe // ---------------------------------------------------------------------------- int index = GetArrayIndex(gt); while (index < 0 || index >= this.data.GetDataArray_ONLY_INTERNAL_USE().Length) { //Resize data array //Keeps on going until the array is large enough. double n = Math.Max(this.data.GetDataArray_ONLY_INTERNAL_USE().Length, 4); //the length could be 1 (or maybe even 0), so we translate 0, 1, 2, 3 into 4 which will become 6 with 1.5 times expandRate. double[] newDataArray = new double[(int)(n * Globals.defaultExpandRateForDataArrays)]; InitializeDataArray(newDataArray); if (index >= this.data.GetDataArray_ONLY_INTERNAL_USE().Length) { //new periods after end System.Array.Copy(this.data.GetDataArray_ONLY_INTERNAL_USE(), newDataArray, this.data.GetDataArray_ONLY_INTERNAL_USE().Length); } else { //new periods added before start int diffSize = newDataArray.Length - this.data.GetDataArray_ONLY_INTERNAL_USE().Length; System.Array.Copy(this.data.GetDataArray_ONLY_INTERNAL_USE(), 0, newDataArray, diffSize, this.data.GetDataArray_ONLY_INTERNAL_USE().Length); this.data.anchorPeriodPositionInArray += diffSize; if (adjustStartEndDates) //only for setting data { if (this.meta != null) { if (this.meta.firstPeriodPositionInArray != Globals.firstPeriodPositionInArrayNull) { this.meta.firstPeriodPositionInArray += diffSize; } if (this.meta.lastPeriodPositionInArray != Globals.lastPeriodPositionInArrayNull) { this.meta.lastPeriodPositionInArray += diffSize; } } } } //this.data.GetDataArray_ONLY_FOR_INTERNAL_USE() = newDataArray; //this.data.SetDataArray_ONLY_FOR_INTERNAL_USE(newDataArray); this.data.SetDataarray_ONLY_INTERNAL_USE(newDataArray); index = GetArrayIndex(gt); } return(index); }
//NOT for outside use, note that it is not safe regarding .dataOffsetLag! private static int FromGekkoTimeToArrayIndexAbstract(GekkoTime_1_2 gt, GekkoTime_1_2 anchorPeriod, int anchorPeriodPositionInArray) { // ---------------------------------------------------------------------------- // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!! NOTE: OFFSET UNSAFE !!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // ---------------------------------------------------------------------------- //Static method not relying on the Series object //NO .dataOffsetLag here, must be added afterwards if (gt.freq != anchorPeriod.freq) { G.Writeln2("*** ERROR: Frequency mismatch"); throw new GekkoException(); } //this.anchorPeriod.sub is always 1 at the moment, and will always be 1 for Annual. //but we cannot count on anchorSubPeriod being 1 forever (for instance for daily obs) int rv = -12345; if (anchorPeriod.freq == EFreq_1_2.A) { //Special treatment in order to make it fast. //undated freq could return fast in the same way as this?? rv = anchorPeriodPositionInArray + gt.super - anchorPeriod.super; } else { //Non-annual int subPeriods = 1; if (anchorPeriod.freq == EFreq_1_2.Q) { subPeriods = 4; } else if (anchorPeriod.freq == EFreq_1_2.M) { subPeriods = 12; } else if (anchorPeriod.freq == EFreq_1_2.U) { subPeriods = 1; } //For quarterly data for instance, each super period amounts to 4 observations. Therefore the multiplication. int dif = subPeriods * (gt.super - anchorPeriod.super) + (gt.sub - anchorPeriod.sub); int index = anchorPeriodPositionInArray + dif; rv = index; } return(rv); }
/// <summary> /// Gets the period (GekkoTime) corresponding to a particular index in the data array. /// </summary> /// <param name="indexInDataArray">The index in the data array.</param> /// <returns>The period (GekkoTime).</returns> public GekkoTime_1_2 GetPeriod(int indexInDataArray) { // ---------------------------------------------------------------------------- // OFFSET SAFE: dataOffsetLag is handled in GetAnchorPeriodPositionInArray() // ---------------------------------------------------------------------------- if (this.type == ESeriesType.Timeless) { G.Writeln2("*** ERROR: Timeless variable error #7"); throw new GekkoException(); } //The inverse method is GetArrayIndex() //Should maybe be private method? But then how to unit-test? //see also AddToPeriod() //DimensionCheck(); int subPeriods = 1; if (this.freq == EFreq_1_2.Q) { subPeriods = 4; } else if (this.freq == EFreq_1_2.M) { subPeriods = 12; } else if (this.freq == EFreq_1_2.U) { subPeriods = 1; } //Calculates the period by means of using the anchor. Uses integer division, so there is an //implicit modulo calculation here. int sub1 = this.data.anchorPeriod.sub + (indexInDataArray - this.GetAnchorPeriodPositionInArray()); int addPer = (sub1 - 1) / subPeriods; int addSub = (indexInDataArray - this.GetAnchorPeriodPositionInArray()) - subPeriods * addPer; int resultSuperPer = this.data.anchorPeriod.super + addPer; int resultSubPer = this.data.anchorPeriod.sub + addSub; //This code below fixes a bug (1.4 suffers from it: only affects non-annual timeseries), bug fixed in 1.5.8 if (resultSubPer < 1) //this may happen, probaby because of "/" on integer not behaving as expected { resultSuperPer -= 1; resultSubPer += subPeriods; } GekkoTime_1_2 t = new GekkoTime_1_2(this.freq, resultSuperPer, resultSubPer); return(t); }
private void InitDataArray(GekkoTime_1_2 t) { if (this.type == ESeriesType.Timeless) { G.Writeln2("*** ERROR: Timeless error #10"); throw new GekkoException(); } else { //The anchor is set in the middle of the array, and the anchor date is set to gt. this.data.SetDataarray_ONLY_INTERNAL_USE(new double[Globals.defaultPeriodsWhenCreatingTimeSeries]); this.data.anchorPeriodPositionInArray = Globals.defaultPeriodsWhenCreatingTimeSeries / 2; //possible to simulate 100 years forwards, and have data 100 years back. InitializeDataArray(this.data.GetDataArray_ONLY_INTERNAL_USE()); //may fill it with NaN's //the following two will always be fixed to what they //were for the very first observation entering the double[] array (unless the array is resized). this.data.anchorPeriod = t; } }
private int ResizeDataArray(GekkoTime_1_2 gt) { return(ResizeDataArray(gt, true)); }
private void FreqError(GekkoTime_1_2 t) { G.Writeln2("*** ERROR: Frequency mismatch: " + (this.freq.ToString()) + " versus " + (t.freq.ToString())); throw new GekkoException(); }