/// <summary>Performs work in order to find optimum location in new constellation for given node /// <para>Recieves planrequest, finds best free location, or trades locations with other node in order to optimize net cost</para> /// </summary> public static void GeneratePlan(INode myNode, PlanRequest request) { // Remove failure detection requests in queue as we are planning to make changes to network structure anyway, which might solve the failure myNode.CommsModule.RequestList.RemoveAll(x => x.Command == Request.Commands.DETECTFAILURE); if (request.DestinationID != myNode.Id) { return; } else { myNode.ExecutingPlan = false; myNode.State = Node.NodeState.PLANNING; myNode.GeneratingPlan = request.Plan; PlanRequest newRequest = request.DeepCopy(); newRequest.AckExpected = true; if (newRequest.Plan.Entries.Any(entry => entry.NodeID == myNode.Id == false)) { List <NodeLocationMatch> matches = CalculatePositions(myNode, newRequest); ConstellationPlan newPlan = ProcessPlan(matches, newRequest, myNode); newRequest.Plan = newPlan; } Transmit(newRequest, myNode); } }
public static void ExcludeNode(INode myNode, DetectFailureRequest request) { ConstellationPlan RecoveryPlan = GenerateConstellation.GenerateTargetConstellation(myNode.Router.ReachableSats(myNode).Count, 7.152f); PlanRequest recoveryRequest = new PlanRequest { SourceID = myNode.Id, DestinationID = myNode.Id, Command = Request.Commands.GENERATE, Plan = RecoveryPlan, Dir = Router.CommDir.CW }; NetworkUpdateRequest updateRequest = new NetworkUpdateRequest(new List <uint?>() { request.NodeToCheck }); recoveryRequest.DependencyRequests.Add(updateRequest); if (myNode.Router.NextSequential(myNode, Router.CommDir.CW) == null) { recoveryRequest.Dir = Router.CommDir.CCW; } PlanGenerator.GeneratePlan(myNode, recoveryRequest); }
public ConstellationPlan DeepCopy() { ConstellationPlan copy = new ConstellationPlan(Entries.ConvertAll(x => x.DeepCopy())); copy.LastEditedBy = LastEditedBy; return(copy); }
// Start is called before the first frame update void Start() { _satellitePrefab = SatellitePrefab; Constants.EarthRadius = (GetComponent <SphereCollider>().radius *transform.localScale.x); float constellationAltitude = Constants.EarthRadius + Constants.ScaleToSize(SatelliteAltitude); float constellationRadius = constellationAltitude / 2; List <ConstellationPlanEntry> entries = new List <ConstellationPlanEntry>(); List <INode> nodes = new List <INode>(); for (int i = 0; i < PlaneNum; i++) { float yAngle = Mathf.PI / PlaneNum * i; for (uint?j = 0; j < SatellitesPerPlane; j++) { float angle = (int)j * Mathf.PI * 2f / SatellitesPerPlane; Vector3 instantiationPos = new Vector3( Mathf.Cos(angle) * constellationRadius, Mathf.Sin(yAngle / SatellitesPerPlane * (int)j) * constellationRadius, Mathf.Sin(angle) * constellationRadius); //Create a vector from earth center to the desired position Vector3 instantiationVector = (instantiationPos - transform.position).normalized * constellationAltitude; GameObject satellite = Instantiate(SatellitePrefab, transform.position + instantiationVector, Quaternion.identity); CommsSim sim = satellite.AddComponent <CommsSim>(); INode node = new Node(j, BackendHelpers.NumericsVectorFromUnity(satellite.transform.position)); node.TargetPosition = node.Position; node.CommsModule = sim; node.PlaneNormalDir = BackendHelpers.NumericsVectorFromUnity(Vector3.up); satellite.name = "P(" + i + "), S(" + j + ")"; satellite.GetComponent <SatelliteComms>().Node = node; satellite.GetComponent <SatelliteComms>().Node.AutoChecksAllowed = CanvasHandler.AutoChecksAllowed; List <ConstellationPlanField> fields = new List <ConstellationPlanField> { new ConstellationPlanField("DeltaV", 0, (x, y) => x.CompareTo(y)) }; ConstellationPlanEntry entry = new ConstellationPlanEntry(node.Position, fields, (x, y) => 1); entry.NodeID = node.Id; entries.Add(entry); nodes.Add(node); SatManager._instance.SatIndex++; } } ConstellationPlan plan = new ConstellationPlan(entries); nodes.ForEach(node => { node.ActivePlan = plan; node.GenerateRouter(); }); }
public static ConstellationPlan GenerateRecoveryConstellation(Vector3 midpoint, int nodeCount) { // Calculate positions evenly spread starting from midpoint List <Vector3> targetPositions = CalculatePositions(midpoint, nodeCount); // Create constellation plan based on target positions ConstellationPlan plan = CreatePlan(targetPositions); return(plan); }
public static void Recovery(INode myNode, uint?secondFailedNode) { //Remove edge from router, ensuring it won't try to route through the failed node myNode.Router.DeleteEdge(myNode.Id, secondFailedNode); // Find positions of nodes this node can reach List <Vector3> positions = new List <Vector3> { myNode.Position }; List <uint?> nodesToVisit = new List <uint?> { myNode.Id }; while (nodesToVisit.Count > 0) { uint?nodeToVisit = nodesToVisit[0]; nodesToVisit.RemoveAt(0); List <NetworkMapEntry> neighbourEntries = myNode.Router.NetworkMap.GetEntryByID(nodeToVisit).Neighbours.Select(x => myNode.Router.NetworkMap.GetEntryByID(x)).ToList(); nodesToVisit.AddRange(neighbourEntries.Where(x => positions.Contains(x.Position) == false).Select(x => x.ID)); positions.AddRange(neighbourEntries.Where(x => positions.Contains(x.Position) == false).Select(x => x.Position)); } // Calculate midpoint Vector3 midpoint = positions.Aggregate(Vector3.Zero, (x, y) => x + y); Vector3 midpointOnRightAltitude = Vector3.Normalize(midpoint) * Vector3.Distance(Vector3.Zero, myNode.Position); // Generate recovery plan and start planning ConstellationPlan recoveryPlan = GenerateConstellation.GenerateRecoveryConstellation(midpointOnRightAltitude, positions.Count); PlanRequest recoveryRequest = new PlanRequest { SourceID = myNode.Id, DestinationID = myNode.Id, Command = Request.Commands.GENERATE, Plan = recoveryPlan, }; NetworkUpdateRequest updateRequest = new NetworkUpdateRequest(new NetworkUpdateRequest(new List <uint?>() { secondFailedNode })); recoveryRequest.DependencyRequests.Add(updateRequest); myNode.Router.NetworkMap.Entries.RemoveAll(entry => entry.ID == secondFailedNode); myNode.CommsModule.Send(myNode.Id, recoveryRequest); }
public Router(INode _node, ConstellationPlan _plan) { node = _node; NetworkMap = new NetworkMap(); if (_plan != null && _plan.Entries.TrueForAll(entry => entry.NodeID != null)) { foreach (ConstellationPlanEntry entry in _plan.Entries) { NetworkMap.Entries.Add(new NetworkMapEntry(entry.NodeID, entry.Position)); NodeToNodeIDMapping.Add(entry.NodeID, 0); } } UpdateNetworkMap(_plan); AddNodeToGraph(node.Id); }
public override void UpdateNetworkMap(ConstellationPlan plan) { if (plan == null) { return; } NetworkMap newMap = new NetworkMap(); foreach (ConstellationPlanEntry entry in plan.Entries) { List <Tuple <uint?, float> > neighbors = new List <Tuple <uint?, float> >(); foreach (ConstellationPlanEntry innerEntry in plan.Entries.Where((x) => x != entry)) { float dist = Vector3.Distance(entry.Position, innerEntry.Position); if (dist < satRange) { if (innerEntry.NodeID != null) { neighbors.Add(new Tuple <uint?, float>(innerEntry.NodeID, dist)); } } } //Order sats by distance to myself neighbors = neighbors.OrderBy(sat => sat.Item2).ToList();//Only distinct please if (entry.NodeID != null) { if (newMap.GetEntryByID(entry.NodeID) == null) { newMap.Entries.Add(new NetworkMapEntry(entry.NodeID, neighbors.Select(sat => sat.Item1).ToList(), entry.Position)); } else { newMap.GetEntryByID(entry.NodeID).Neighbours = neighbors.Select(sat => sat.Item1).ToList(); newMap.GetEntryByID(entry.NodeID).Position = entry.Position; } } } NetworkMap = newMap; NodeToNodeIDMapping.Clear(); UpdateGraph(); }
public static ConstellationPlan CreatePlan(List <Vector3> targetPositions) { List <ConstellationPlanEntry> entries = new List <ConstellationPlanEntry>(); foreach (Vector3 targetPosition in targetPositions) { List <ConstellationPlanField> fields = new List <ConstellationPlanField> { new ConstellationPlanField("DeltaV", 0, (x, y) => x.CompareTo(y)) }; ConstellationPlanEntry entry = new ConstellationPlanEntry(targetPosition, fields, (x, y) => 1); entries.Add(entry); } ConstellationPlan plan = new ConstellationPlan(entries); return(plan); }
private static void Recover(INode myNode) { ConstellationPlan recoveryPlan = GenerateConstellation.GenerateTargetConstellation(myNode.Router.ReachableSats(myNode).Count, 7.152f); PlanRequest recoveryRequest = new PlanRequest { SourceID = myNode.Id, DestinationID = myNode.Id, Command = Request.Commands.GENERATE, Plan = recoveryPlan }; if (myNode.Router.NextSequential(myNode, Router.CommDir.CW) == null) { recoveryRequest.Dir = Router.CommDir.CCW; } myNode.CommsModule.Send(myNode.Id, recoveryRequest); }
public static ConstellationPlan GenerateTargetConstellation(int satCount, float constellationAltitude) { Random rng = new Random(); List <Vector3> TargetPositions = new List <Vector3>(); //Generate the target positions for (int i = 0; i < satCount; i++) { //Create random angle for position of Targetposition float angle = (360 / satCount) * i; angle = (float)(Math.PI / 180) * angle; Vector3 instantiationPos = Vector3.Transform(new Vector3(0, 0, 1), Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), angle)); //Set it relative to the earth Vector3 instantiationVector = Vector3.Normalize(instantiationPos) * constellationAltitude * rng.Next(1, 1); //Store for propagation TargetPositions.Add(instantiationVector); } List <ConstellationPlanEntry> entries = new List <ConstellationPlanEntry>(); //Create a plan containing the taraget positions foreach (Vector3 pos in TargetPositions) { Vector3 position = new Vector3(pos.X, pos.Y, pos.Z); List <ConstellationPlanField> fields = new List <ConstellationPlanField> { new ConstellationPlanField("DeltaV", 0, (x, y) => x.CompareTo(y)) }; ConstellationPlanEntry entry = new ConstellationPlanEntry(position, fields, (x, y) => 1); entries.Add(entry); } ConstellationPlan plan = new ConstellationPlan(entries); //Send the targetconstellation to random sat return(plan); }
/// <summary> /// Returns whether or not swapping the two nodes yields a more cost-efficient constellation. /// </summary> /// <returns></returns> public bool TrySwapNodes(uint?nodeID1, Vector3 nodePosition1, uint?nodeID2, Vector3 nodePosition2, out ConstellationPlan newPlan) { ConstellationPlan planCopy = DeepCopy(); // Make a copy of the plan to avoid the method having side effects. ConstellationPlanEntry entry1 = planCopy.Entries.Find(x => x.NodeID == nodeID1); ConstellationPlanEntry entry2 = planCopy.Entries.Find(x => x.NodeID == nodeID2); entry1.NodeID = nodeID2; entry1.Fields["DeltaV"].Value = Vector3.Distance(nodePosition2, entry1.Position); entry2.NodeID = nodeID1; entry2.Fields["DeltaV"].Value = Vector3.Distance(nodePosition1, entry2.Position); float currentSum = Entries.Select(x => x.Fields["DeltaV"].Value).Sum(); float newSum = planCopy.Entries.Select(x => x.Fields["DeltaV"].Value).Sum(); if (newSum < currentSum) { newPlan = planCopy; return(true); } else { newPlan = null; return(false); } }
public AdditionRequest(AdditionRequest other) : base(other) { plan = other.plan; }
public PlanRequest(PlanRequest other) : base(other) { Plan = other.Plan.DeepCopy(); }
private void Update() { if (SatManager._instance.satellites.TrueForAll(sat => sat.Node.State != Node.NodeState.PLANNING)) { GameObject.FindGameObjectsWithTag("LocationPlaceholder")?.ToList().ForEach(Destroy); } if (GameObject.FindGameObjectsWithTag("LocationPlaceholder").Length == 0 && SatManager._instance.satellites.Any(sat => sat.Node.State == Node.NodeState.PLANNING)) { SatelliteComms planningNode = SatManager._instance.satellites.Find(sat => sat.Node.State == Node.NodeState.PLANNING); planningNode.Node.GeneratingPlan.Entries.ForEach(entry => Instantiate(SatLocationPlaceholderPrefab, BackendHelpers.UnityVectorFromNumerics(entry.Position), Quaternion.identity)); } if (nodes.Count == 0) { Sats.ForEach(sat => nodes.Add(sat.GetComponent <SatelliteComms>().Node)); } if (plan == null) { return; } if (Input.GetMouseButtonDown(0) && Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out RaycastHit hit, float.MaxValue, ManualDesignMask) && plan.Entries.TrueForAll(entry => nodes.Any(node => System.Numerics.Vector3.Distance(node.Position, entry.Position) < 0.1f))) { if (EnableManualDesign == false) { Clear(); } if (GameObject.FindGameObjectsWithTag("LocationPlaceholder")?.ToList().Count < nodes.Count) { Instantiate(SatLocationPlaceholderPrefab, hit.point, Quaternion.identity); EnableAutotest = false; EnableManualDesign = true; } else if (EnableManualDesign) { List <ConstellationPlanEntry> entries = new List <ConstellationPlanEntry>(); foreach (Vector3 pos in GameObject.FindGameObjectsWithTag("LocationPlaceholder")?.ToList().Select(loc => loc.transform.position)) { System.Numerics.Vector3 position = new System.Numerics.Vector3(pos.x, pos.y, pos.z); List <ConstellationPlanField> fields = new List <ConstellationPlanField> { new ConstellationPlanField("DeltaV", 0, (x, y) => x.CompareTo(y)) }; ConstellationPlanEntry entry = new ConstellationPlanEntry(position, fields, (x, y) => 1); entries.Add(entry); } plan = new ConstellationPlan(entries); //Send the targetconstellation to random sat INode targetSat = Sats[UnityEngine.Random.Range(0, Sats.Count - 1)].GetComponent <SatelliteComms>().Node; PlanRequest request = new PlanRequest(); request.Command = Request.Commands.GENERATE; request.DestinationID = targetSat.Id; request.Plan = plan; request.MessageIdentifer = "42"; targetSat.Communicate(request); EnableManualDesign = false; } } }
public abstract void UpdateNetworkMap(ConstellationPlan plan);
public void GenerateTargetConstellation(INode RequesterNode) { System.Random r = new System.Random(RandomSeed); TargetPositions.Clear(); //If the constellation altitude input from textfield isn't numbers, return if (float.TryParse(ConstellationAltitudeInput, out float constellationAltitude) == false) { return; } //Set the constellation altitude based on the input textfield constellationAltitude = Constants.EarthRadius + Constants.ScaleToSize(constellationAltitude); //Get reference to satellites Sats = GameObject.FindGameObjectsWithTag("Satellite").ToList(); List <uint?> reachableNodes = RequesterNode.Router.ReachableSats(RequesterNode).ToList(); Sats.RemoveAll(sat => reachableNodes.Contains(sat.GetComponent <SatelliteComms>().Node.Id) == false); //Remove old location Placeholders GameObject.FindGameObjectsWithTag("LocationPlaceholder")?.ToList().ForEach(Destroy); for (int i = 0; i < Sats.Count; i++) { //Create random angle for position of Targetposition float angle = (360 / Sats.Count) * i; Vector3 instantiationPos = Quaternion.Euler(0, angle, 0) * Vector3.forward; //Set it relative to the earth Vector3 instantiationVector = (instantiationPos - Vector3.zero).normalized * constellationAltitude; //Store for propagation TargetPositions.Add(instantiationVector); Instantiate(SatLocationPlaceholderPrefab, instantiationVector, Quaternion.identity); } List <ConstellationPlanEntry> entries = new List <ConstellationPlanEntry>(); foreach (Vector3 pos in TargetPositions) { Vector3 position = new Vector3(pos.x, pos.y, pos.z); List <ConstellationPlanField> fields = new List <ConstellationPlanField> { new ConstellationPlanField("DeltaV", 0, (x, y) => x.CompareTo(y)) }; ConstellationPlanEntry entry = new ConstellationPlanEntry(BackendHelpers.NumericsVectorFromUnity(position), fields, (x, y) => 1); entries.Add(entry); } plan = new ConstellationPlan(entries); //Send the targetconstellation to random sat INode targetSat = RequesterNode; PlanRequest request = new PlanRequest { Command = Request.Commands.GENERATE, SourceID = targetSat.Id, DestinationID = targetSat.Id, SenderID = 42, Dir = Router.CommDir.CW, AckExpected = true, MessageIdentifer = "42", Plan = plan }; PlanGenerator.GeneratePlan(targetSat, request); }
public async static void FailureDetected(INode myNode, uint?failedNode) { //Remove edge from router, ensuring it won't try to route through the failed node myNode.Router.DeleteEdge(myNode.Id, failedNode); List <uint?> failedNeighbours = new List <uint?>() { myNode.Id }; List <uint?> neighboursToCheck = myNode.Router.NetworkMap.GetEntryByID(failedNode).Neighbours.Except(failedNeighbours).ToList(); // Start recovery plan gen without failedNode in case myNode is the only neighbour if (neighboursToCheck.Count == 0) { ConstellationPlan RecoveryPlan = GenerateConstellation.GenerateTargetConstellation(myNode.Router.ReachableSats(myNode).Count, 7.152f); PlanRequest recoveryRequest = new PlanRequest { SourceID = myNode.Id, DestinationID = myNode.Id, Command = Request.Commands.GENERATE, Plan = RecoveryPlan, Dir = Router.CommDir.CW }; NetworkUpdateRequest updateRequest = new NetworkUpdateRequest(new NetworkUpdateRequest(new List <uint?>() { failedNode })); recoveryRequest.DependencyRequests.Add(updateRequest); if (myNode.Router.NextSequential(myNode, Router.CommDir.CW) == null) { recoveryRequest.Dir = Router.CommDir.CCW; } PlanGenerator.GeneratePlan(myNode, recoveryRequest); } else // Otherwise ask another neighbour to try to contact failedNode { uint?neighbourID = neighboursToCheck[0]; uint?nextHop = myNode.Router.NextHop(myNode.Id, neighbourID); DetectFailureRequest request = new DetectFailureRequest { DestinationID = neighbourID, SourceID = myNode.Id, Command = Request.Commands.DETECTFAILURE, ResponseExpected = false, AckExpected = true, NodeToCheck = failedNode, DeadEdges = new List <Tuple <uint?, uint?> > { new Tuple <uint?, uint?>(myNode.Id, failedNode) }, FailedNeighbours = failedNeighbours }; myNode.Router.NetworkMap.Entries.RemoveAll(entry => entry.ID == failedNode); await myNode.CommsModule.SendAsync(nextHop, request, Constants.COMMS_TIMEOUT, Constants.COMMS_ATTEMPTS); } }