protected override async Task <double[]> EvaluateCellsBatchAsync(IRequestContext context, ComputationalContext computationalContext, IEnumerable <GeoCellTuple> cells) { await SaveObservationsAndDalanayDiagsForCells(context, computationalContext, cells); VariogramModule.IVariogramFitter variogramFitter = new LMDotNetVariogramFitter.Fitter(); Dictionary <ITimeSegment, VariogramModule.IVariogram> variograms = new Dictionary <ITimeSegment, VariogramModule.IVariogram>(); Dictionary <ITimeSegment, IObservationsInformation> observations = (Dictionary <ITimeSegment, IObservationsInformation>)computationalContext["observations"]; LimitedConcurrencyLevelTaskScheduler lclts = new LimitedConcurrencyLevelTaskScheduler(Environment.ProcessorCount); TaskFactory taskFactory = new TaskFactory(lclts); var variogramTasks = observations.Select(pair => taskFactory.StartNew(() => { ITimeSegment ts = pair.Key; TraceVerbose(string.Format("Fitting variogram for {0} ({1} observations)", ts, pair.Value.Observations.Length)); Stopwatch sw1 = Stopwatch.StartNew(); var lats = pair.Value.Observations.Select(o => o.Latitude).ToArray(); var lons = pair.Value.Observations.Select(o => o.Longitude).ToArray(); var vals = pair.Value.Observations.Select(o => o.Value).ToArray(); var pointSet = new EmpVariogramBuilder.PointSet(lats, lons, vals); var dist = FuncConvert.ToFSharpFunc(new Converter <Tuple <double, double>, FSharpFunc <Tuple <double, double>, double> >(t1 => FuncConvert.ToFSharpFunc(new Converter <Tuple <double, double>, double>(t2 => SphereMath.GetDistance(t1.Item1, t1.Item2, t2.Item1, t2.Item2))))); var empVar = EmpVariogramBuilder.EmpiricalVariogramBuilder.BuildEmpiricalVariogram(pointSet, dist); var fitted_variogram = variogramFitter.Fit(empVar); VariogramModule.IVariogram effectiveVariogram = null; sw1.Stop(); if (FSharpOption <VariogramModule.IDescribedVariogram> .get_IsSome(fitted_variogram)) { effectiveVariogram = fitted_variogram.Value; TraceVerbose(string.Format("Variogram fited for {0} ({1} observations) in {2}", ts, pair.Value.Observations.Length, sw1.Elapsed)); } else { TraceWarning(string.Format("Variogram fitting failed for {0} ({1} observations) in {2}. Using fallback variogram", ts, pair.Value.Observations.Length, sw1.Elapsed)); effectiveVariogram = variogramFitter.GetFallback(empVar); } lock ("saving_variograms") { variograms.Add(ts, effectiveVariogram); } })); TraceVerbose(string.Format("Starting calculations of linear weights for all cells")); Stopwatch sw2 = Stopwatch.StartNew(); var weigths = CalcLinearWeights(computationalContext, cells); sw2.Stop(); TraceVerbose(string.Format("calculations of linear weights for all cells ended in {0}", sw2.Elapsed)); TraceVerbose(string.Format("Waiting for all variograms to be computed")); await Task.WhenAll(variogramTasks); TraceVerbose(string.Format("All variograms are computed. Calculating variances and values")); Stopwatch sw3 = Stopwatch.StartNew(); var resultValues = cells.Zip(weigths, (cell, weightTuple) => { ITimeSegment ts = cell.Time; var weight = weightTuple.Item2; VariogramModule.IVariogram variogram = variograms[ts]; var observation = observations[ts].Observations; Debug.Assert(Math.Abs(weight.Sum(w => w.Weight) - 1.0) < 1e-10); double sill = variogram.Sill; double cellLat = (cell.LatMax + cell.LatMin) * 0.5; double cellLon = (cell.LonMax + cell.LonMin) * 0.5; //var = cov(0)+ sum sum (w[i]*w[j]*cov(i,j))-2.0*sum(w[i]*cov(x,i)) double cov_at_0 = sill; double acc = cov_at_0; //cov(0) for (int i = 0; i < weight.Length; i++) { double w = weight[i].Weight; int idx1 = weight[i].DataIndex; double lat1 = observation[idx1].Latitude; double lon1 = observation[idx1].Longitude; for (int j = 0; j < i; j++) { int idx2 = weight[j].DataIndex; double lat2 = observation[idx2].Latitude; double lon2 = observation[idx2].Longitude; double dist = SphereMath.GetDistance(lat1, lon1, lat2, lon2); double cov = sill - variogram.GetGamma(dist); acc += 2.0 * w * weight[j].Weight * cov; } acc += w * w * cov_at_0; //diagonal elements double dist2 = SphereMath.GetDistance(lat1, lon1, cellLat, cellLon); double cov2 = sill - variogram.GetGamma(dist2); acc -= 2.0 * w * cov2; } return(Tuple.Create(cell, Math.Sqrt(acc), weight.Sum(w => observation[w.DataIndex].Value * w.Weight))); }).ToArray(); sw3.Stop(); TraceVerbose(string.Format("All sigmas calulated in {0}", sw3.Elapsed)); computationalContext.Add("results", resultValues); return(resultValues.Select(r => r.Item2).ToArray()); }