private bool TryGetContaining(Conditions conditions, out Conditions containingConditions, out EnvelopePoint[,] points) { containingConditions = new Conditions(); points = new EnvelopePoint[0, 0]; Dictionary <Conditions, EnvelopePoint[, ]> .Enumerator enumerator = cache.GetEnumerator(); int bestNumPoints = 0; bool result = false; while (enumerator.MoveNext()) { Conditions enumConditions = cachedConditions[enumerator.Current.Key]; if (enumConditions.Contains(conditions)) { result = true; int numPoints = Mathf.FloorToInt((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / enumConditions.stepSpeed + 1) * Mathf.FloorToInt((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / enumConditions.stepAltitude + 1); if (numPoints > bestNumPoints) { bestNumPoints = numPoints; containingConditions = enumConditions; points = cache[enumConditions]; } } } return(result); }
public void Calculate(CelestialBody body, float lowerBoundSpeed = 0, float upperBoundSpeed = 2000, float lowerBoundAltitude = 0, float upperBoundAltitude = 60000, float stepSpeed = 50f, float stepAltitude = 500) { // Set up calculation conditions and bounds Conditions newConditions; newConditions = new Conditions(body, lowerBoundSpeed, upperBoundSpeed, stepSpeed, lowerBoundAltitude, upperBoundAltitude, stepAltitude); if (currentConditions.Equals(newConditions) && Status != TaskStatus.WaitingToRun) { return; } Cancel(); // Generate 'coarse' cache float firstStepSpeed = (newConditions.upperBoundSpeed - newConditions.lowerBoundSpeed) / resolution[0, 0]; float firstStepAltitude = (newConditions.upperBoundAltitude - newConditions.lowerBoundAltitude) / resolution[0, 1]; EnvelopePoint[] preliminaryData = new EnvelopePoint[(resolution[0, 0] + 1) * (resolution[0, 1] + 1)]; // Probably won't run in parallel because it's very short. // But the UI will hang waiting for this to complete, so a self-triggering CancellationToken is provided with a life span of 5 seconds. try { Parallel.For(0, preliminaryData.Length, new ParallelOptions() { CancellationToken = new CancellationTokenSource(5000).Token }, WindTunnelWindow.Instance.GetAeroPredictor, (index, state, predictor) => { int x = index % (resolution[0, 0] + 1), y = index / (resolution[0, 0] + 1); EnvelopePoint result = new EnvelopePoint(predictor, newConditions.body, y * firstStepAltitude + newConditions.lowerBoundAltitude, x * firstStepSpeed + newConditions.lowerBoundSpeed); preliminaryData[index] = result; cache[new SurfCoords(result.speed, result.altitude)] = result; return(predictor); }, (predictor) => (predictor as VesselCache.IReleasable)?.Release()); } catch (OperationCanceledException) { Debug.LogError("Wind Tunnel: Initial pass timed out."); } catch (AggregateException ex) { Debug.LogError("Wind Tunnel: Initial pass threw an inner exception."); Debug.LogException(ex.InnerException); } cancellationTokenSource = new CancellationTokenSource(); WindTunnel.Instance.StartCoroutine(Processing(newConditions, preliminaryData.To2Dimension(resolution[0, 0] + 1))); }
private static void GenerateSurfPoint(object obj) { GenData data = (GenData)obj; if (data.storeState.manager.Cancelled) { return; } //Debug.Log("Starting point: " + data.altitude + "/" + data.speed); EnvelopePoint result = new EnvelopePoint(data.vessel, data.conditions.body, data.altitude, data.speed, data.AoA_guess, data.maxA_guess, data.pitchI_guess); //Debug.Log("Point solved: " + data.altitude + "/" + data.speed); data.storeState.StoreResult(result); }
private IEnumerator Processing(CalculationManager manager, Conditions conditions, AeroPredictor vessel) { int numPtsX = (int)Math.Ceiling((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / conditions.stepSpeed); int numPtsY = (int)Math.Ceiling((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / conditions.stepAltitude); EnvelopePoint[,] newEnvelopePoints = new EnvelopePoint[numPtsX + 1, numPtsY + 1]; GenData rootData = new GenData(vessel, conditions, 0, 0, manager); //System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); //timer.Start(); ThreadPool.QueueUserWorkItem(SetupInBackground, rootData, true); while (!manager.Completed) { //Debug.Log(manager.PercentComplete + "% done calculating..."); if (manager.Status == CalculationManager.RunStatus.Cancelled) { yield break; } yield return(0); } //timer.Stop(); //Debug.Log("Time taken: " + timer.ElapsedMilliseconds / 1000f); newEnvelopePoints = ((CalculationManager.State[, ])rootData.storeState.Result) .SelectToArray(pt => (EnvelopePoint)pt.Result); AddToCache(conditions, newEnvelopePoints); if (!manager.Cancelled) { envelopePoints = newEnvelopePoints; currentConditions = conditions; UpdateGraphs(); CalculateOptimalLines(vessel, conditions, WindTunnelWindow.Instance.TargetSpeed, WindTunnelWindow.Instance.TargetAltitude, 0, 0); valuesSet = true; } yield return(0); if (!manager.Cancelled) { Conditions nextConditions = conditions.Modify(stepSpeed: conditions.stepSpeed / 2, stepAltitude: conditions.stepAltitude / 2); WindTunnel.Instance.StartCoroutine(RefinementProcessing(calculationManager, nextConditions, vessel, newEnvelopePoints, conditions)); } }
private IEnumerator RefinementProcessing(CalculationManager manager, Conditions conditions, AeroPredictor vessel, EnvelopePoint[,] basisData, Conditions basisConditions = new Conditions(), Queue <Conditions> followOnConditions = null, bool forcePushToGraph = false) { int numPtsX = (int)Math.Ceiling((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / conditions.stepSpeed); int numPtsY = (int)Math.Ceiling((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / conditions.stepAltitude); EnvelopePoint[,] newEnvelopePoints = new EnvelopePoint[numPtsX + 1, numPtsY + 1]; CalculationManager backgroundManager = new CalculationManager(); manager.OnCancelCallback += backgroundManager.Cancel; CalculationManager.State[,] results = new CalculationManager.State[numPtsX + 1, numPtsY + 1]; GenData rootData = new GenData(vessel, conditions, 0, 0, backgroundManager); ThreadPool.QueueUserWorkItem(ContinueInBackground, new object[] { rootData, results, basisData, basisConditions }); while (!backgroundManager.Completed) { if (manager.Status == CalculationManager.RunStatus.Cancelled) { backgroundManager.Cancel(); yield break; } yield return(0); } manager.OnCancelCallback -= backgroundManager.Cancel; newEnvelopePoints = ((CalculationManager.State[, ])rootData.storeState.Result) .SelectToArray(pt => (EnvelopePoint)pt.Result); AddToCache(conditions, newEnvelopePoints); if (currentConditions.Equals(conditions) || (forcePushToGraph && !backgroundManager.Cancelled)) { envelopePoints = newEnvelopePoints; currentConditions = conditions; UpdateGraphs(); valuesSet = true; } backgroundManager.Dispose(); if (!manager.Cancelled && followOnConditions != null && followOnConditions.Count > 0) { yield return(0); Conditions nextConditions = followOnConditions.Dequeue(); WindTunnel.Instance.StartCoroutine(RefinementProcessing(manager, nextConditions, vessel, newEnvelopePoints, conditions, followOnConditions, forcePushToGraph)); } }
private IEnumerator Processing(CalculationManager manager, Conditions conditions, AeroPredictor vessel) { int numPtsX = (int)Math.Ceiling((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / conditions.stepSpeed); int numPtsY = (int)Math.Ceiling((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / conditions.stepAltitude); EnvelopePoint[,] newEnvelopePoints = new EnvelopePoint[numPtsX + 1, numPtsY + 1]; GenData rootData = new GenData(vessel, conditions, 0, 0, manager); ThreadPool.QueueUserWorkItem(SetupInBackground, rootData); while (!manager.Completed) { //Debug.Log(manager.PercentComplete + "% done calculating..."); if (manager.Status == CalculationManager.RunStatus.Cancelled) { yield break; } yield return(0); } newEnvelopePoints = ((CalculationManager.State[, ])rootData.storeState.Result) .SelectToArray(pt => (EnvelopePoint)pt.Result); if (!manager.Cancelled) { //cache.Add(conditions, newEnvelopePoints); AddToCache(conditions, newEnvelopePoints); envelopePoints = newEnvelopePoints; currentConditions = conditions; GenerateGraphs(); valuesSet = true; } float stepSpeed = conditions.stepSpeed, stepAltitude = conditions.stepAltitude; for (int i = 2; i <= 2; i++) { yield return(0); CalculationManager backgroundManager = new CalculationManager(); manager.OnCancelCallback += backgroundManager.Cancel; conditions = new Conditions(conditions.body, conditions.lowerBoundSpeed, conditions.upperBoundSpeed, stepSpeed / i, conditions.lowerBoundAltitude, conditions.upperBoundAltitude, stepAltitude / i); CalculationManager.State[,] prevResults = ((CalculationManager.State[, ])rootData.storeState.Result).SelectToArray(p => p); rootData = new GenData(vessel, conditions, 0, 0, backgroundManager); ThreadPool.QueueUserWorkItem(ContinueInBackground, new object[] { rootData, prevResults }); while (!backgroundManager.Completed) { if (manager.Status == CalculationManager.RunStatus.Cancelled) { backgroundManager.Cancel(); yield break; } yield return(0); } newEnvelopePoints = ((CalculationManager.State[, ])rootData.storeState.Result) .SelectToArray(pt => (EnvelopePoint)pt.Result); if (!manager.Cancelled) { //cache.Add(conditions, newEnvelopePoints); AddToCache(conditions, newEnvelopePoints); envelopePoints = newEnvelopePoints; currentConditions = conditions; UpdateGraphs(); valuesSet = true; } } }
public SurfCoords(EnvelopePoint point) : this(point.speed, point.altitude) { }
private IEnumerator Processing(Conditions conditions, EnvelopePoint[,] prelimData) { CancellationTokenSource closureCancellationTokenSource = this.cancellationTokenSource; primaryProgress = new EnvelopePoint[conditions.Resolution]; int cachedCount = 0; stopwatch.Reset(); stopwatch.Start(); task = Task.Factory.StartNew <EnvelopePoint[, ]>( () => { float[,] AoAs_guess = null, maxAs_guess = null, pitchIs_guess = null; AoAs_guess = prelimData.SelectToArray(pt => pt.AoA_level); maxAs_guess = prelimData.SelectToArray(pt => pt.AoA_max); pitchIs_guess = prelimData.SelectToArray(pt => pt.pitchInput); try { //OrderablePartitioner<EnvelopePoint> partitioner = Partitioner.Create(primaryProgress, true); Parallel.For <AeroPredictor>(0, primaryProgress.Length, new ParallelOptions() { CancellationToken = closureCancellationTokenSource.Token }, WindTunnelWindow.Instance.GetAeroPredictor, (index, state, predictor) => { int x = index % conditions.XResolution, y = index / conditions.XResolution; SurfCoords coords = new SurfCoords(x * conditions.stepSpeed + conditions.lowerBoundSpeed, y * conditions.stepAltitude + conditions.lowerBoundAltitude); EnvelopePoint result; if (!cache.TryGetValue(coords, out result)) { result = new EnvelopePoint(predictor, conditions.body, y * conditions.stepAltitude + conditions.lowerBoundAltitude, x * conditions.stepSpeed + conditions.lowerBoundSpeed); cache[coords] = result; } else { Interlocked.Increment(ref cachedCount); } primaryProgress[index] = result; return(predictor); }, (predictor) => (predictor as VesselCache.IReleasable)?.Release()); closureCancellationTokenSource.Token.ThrowIfCancellationRequested(); Debug.Log("KWT Data run finished. " + cachedCount + " of " + primaryProgress.Length + " retreived from cache. (" + (float)cachedCount / primaryProgress.Length * 100 + "%)"); return(primaryProgress.To2Dimension(conditions.XResolution)); } catch (AggregateException aggregateException) { foreach (var ex in aggregateException.Flatten().InnerExceptions) { Debug.LogException(ex); } throw aggregateException; } }, closureCancellationTokenSource.Token); //if (task.Wait(25)) //Debug.Log("KWT: Waiting actually did something!"); while (task.Status < TaskStatus.RanToCompletion) { //Debug.Log(manager.PercentComplete + "% done calculating..."); yield return(0); } //timer.Stop(); //Debug.Log("Time taken: " + timer.ElapsedMilliseconds / 1000f); if (task.Status > TaskStatus.RanToCompletion) { if (task.Status == TaskStatus.Faulted) { Debug.LogError("Wind tunnel task faulted (Envelope)"); Debug.LogException(task.Exception); } else if (task.Status == TaskStatus.Canceled) { Debug.Log("Wind tunnel task was canceled. (Envelope)"); } yield break; } if (!closureCancellationTokenSource.IsCancellationRequested) { envelopePoints = ((Task <EnvelopePoint[, ]>)task).Result; currentConditions = conditions; UpdateGraphs(); EnvelopeLine.CalculateOptimalLines(conditions, WindTunnelWindow.Instance.TargetSpeed, WindTunnelWindow.Instance.TargetAltitude, 0, 0, envelopePoints, closureCancellationTokenSource, graphables); valuesSet = true; } if (cachedCount < primaryProgress.Length) { yield return(0); } if (!closureCancellationTokenSource.IsCancellationRequested) { Conditions newConditions; for (int i = 1; i <= resolution.GetUpperBound(0); i++) { if (resolution[i, 0] + 1 > conditions.XResolution || resolution[i, 1] + 1 > conditions.YResolution) { newConditions = conditions.Modify( stepSpeed: Math.Min((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / resolution[i, 0], conditions.stepSpeed), stepAltitude: Math.Min((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / resolution[i, 1], conditions.stepAltitude)); Debug.Log("Wind Tunnel graphing higher res at:" + newConditions.XResolution + " by " + newConditions.YResolution); WindTunnel.Instance.StartCoroutine(Processing(newConditions, envelopePoints)); yield break; } } Debug.Log("Wind Tunnel Graph reached maximum resolution"); } }