Exemplo n.º 1
0
        /// <summary>
        /// This function will "flux" the wood from path to path using connection points and list of sites in the paths until it meets an exit path.
        /// </summary>
        /// <param name="connectionToThisSite">The site from which we will beguin to flux on this current path. Has to be in the current path.</param>
        /// <param name="woodFlux">The amount of wood to be fluxed along the paths to an exit point</param>
        public void FluxPathFromSite(Site connectionToThisPath, double woodFlux)
        {
            FluxPath    currentPath            = this;
            Site        currentConnectionPoint = connectionToThisPath;
            int         connectionIndex;
            List <Site> sitesTofFlux;

            while (!currentPath.isAnEnd)
            {
                // Case of micro-paths (1 site), in order to avoid errors.
                if (currentPath.sitesInPath.Count == 1)
                {
                    SiteVars.RoadsInLandscape[currentPath.sitesInPath[0]].timestepWoodFlux += woodFlux;
                }
                else
                {
                    connectionIndex = currentPath.sitesInPath.IndexOf(currentConnectionPoint);
                    if (connectionIndex == -1)
                    {
                        throw new Exception("FOREST ROADS SIMULATION ERROR : During the computing of the flux of wood, site " + currentConnectionPoint + " was not found in the corresponding path that contained " + currentPath.sitesInPath.Count + " sites. This is not normal." + PlugIn.errorToGithub);
                    }
                    sitesTofFlux = currentPath.sitesInPath.GetRange(connectionIndex, (currentPath.sitesInPath.Count - connectionIndex));

                    foreach (Site siteToFlux in sitesTofFlux)
                    {
                        SiteVars.RoadsInLandscape[siteToFlux].timestepWoodFlux += woodFlux;
                    }
                }

                currentConnectionPoint = currentPath.connectionToNext;
                currentPath            = currentPath.nextPath;
            }

            // Ending when we reached a currentPath that is an end

            // Case of micro-paths (1 site), in order to avoid errors.
            if (currentPath.sitesInPath.Count == 1)
            {
                SiteVars.RoadsInLandscape[currentPath.sitesInPath[0]].timestepWoodFlux += woodFlux;
            }
            else
            {
                connectionIndex = currentPath.sitesInPath.IndexOf(currentConnectionPoint);
                if (connectionIndex == -1)
                {
                    throw new Exception("FOREST ROADS SIMULATION ERROR : During the computing of the flux of wood, site " + currentConnectionPoint + " was not found in the corresponding path that contained " + currentPath.sitesInPath.Count + " sites. This is not normal." + PlugIn.errorToGithub);
                }
                sitesTofFlux = currentPath.sitesInPath.GetRange(connectionIndex, (currentPath.sitesInPath.Count - connectionIndex));

                foreach (Site siteToFlux in sitesTofFlux)
                {
                    SiteVars.RoadsInLandscape[siteToFlux].timestepWoodFlux += woodFlux;
                }
            }
        }
