public Task <double> GetVarianceForCombinationAsync(IPs temporalWeights, ICellRequest cell, double baseNodeVariance)
        {
            var capturedValues = Tuple.Create(temporalWeights, cell, baseNodeVariance);

            return(Task.Factory.StartNew(obj =>
            {
                Tuple <IPs, ICellRequest, double> typedObj = (Tuple <IPs, ICellRequest, double>)obj;

                var name = typedObj.Item2.VariableName;

                var processDescription = dict.GetOrAdd(name, new Lazy <IGaussianProcessDescription>(() =>
                {
                    var v = variogramFactory.Create(name);
                    if (v == null)
                    {
                        ts.TraceEvent(TraceEventType.Warning, 1, string.Format("Could not find temporal variogram for the \"{0}\" variable. Skipping uncertainty propagation analysis", name));
                    }
                    else
                    {
                        ts.TraceEvent(TraceEventType.Information, 2, string.Format("Loaded temporal variogram for \"{0}\" variable", name));
                    }
                    return v;
                }, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication)).Value;

                if (processDescription == null)    //Variogram not found.
                {
                    return double.MaxValue;
                }

                var variogram = processDescription.Variogram;

                var tempPrecomputedNugget = variogram.Nugget;
                var tempPrecomputedSill = variogram.Sill;

                double tempSpatIndependentVariance = double.IsNaN(typedObj.Item3) ? (tempPrecomputedNugget) : (typedObj.Item3);
                var tempVarProps = new TemporalVarianceProperties(tempPrecomputedSill - tempPrecomputedNugget + tempSpatIndependentVariance, new Func <double, double, double>((coord1, coord2) => (tempPrecomputedSill - variogram.GetGamma(processDescription.Dist(coord1, coord2)))));
                double temporalVariance = GetTemporalVariance(typedObj.Item1, timeAxis, axisLocator.getAproximationGrid(cell.Time), tempVarProps);
                Debug.Assert(temporalVariance >= 0.0);
                return temporalVariance;
            }, capturedValues));
        }
        private static double GetTemporalVariance(IPs temporalWeights, double[] nodeLocations, double[] targetLocations, TemporalVarianceProperties varianceProps)
        {
            //Var(x) = Cov(0) + sum(sum(v_i*v_j*Cov(X_i,X_j)) - 2.0 * sum(v_i*Cov(X_i,X))) for semivariograms.
            double tempCov0        = varianceProps.Cov0;
            var    tempCovariogram = varianceProps.Covariance;
            double acc             = tempCov0; //Cov(0)
            var    weights         = temporalWeights.Weights;
            var    indices         = temporalWeights.Indices;
            int    N    = temporalWeights.Weights.Length;
            int    M    = targetLocations.Length;
            double sum2 = 0.0;

            for (int i = 0; i < N; i++)
            {
                // sum(sum(lambda.[i]*lambda.[j]*Cov(X_i,X_j))
                var weight_i = weights[i];
                acc += weight_i * weight_i * tempCov0;
                for (int j = i + 1; j < N; j++)
                {
                    acc += 2.0 * weight_i * weights[j] * tempCovariogram.Invoke(nodeLocations[indices[i]], nodeLocations[indices[j]]);
                }

                //cov(x,x_i))
                double cov_x_xi = 0.0;
                for (int j = 0; j < M; j++) //average cov(x,x_i) as in block kriging for region requsts
                {
                    cov_x_xi += tempCovariogram.Invoke(nodeLocations[indices[i]], targetLocations[j]);
                }
                sum2 += weight_i * cov_x_xi / M;
            }
            return(0.5 * acc - sum2); //as dealing with full variograms instead of semivariogrmas acc - 2.0* sum2
        }