public void GreatCircleDistanceTest() { Assert.AreEqual(System.Math.PI * 0.5, SphereMath.GetDistance(0.0, 90.0, 90.0, 23.4, 1.0), 1e-14); Assert.AreEqual(System.Math.PI * 0.5, SphereMath.GetDistance(0.0, 0.0, 0.0, 90.0, 1.0), 1e-14); Assert.AreEqual(System.Math.PI * 0.5, SphereMath.GetDistance(0.0, 0.0, 0.0, -90.0, 1.0), 1e-14); Assert.AreEqual(System.Math.PI * 0.5, SphereMath.GetDistance(0.0, 180.0, 0.0, 90.0, 1.0), 1e-14); Assert.AreEqual(System.Math.PI * 0.5, SphereMath.GetDistance(0.0, 180.0, 0.0, -90.0, 1.0), 1e-14); Assert.AreEqual(System.Math.PI * 0.5, SphereMath.GetDistance(0.0, 360.0, 0.0, 90.0, 1.0), 1e-14); Assert.AreEqual(System.Math.PI * 0.5, SphereMath.GetDistance(0.0, 360.0, 0.0, -90.0, 1.0), 1e-14); }
public async Task <double[]> EvaluateCellsBatchAsync(LinearCombinationContext computationalContext, IEnumerable <ICellRequest> cells) { var variogramProvider = await variogramProviderFactory.ConstructAsync(); var combinationsIterator = computationalContext.Combinations.GetEnumerator(); traceSource.TraceEvent(TraceEventType.Start, 1, "Filtering out cells that are not requested"); var filtered = cells.Select(cell => { Tuple <ICellRequest, RealValueNodes, IEnumerable <LinearWeight> > currentElement; ICellRequest contextCell; do { var nextExists = combinationsIterator.MoveNext(); if (!nextExists) { throw new InvalidOperationException("Received linear combination does not containg information about requested cell. Context is not synchronize with requested cells sequenece."); } currentElement = combinationsIterator.Current; contextCell = currentElement.Item1; } while (!contextCell.Equals(cell)); return(currentElement); }).ToArray(); traceSource.TraceEvent(TraceEventType.Stop, 1, "Filtered out cells that are not requested"); traceSource.TraceEvent(TraceEventType.Start, 2, "Evaluating uncertatinty for sequence of cells using precomputed linear combinations"); var resultsTasks = filtered.AsParallel().AsOrdered().Select(async tuple => { if (tuple.Item2.Lats.Length == 0) { return(Double.NaN); //there are no nodes. Out of data request? can't produce uncertainty } var variogram = await variogramProvider.GetSpatialVariogramAsync(tuple.Item2); var cell = tuple.Item1; var weights = tuple.Item3.ToArray(); var nodes = tuple.Item2; Debug.Assert(Math.Abs(weights.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 < weights.Length; i++) { double w = weights[i].Weight; int idx1 = weights[i].DataIndex; double lat1 = nodes.Lats[idx1]; double lon1 = nodes.Lons[idx1]; for (int j = 0; j < i; j++) { int idx2 = weights[j].DataIndex; double lat2 = nodes.Lats[idx2]; double lon2 = nodes.Lons[idx2]; double dist = SphereMath.GetDistance(lat1, lon1, lat2, lon2); double cov = sill - variogram.GetGamma(dist); acc += 2.0 * w * weights[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(acc * 0.5); //as dealing with full variogram instead of semivariogram }).ToArray(); var results = await Task.WhenAll(resultsTasks); traceSource.TraceEvent(TraceEventType.Stop, 2, "Evaluated uncertatinty for sequence of cells using precomputed linear combinations"); return(results); }
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()); }
public Task <VariogramModule.IVariogram> GetSpatialVariogramAsync(LinearCombination.RealValueNodes nodes) { var task = taskFactory.StartNew(new Func <object, VariogramModule.IVariogram>(obj => { Stopwatch sw = Stopwatch.StartNew(); LinearCombination.RealValueNodes localNodes = (LinearCombination.RealValueNodes)obj; var variogramFitter = new LMDotNetVariogramFitter.Fitter() as VariogramModule.IVariogramFitter; traceSource.TraceEvent(TraceEventType.Start, 1, "Starting build of emperical variogram"); var pointSet = new EmpVariogramBuilder.PointSet(localNodes.Lats, localNodes.Lons, localNodes.Values); 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); sw.Stop(); traceSource.TraceEvent(TraceEventType.Stop, 1, string.Format("Emperical variogram is build in {0}", sw.Elapsed)); sw = Stopwatch.StartNew(); traceSource.TraceEvent(TraceEventType.Start, 2, "Starting variogram fitting"); var variogramRes = variogramFitter.Fit(empVar); sw.Stop(); traceSource.TraceEvent(TraceEventType.Stop, 2, string.Format("Emperical variogram is build in {0}", sw.Elapsed)); if (FSharpOption <VariogramModule.IDescribedVariogram> .get_IsNone(variogramRes)) { traceSource.TraceEvent(TraceEventType.Error, 3, "Fariogram fitting failed. Falling back to coarse variogram approximation"); return(variogramFitter.GetFallback(empVar)); } else { return(variogramRes.Value); } }), nodes); return(task); }