Exemplo n.º 2
0
        // Constructor for the end of the dijkstra search, when we have found a connection to another path
        public FluxPath(List <Site> sitesInPath, Site connectionToNext)
        {
            if (sitesInPath.Count == 0)
            {
                throw new Exception("FOREST ROADS SIMULATION ERROR : Tried to create a path with no sites in it." + PlugIn.errorToGithub);
            }

            // We create this path properly
            this.sitesInPath      = sitesInPath;
            this.connectionToNext = connectionToNext;
            this.nextPath         = RoadNetwork.fluxPathDictionary[connectionToNext];
            this.isAnEnd          = false;
            RoadNetwork.fluxPathCatalogue.Add(this);
            foreach (Site site in sitesInPath)
            {
                RoadNetwork.fluxPathDictionary[site] = this;
            }
        }
        /// <summary>
        /// Finds the least cost path from roads to roads to a exit point for the wood in the landscape, and add the given wood flux to every road visited.
        /// Warning : The starting site must not be inside an existing fluxpath.
        /// </summary>
        /// /// <param name="ModelCore">
        /// The model's core framework.
        /// </param>
        /// /// <param name="startingSite">
        /// The starting site of the search.
        /// </param>
        /// /// <param name="Woodflux">
        /// The flux of wood that is going to flow to the exit point.
        /// </param>
        public static void DijkstraWoodFlux(ICore ModelCore, Site startingSite, double woodFlux)
        {
            // We initialize the frontier and everything else
            Priority_Queue.SimplePriorityQueue <Site> frontier = new Priority_Queue.SimplePriorityQueue <Site>();
            Dictionary <Site, Site>   predecessors             = new Dictionary <Site, Site>();
            Dictionary <Site, double> costSoFar = new Dictionary <Site, Double>();
            HashSet <Site>            isClosed  = new HashSet <Site>();
            bool haveWeFoundARoadToConnectTo    = false;

            costSoFar[startingSite] = 0;
            frontier.Enqueue(startingSite, 0);
            Site   siteToClose;
            double newDistanceToStart;

            // Useless assignement to please the gods of C#
            Site arrivalSite = startingSite;

            // First, we got to check the possibility that the starting site IS the arrival site. This is possible in very rare situations,
            // as the given starting site can be an exit point...That is not surounded by roads. If that happens, the dijkstra will not be able to
            // open any neighbors, and will fail. Again, very rare, but still important.
            if (RoadNetwork.fluxPathDictionary.ContainsKey(startingSite) || SiteVars.RoadsInLandscape[startingSite].IsAPlaceForTheWoodToGo)
            {
                haveWeFoundARoadToConnectTo = true; goto End;
            }

            // We loop until the list is empty
            while (frontier.Count > 0)
            {
                // We take the site with the lowest distance to start.
                siteToClose = frontier.Dequeue();

                // We look at each of its neighbours, but only those with roads on them.
                foreach (Site neighbourToOpen in MapManager.GetNeighbouringSitesWithRoads(siteToClose))
                {
                    // We don't consider the neighbour if it is closed
                    if (!isClosed.Contains(neighbourToOpen))
                    {
                        // We get the value of the distance to start by using the current node to close, which is just an addition of the distance to the start
                        // from the node to close + the cost between it and the neighbor.
                        newDistanceToStart = costSoFar[siteToClose] + MapManager.CostOfTransition(siteToClose, neighbourToOpen);

                        // If the node isn't opened yet, or if it is opened and going to start throught the current node to close is closer; then,
                        // this node to close will become its predecessor, and its distance to start will become this one.
                        if (!costSoFar.ContainsKey(neighbourToOpen) || newDistanceToStart < costSoFar[neighbourToOpen])
                        {
                            costSoFar[neighbourToOpen]    = newDistanceToStart;
                            predecessors[neighbourToOpen] = siteToClose;
                            // Case of the node not being opened
                            if (!frontier.Contains(neighbourToOpen))
                            {
                                frontier.Enqueue(neighbourToOpen, (float)costSoFar[neighbourToOpen]);
                            }
                            // Case of the node being already open
                            else
                            {
                                frontier.UpdatePriority(neighbourToOpen, (float)costSoFar[neighbourToOpen]);
                            }
                        }

                        // We check if the neighbour is a exit node for the wood. If that's the case, search is other.
                        if (RoadNetwork.fluxPathDictionary.ContainsKey(neighbourToOpen) || SiteVars.RoadsInLandscape[neighbourToOpen].IsAPlaceForTheWoodToGo)
                        {
                            arrivalSite = neighbourToOpen; haveWeFoundARoadToConnectTo = true; goto End;
                        }
                    }
                }
                // Now that we have checked all of its neighbours, we can close the current node.
                isClosed.Add(siteToClose);
            }

End:
            // ModelCore.UI.WriteLine("Dijkstra search for wood flux is over.");

            // If we're out of the loop, that means that the search is over. If it was successfull before we ran out of neighbours to check,
            // We can now retrieve the list of the sites that
            // are the least cost path, and make sure that all of these site now have a road constructed on them, and that it is
            // indicated as connected to a place where we can make wood go.
            if (haveWeFoundARoadToConnectTo)
            {
                // If we found a fluxPath to connect to, we create a new one starting from the starting site, and stopping just before the arrival (which is our connection site to the fluxpath, and thus already belongs to a fluxpath)
                if (RoadNetwork.fluxPathDictionary.ContainsKey(arrivalSite))
                {
                    List <Site> listOfSitesInLeastCostPath = MapManager.FindPathToStart(startingSite, arrivalSite, predecessors);

                    // We have to reverse the list, because we want to go from the harvested zones to the connection point, and not the opposite.
                    listOfSitesInLeastCostPath.Reverse();

                    // We don't put the arrival site in the fluxpath, because it is part of another fluxpath.
                    listOfSitesInLeastCostPath.Remove(arrivalSite);

                    FluxPath newFluxPath = new FluxPath(listOfSitesInLeastCostPath, arrivalSite);

                    // Now that this new path is created, we flux the wood.
                    newFluxPath.FluxPathFromSite(startingSite, woodFlux);
                }
                // Else, if we didn't found a fluxPath to connect to but an exit point for the wood, we create a new "isAnEnd" path.
                else
                {
                    List <Site> listOfSitesInLeastCostPath = MapManager.FindPathToStart(startingSite, arrivalSite, predecessors);

                    // We have to reverse the list, because we want to go from the harvested zones to the exit point, and not the opposite.
                    listOfSitesInLeastCostPath.Reverse();

                    FluxPath newFluxPathIsAnEnd = new FluxPath(listOfSitesInLeastCostPath);

                    // Then, we flux the wood down this path.
                    newFluxPathIsAnEnd.FluxPathFromSite(startingSite, woodFlux);
                }
            }
            else
            {
                throw new Exception("FOREST ROADS SIMULATION ERROR : A Dijkstra search wasn't able to flux the wood from site " + startingSite.Location + " to any exit point. This isn't supposed to happen. Please check the output raster containg the road network for the current timestep (" + ModelCore.CurrentTime + " years) and see if a road is interrupted somewhere." + PlugIn.errorToGithub);
            }
        }