public StorageContextMetadataTimeVarianceExtractor(IDataStorageDefinition storageDefinition, double axisPeriod = double.NaN)
        {
            var dict    = storageDefinition.VariablesMetadata;
            var dimDict = storageDefinition.VariablesDimensions;

            string timeDimName = TimeAxisAutodetection.GetTimeDimension(storageDefinition);

            foreach (var variable in dict.Keys)
            {
                //checking for temporal variogram. Storing it if found
                if (timeDimName != null)
                {
                    int idx = Array.IndexOf(dimDict[variable], timeDimName);
                    if (idx >= 0)
                    {
                        var temporalVariogramStorage = new StorageContextVariogramStorage.StorageContextMetadataStorage(storageDefinition, variable, idx.ToString()) as VariogramModule.IVariogramStorage;
                        var materializationResult    = temporalVariogramStorage.Materialize();
                        if (FSharp.Core.FSharpOption <VariogramModule.IVariogram> .get_IsSome(materializationResult))
                        {
                            processes.Add(variable, new GaussianProcessDescription(materializationResult.Value, axisPeriod));
                        }
                    }
                }
            }
        }
        public static AxisDetectionResult SmartDetectAxis(IStorageContext storage)
        {
            IDataStorageDefinition storageDefinition = storage.StorageDefinition;
            string varName = TimeAxisAutodetection.GetTimeVariableName(storageDefinition);

            if (string.IsNullOrEmpty(varName))
            {
                throw new InvalidOperationException("Can't autodetect time axis variable");
            }
            string timeUnits = storageDefinition.VariablesMetadata[varName].Where(pair => pair.Key.ToLowerInvariant() == "units").Select(p => p.Value).FirstOrDefault() as string;

            if (timeUnits == null)
            {
                throw new InvalidOperationException(string.Format("Can't find units metadata entry for the time axis \"{0}\"", varName));
            }

            string trimmed = timeUnits.Trim();

            string[] splitted = trimmed.Split(new char[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
            if (splitted.Length < 4 || splitted[1].ToLowerInvariant() != "since")
            {
                throw new InvalidOperationException("Automatic time axis detection failed to determine time axis semantics. Time axis units must be in format \"days|hours|years since YYYY-MM-DD HH:MM:SS\"");
            }

            DateTime baseTime    = new DateTime();
            string   dateToParse = string.Format("{0} {1}", splitted[2], splitted[3]);

            if (dateToParse.Length > 19)
            {
                dateToParse = dateToParse.Substring(0, 19);
            }

            bool baseTimeParsed = false;

            foreach (var dateFormat in dateFormats)
            {
                baseTimeParsed = DateTime.TryParseExact(dateToParse, dateFormat, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeUniversal, out baseTime);
                if (baseTimeParsed)
                {
                    traceSource.TraceEvent(TraceEventType.Information, 4, string.Format("base datetime \"{0}\" for axis variable \"{1}\" was successfuly parsed as {2}", dateToParse, varName, baseTime.ToString("u")));
                    break;
                }
                else
                {
                    traceSource.TraceEvent(TraceEventType.Information, 4, string.Format("can not parse base datetime \"{0}\" for axis variable \"{1}\" with format {2}", dateToParse, varName, dateFormat));
                }
            }

            if (baseTimeParsed)
            {
                switch (splitted[0].ToLowerInvariant())
                {
                case "years":
                    traceSource.TraceEvent(TraceEventType.Information, 1, "Detected axis suitable for StepFunctionYearsIntegrator");
                    return(new AxisFound(varName, AxisKind.Years, baseTime));

                case "days":
                    traceSource.TraceEvent(TraceEventType.Information, 2, "Detected axis suitable for  StepFunctionDaysIntegrator");
                    return(new AxisFound(varName, AxisKind.Days, baseTime));

                case "hours":
                    traceSource.TraceEvent(TraceEventType.Information, 3, "Detected axis suitable for  StepFunctionHoursIntegrator");
                    return(new AxisFound(varName, AxisKind.Hours, baseTime));

                default:
                    traceSource.TraceEvent(TraceEventType.Error, 4, string.Format("the offset units in units metadata entry of \"{0}\" can't be parsed. It must be one of the following: years, days or hours", varName));
                    return(new AxisNotFound());
                }
            }
            else
            {
                traceSource.TraceEvent(TraceEventType.Error, 5, string.Format("reference datetime in units metadata entry of \"{0}\" can't be parsed. It must be in format \"{1}\", but it is \"{2}\"", varName, dateFormats[0], dateToParse));
            }
            return(new AxisNotFound());
        }