/// <summary>
        /// This function initialize the road network by checking if every road is connected one way or another to a place where the harvested wood can flow to (sawmill, etc.). If not, it construct the road.
        /// </summary>
        /// /// <param name="ModelCore">
        /// The model's core framework.
        /// </param>
        /// /// <param name="heuristic">
        /// The heuristic used to determine in which order the roads must be built by the least-cost path algorithm.
        /// </param>
        public static void Initialize(ICore ModelCore, string heuristic)
        {
            // We get all of the sites with a road on it
            List <Site> listOfSitesWithRoads = MapManager.GetSitesWithRoads(ModelCore);

            PlugIn.ModelCore.UI.WriteLine(listOfSitesWithRoads.Count + " sites with a road on them have been detected.");

            // We check wich ones are connected to an exit point
            ModelCore.UI.WriteLine("   Looking to see if the roads can go to a exit point (sawmill, main road network)...");
            List <Site> listOfSitesThatCantConnect = UpdateConnectionToExitPointStatus();

            // If there were sites that we couldn't not connect, we throw a warning the user
            if (listOfSitesThatCantConnect.Count != 0)
            {
                ModelCore.UI.WriteLine("   FOREST ROADS SIMULATION WARNING : Roads that can't be connected to exit points (e.g. sawmills or main road network) have been detected in the input map.");
                ModelCore.UI.WriteLine("   The extension will now try to create roads to link those roads that are not connected to places where the harvest wood can flow.");
                PlugIn.ModelCore.UI.WriteLine(listOfSitesThatCantConnect.Count + " sites are in need of a connection to an exit point.");

                ModelCore.UI.WriteLine("   Shuffling list of not connected sites with roads on them...");

                // Then, we shuffle the list according to the heuristic given in the .txt parameter file.
                listOfSitesThatCantConnect = MapManager.ShuffleAccordingToHeuristic(ModelCore, listOfSitesThatCantConnect, heuristic);

                ModelCore.UI.WriteLine("   Building missing roads...");
                var progressBar = PlugIn.ModelCore.UI.CreateProgressMeter(listOfSitesThatCantConnect.Count);


                foreach (Site site in listOfSitesThatCantConnect)
                {
                    // If the site has been updated and connected, no need to look at him.
                    if (!SiteVars.RoadsInLandscape[site].isConnectedToSawMill)
                    {
                        // ModelCore.UI.WriteLine("   Getting the connected neighbours...");
                        // Now, we get all of the roads that are connected to this one (and, implicitly, in need of being connected too)
                        List <Site> sitesConnectedToTheLonelySite = MapManager.GetAllConnectedRoads(site);

                        // ModelCore.UI.WriteLine("   Building the missing road...");
                        // We create a new road that will connect the given site to a road that is connected to a sawmill
                        DijkstraSearch.DijkstraLeastCostPathToClosestConnectedRoad(ModelCore, site, true);

                        // Now that it is connected, all of its connected neighbours will become automatically connected too.
                        foreach (Site connectedSite in sitesConnectedToTheLonelySite)
                        {
                            SiteVars.RoadsInLandscape[connectedSite].isConnectedToSawMill = true;
                        }
                    }
                    progressBar.IncrementWorkDone(1);
                }
            }
            // All the sites are now connected. Initialization of the road network is thus complete.
            ModelCore.UI.WriteLine("   Initialization of the road network is now complete.");
        }
