Purpose
Illustrates how to select in a list an element that optimise a given function.
Formulation
- Replace the parameter repair_time by a parameter repair_capacity_step which is equal to 10. This parameter represents the number of meters of road that can be repaired of one destruction unit per simulation step.
- Every simulation step, the road agents that are the most destroyed are repaired. the process is the following: the road agent with the highest destruction_coeff is selected. If the repair capacity is high enough ("repair_capacity (initialy equals to repair_capacity_step) > (road length * (destruction_coeff - 1)"), the destruction_coeff of the road is set to "1", and the repair_capacity is updated ("repair_capacity = repair_capacity - road length * (destruction_coeff - 1)"). Another road is then selected, on so on. If the repair capacity is not high enough, the road is partially repaired ("destruction_coeff = destruction_coeff - repair_capacity / road length)".
Model
Paremeters
We have to add a new parameter: repair_capacity_step.
<global>
...
<var type="float" name="repair_capacity_step" init="10" parameter="Per step, number of meters of road that can be repaired of one destruction unit" category="Road" />
...
</global>Road repairing
We have to add a reflex method in the global section that is triggered every simulation step. We use the attribute perimeter contains in the situated skill to compute the road length. Note that we remove the update_graph global variable as now the graph is updated at each simulation step.
<global>
...
<reflex name="repair_road">
<let name="repair_capacity" value="repair_capacity_step" />
<loop while="repair_capacity > 0">
<let type="road" name="the_road_to_repair" value="(list road) with_max_of (each.destruction_coeff)" />
<let type="float" name="road_requirement" value="the_road_to_repair.perimeter * (the_road_to_repair.destruction_coeff - 1)" />
<if condition="road_requirement = 0">
<set name="repair_capacity" value="0" />
<else>
<if condition="road_requirement < repair_capacity">
<ask target="the_road_to_repair">
<set name="destruction_coeff" value="1" />
</ask>
<set name="repair_capacity" value="repair_capacity - road_requirement" />
<else>
<ask target="the_road_to_repair">
<set name="destruction_coeff" value="destruction_coeff - (repair_capacity / perimeter)" />
</ask>
<set name="repair_capacity" value="0" />
</else>
</if>
</else>
</if>
</loop>
</reflex>
...
</global>Complete model
<model name="tutorial_gis_city_traffic">
<global>
<var type="string" name="shape_file_buildings" init="'../gis/building.shp'" parameter="Shapefile for the buildings:" category="GIS" />
<var type="string" name="shape_file_roads" init="'../gis/road.shp'" parameter="Shapefile for the roads:" category="GIS" />
<var type="string" name="shape_file_bounds" init="'../gis/bounds.shp'" parameter="Shapefile for the bounds:" category="GIS" />
<var type="int" name="nb_people" init="100" parameter="Number of people agents" category="People" />
<var type="int" name="day_time" value="time%144" />
<var type="int" name="min_work_start" init="36" parameter="Earliest hour to start work" category="People" />
<var type="int" name="max_work_start" init="60" parameter="Latest hour to start work" category="People" />
<var type="int" name="min_work_end" init="84" parameter="Earliest hour to end work" category="People" />
<var type="int" name="max_work_end" init="132" parameter="Latest hour to end work" category="People" />
<var type="float" name="min_speed" init="50" parameter="minimal speed" category="People" />
<var type="float" name="max_speed" init="100" parameter="maximal speed" category="People" />
<var type="float" name="destroy" init="0.02" parameter="Value of destruction when a people agent takes a road" category="Road" />
<var type="float" name="repair_capacity_step" init="10" parameter="Per step, number of meters of road that can be repaired of one destruction unit" category="Road" />
<init>
<create species="building" from="shape_file_buildings" with="[type::read 'NATURE']" return="the_buildings">
<if condition="type='Industrial'">
<set name="color" value="rgb 'blue'"/>
</if>
</create>
<create species="road" from="shape_file_roads" return="the_roads"/>
<do action="compute_graph">
<arg name="network" value="the_roads"/>
<arg name="name" value="'road_network'"/>
<arg name="weights" value="'destruction_coeff'"/>
</do>
<let type="list" name="residential_buildings" value="the_buildings where (each.type='Residential')"/>
<let type="list" name="industrial_buildings" value="the_buildings where (each.type='Industrial')"/>
<let type="float" name="area_rb_tot" value="self area_sum [agents::residential_buildings]"/>
<ask target="residential_buildings">
<set name="proba_select" value="area / area_rb_tot"/>
</ask>
<let type="float" name="area_ib_tot" value="self area_sum [agents::industrial_buildings]"/>
<ask target="industrial_buildings">
<set name="proba_select" value="area / area_ib_tot"/>
</ask>
<create species="people" number="nb_people">
<set name="speed" value="min_speed + rnd (max_speed - min_speed)"/>
<set name="start_work" value="min_work_start + rnd (max_work_start - min_work_start)"/>
<set name="end_work" value="min_work_end + rnd (max_work_end - min_work_end)"/>
<let type="float" name="rand_nb" value="rnd 1000 / 1000"/>
<let type="float" name="proba_sum" value="0"/>
<loop over="residential_buildings" var="the_rb">
<set name="proba_sum" value="proba_sum + the_rb.proba_select"/>
<if condition="(living_place = nil) and (rand_nb < proba_sum)">
<set name="living_place" value="the_rb"/>
</if>
</loop>
<set name="rand_nb" value="rnd 1000 / 1000"/>
<set name="proba_sum" value="0"/>
<loop over="industrial_buildings" var="the_ib">
<set name="proba_sum" value="proba_sum + the_ib.proba_select"/>
<if condition="(working_place = nil) and (rand_nb < proba_sum)">
<set name="working_place" value="the_ib"/>
</if>
</loop>
<set name="location" value="self place_in [agent::living_place]"/>
</create>
</init>
<reflex name="repair_road">
<let name="repair_capacity" value="repair_capacity_step" />
<loop while="repair_capacity > 0">
<let type="road" name="the_road_to_repair" value="(list road) with_max_of (each.destruction_coeff)" />
<let type="float" name="road_requirement" value="the_road_to_repair.perimeter * (the_road_to_repair.destruction_coeff - 1)" />
<if condition="road_requirement = 0">
<set name="repair_capacity" value="0" />
<else>
<if condition="road_requirement < repair_capacity">
<ask target="the_road_to_repair">
<set name="destruction_coeff" value="1" />
</ask>
<set name="repair_capacity" value="repair_capacity - road_requirement" />
<else>
<ask target="the_road_to_repair">
<set name="destruction_coeff" value="destruction_coeff - (repair_capacity / perimeter)" />
</ask>
<set name="repair_capacity" value="0" />
</else>
</if>
</else>
</if>
</loop>
</reflex>
<reflex name="update_graph">
<do action="update_graph">
<arg name="network" value="list road" />
<arg name="graph_name" value="'road_network'" />
<arg name="weights" value="'destruction_coeff'" />
</do>
</reflex>
</global>
<entities>
<species name="building" skills="situated">
<var type="string" name="type"/>
<var type="rgb" name="color" init="rgb 'gray' " />
<var type="float" name="proba_select"/>
<aspect name="base">
<draw shape="geometry" color="color"/>
</aspect>
</species>
<species name="road" skills="situated">
<var type="float" name="destruction_coeff" init="1"/>
<var type="rgb" name="color" value="[min [255, 255*(destruction_coeff - 1)],max [0, 255 - (255*(destruction_coeff - 1))],0]" />
<aspect name="base">
<draw shape="geometry" color="color"/>
</aspect>
</species>
<species name="people" skills="moving">
<var type="rgb" name="color" init="rgb 'yellow'" />
<var type="building" name="living_place" init="nil"/>
<var type="building" name="working_place" init="nil"/>
<var type="int" name="start_work"/>
<var type="int" name="end_work"/>
<var type="string" name="objectif"/>
<var type="point" name="the_target" init="nil"/>
<var type="list" of="road" name="path" />
<aspect name="base">
<draw shape="geometry" color="color" size="10"/>
</aspect>
<reflex name="time_to_work" when="day_time = start_work">
<set name="objectif" value="'working'"/>
<set name="the_target" value="self place_in [agent::working_place]"/>
<set name="path" value="self path_graph [graph_name::'road_network', target::the_target]" />
</reflex>
<reflex name="time_to_go_home" when="day_time = end_work">
<set name="objectif" value="'go home'"/>
<set name="the_target" value="self place_in [agent::living_place]"/>
<set name="path" value="self path_graph [graph_name::'road_network', target::the_target]" />
</reflex>
<reflex name="move" when="the_target != nil">
<do action="goto">
<arg name="target" value="the_target" />
<arg name="graph_name" value="'road_network'" />
</do>
<if condition="the_target = location">
<set name="the_target" value="nil" />
<ask target="path">
<set name="destruction_coeff" value="destroy + destruction_coeff" />
</ask>
</if>
</reflex>
</species>
</entities>
<environment bounds="shape_file_bounds"/>
<output>
<display name="city_display" refresh_every="1">
<species name="building" aspect="base"/>
<species name="road" aspect="base"/>
<species name="people" aspect="base"/>
</display>
<display name="chart_display" refresh_every="10">
<chart type="series" name="Road Status" background="rgb 'lightGray'" size="{0.9, 0.4}" position="{0.05, 0.05}">
<data name="Mean road destruction" value="mean ((list road) collect each.destruction_coeff)" style="line" color="rgb 'green'" />
<data name="Max road destruction" value="(list road) max_of (each.destruction_coeff)" style="line" color="rgb 'red'" />
</chart>
<chart type="pie" name="People Objectif" background="rgb 'lightGray'" style="exploded" size="{0.9, 0.4}" position="{0.05, 0.55}">
<data name="Working" value="length ((list people) where (each.objectif='working'))" color="rgb 'green'"/>
<data name="Staying home" value="length ((list people) where (each.objectif='go home'))" color="rgb 'blue'"/>
</chart>
</display>
</output>
</model>