Exemplo n.º 2
0
        // Function called at every time step where the extension is activated.
        // Contains the effects of the extension on the landscape.
        public override void Run()
        {
            // We give a warning back to the user if no harvest extension is detected
            if (!this.harvestExtensionDetected)
            {
                modelCore.UI.WriteLine("   FOREST ROAD SIMULATION WARNING : NO HARVEST EXTENSION DETECTED");
                modelCore.UI.WriteLine("   Without a harvest extension, no roads will be created by this extension. Please include a harvest extension in your scenario, or this extension will be quite useless.");
            }

            // If not, we do what the extension have to do at its timestep : for each recently harvested site, we'll try to build a road that lead to it if needed.
            else if (this.harvestExtensionDetected)
            {
                // 1) We age all of the roads in the landscape, if aging is simulated. Those that are too old will be considered destroyed.
                List <Site> listOfSitesWithRoads;
                if (parameters.SimulationOfRoadAging)
                {
                    listOfSitesWithRoads = MapManager.GetSitesWithRoads(ModelCore);

                    foreach (Site siteWithRoad in listOfSitesWithRoads)
                    {
                        SiteVars.RoadsInLandscape[siteWithRoad].agingTheRoad(siteWithRoad);
                    }
                    // 2) We update the status of all the roads concerning their connection to an exit point (sawmill or main road network); so that the pathfinding algorithms can now when to stop afterward.
                    ModelCore.UI.WriteLine("   Looking to see if the roads can go to a exit point (sawmill, main road network)...");
                    listOfSitesWithRoads = MapManager.GetSitesWithRoads(ModelCore);
                    RoadNetwork.UpdateConnectionToExitPointStatus();
                }


                // 3) We get all of the sites for which a road must be constructed
                modelCore.UI.WriteLine("  Getting sites recently harvested...");
                List <Site> listOfHarvestedSites = MapManager.GetAllRecentlyHarvestedSites(ModelCore, Timestep);

                // 4) We shuffle the list according to the heuristic given by the user.
                modelCore.UI.WriteLine("  Shuffling sites according to the heuristic...");
                listOfHarvestedSites = MapManager.ShuffleAccordingToHeuristic(ModelCore, listOfHarvestedSites, parameters.HeuristicForNetworkConstruction);

                // 5) We reset the wood flux objects and data for the current timestep, if wood flux is sumlated
                if (parameters.SimulationOfWoodFlux)
                {
                    modelCore.UI.WriteLine("  Reseting wood flux data...");
                    RoadNetwork.RestTimestepWoodFluxData();
                }

                // 6) We initialize some UI elements because this step takes time, and set the cost of construction/repairs at this timestep to 0.
                modelCore.UI.WriteLine("  Number of recently harvested sites : " + listOfHarvestedSites.Count);
                modelCore.UI.WriteLine("  Generating roads to harvested sites...");
                var progressBar = modelCore.UI.CreateProgressMeter(listOfHarvestedSites.Count);
                var watch       = System.Diagnostics.Stopwatch.StartNew();
                int roadConstructedAtThisTimestep = 0;
                RoadNetwork.costOfConstructionAndRepairsAtTimestep = 0;

                // 7) We construct the roads to each harvested site
                foreach (Site harvestedSite in listOfHarvestedSites)
                {
                    // We construct the road only if the cell is at more than the given skidding distance by the user from an existing road.
                    if (!MapManager.IsThereANearbyRoad(skiddingNeighborhood, harvestedSite))
                    {
                        // If the looping behavior is activated, we will check if we should do a loop.
                        if (parameters.LoopingBehavior)
                        {
                            // To create a normal road if one of the conditions fail
                            bool conditionsForLoop = true;

                            // We don't create a loop if there are roads that are too close
                            int roadsInSmallNeighborhood = MapManager.HowManyRoadsNearby(minLoopingNeighborhood, harvestedSite);
                            if (roadsInSmallNeighborhood > 0)
                            {
                                conditionsForLoop = false;
                            }
                            else
                            {
                                // We don't create a loop if there are no roads close enough, at least 2 to make a loop
                                int roadsInLargeNeighborhood = MapManager.HowManyRoadsNearby(maxLoopingNeighborhood, harvestedSite);
                                if (roadsInLargeNeighborhood < 2)
                                {
                                    conditionsForLoop = false;
                                }
                                else
                                {
                                    // We don't create a loop if there are too many roads nearby
                                    double percentageOfRoadsAround = (double)((double)roadsInLargeNeighborhood * 100.0) / (double)maxLoopingNeighborhood.Count;
                                    if (percentageOfRoadsAround > parameters.LoopingMaxPercentageOfRoads)
                                    {
                                        conditionsForLoop = false;
                                    }
                                    else
                                    {
                                        // Now, we let the dijkstra function for the loop try to create a loop.
                                        // However, if the loop is too costly to build or if the probability isn't right, the loop will not be constructed (see inside this function)
                                        int numberOfRoadsCreated = DijkstraSearch.DijkstraLeastCostPathWithLooping(ModelCore, harvestedSite, minLoopingNeighborhood, parameters.LoopingMaxCost);
                                        roadConstructedAtThisTimestep += numberOfRoadsCreated;
                                    }
                                }
                            }
                            // If one of the conditions to make the loop has failed, we create a normal road.
                            if (!conditionsForLoop)
                            {
                                DijkstraSearch.DijkstraLeastCostPathToClosestConnectedRoad(ModelCore, harvestedSite);
                                roadConstructedAtThisTimestep++;
                            }
                        }
                        // If no looping behavior, we just create the least-cost road to the site.
                        else
                        {
                            DijkstraSearch.DijkstraLeastCostPathToClosestConnectedRoad(ModelCore, harvestedSite);
                            roadConstructedAtThisTimestep++;
                        }
                    }
                    progressBar.IncrementWorkDone(1);
                }
                watch.Stop();
                modelCore.UI.WriteLine("   At this timestep, " + roadConstructedAtThisTimestep + " roads were built");
                modelCore.UI.WriteLine("   The construction took " + (watch.ElapsedMilliseconds / 1000) + " seconds.\n");

                // 8) If woodflux is simulated, We add the woodflux from the harvested area to the closest road, and we then used a dijkstra
                // search that only goes through roads in order to reach an exit point for the wood. Every road used will see its flux value
                // for the timestep augment by one. The quantity of woodflux is based on the number of cohorts harvested in the cell.
                if (parameters.SimulationOfWoodFlux)
                {
                    modelCore.UI.WriteLine("  Fluxing the wood to exit points...");

                    progressBar = modelCore.UI.CreateProgressMeter(listOfHarvestedSites.Count);
                    int sitesFluxedAtThisTimestep = 0;
                    watch.Restart();
                    ISiteVar <int> numberOfCohortsDamaged = modelCore.GetSiteVar <int>("Harvest.CohortsDamaged");

                    foreach (Site harvestedSite in listOfHarvestedSites)
                    {
                        int  siteFlux            = numberOfCohortsDamaged[harvestedSite];
                        Site siteWithClosestRoad = MapManager.GetClosestSiteWithRoad(skiddingNeighborhood, harvestedSite);

                        // Case of the siteWithClosestRoad being a fluxpath : we just flux this path.
                        if (RoadNetwork.fluxPathDictionary.ContainsKey(siteWithClosestRoad))
                        {
                            RoadNetwork.fluxPathDictionary[siteWithClosestRoad].FluxPathFromSite(siteWithClosestRoad, siteFlux);
                        }
                        // If not, we create a flux path.
                        else
                        {
                            DijkstraSearch.DijkstraWoodFlux(PlugIn.ModelCore, siteWithClosestRoad, siteFlux);
                        }
                        sitesFluxedAtThisTimestep++;
                        progressBar.IncrementWorkDone(1);
                    }
                    modelCore.UI.WriteLine("   At this timestep, the wood of " + sitesFluxedAtThisTimestep + " sites was fluxed.");
                    modelCore.UI.WriteLine("   The fluxing took " + (watch.ElapsedMilliseconds / 1000) + " seconds.\n");
                }

                // 9) We finish by upgrading the types of the roads if they have to be according to the woodflux for the timestep, and the parameters given by the user, if woodflux is simulated.
                if (parameters.SimulationOfWoodFlux)
                {
                    listOfSitesWithRoads = MapManager.GetSitesWithRoads(ModelCore);

                    foreach (Site siteWithRoad in listOfSitesWithRoads)
                    {
                        SiteVars.RoadsInLandscape[siteWithRoad].UpdateAccordingToWoodFlux(siteWithRoad);
                    }
                }

                // 10) We write the output maps
                MapManager.WriteMap(parameters.OutputsOfRoadNetworkMaps, modelCore);
                if (parameters.SimulationOfWoodFlux)
                {
                    MapManager.WriteMap(parameters.OutputsOfRoadNetworkMaps, modelCore, "WoodFlux");
                }

                // 11) We write the log, and we're done for this timestep.
                roadConstructionLog.Clear();
                RoadLog roadLog = new RoadLog();
                roadLog.Timestep = modelCore.CurrentTime;
                roadLog.NumberOfHarvestedSitesToConnect = listOfHarvestedSites.Count;
                roadLog.NumberOfRoadsConstructed        = roadConstructedAtThisTimestep;
                roadLog.TimeTaken = (int)watch.ElapsedMilliseconds / (1000 * 60);
                roadLog.CostOfConstructionAndRepairs = RoadNetwork.costOfConstructionAndRepairsAtTimestep;
                roadConstructionLog.AddObject(roadLog);
                roadConstructionLog.WriteToFile();
            } // End of if harvest extension detected
        }     // End of run function