-
Notifications
You must be signed in to change notification settings - Fork 1
/
CHIME.nlogo
11831 lines (11101 loc) · 452 KB
/
CHIME.nlogo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;<<<<<<< HEAD
;;;-------DESCRIPTION OF PROCEDURES USED IN THIS AGENT-BASED-MODEL-----------------------------------------------------------------------------------
;Setup-Everything: Loads GIS files, loads hurricane best-track information, loads forecasts, sets the scale of the model world, generates the storm, and populates the model with agents (randomly distributed, based on population density, or based on census data). Assigns social networks to each citizen.
;1. Load-GIS: Displays the region of interest, loads GIS data (i.e., elevation; population density; counties; county¬¬ seats). Determines which patches are land and ocean. Ocean patches are designated where the elevation data has “no data” values.
;2. Load-Hurricane: Loads hurricane best track data. Defines a list called best-track-data that stores the best track data.
;3. Load-Forecasts: Loads full-worded forecast advisories from the National Hurricane Center and stores data in a list called forecast-matrix.
;4. Load-Forecasts-New: Loads a .csv file of forecast advisories and stores data in a list called forecast-matrix.
;1. Calculate-Advisory-Time: Converts times from the forecast advisory file to the date and hour.
;2. Calculate-Coordinates: Reports lat-lon coordinates of the storm center in model space.
;5. Setup: Sets the scale of the model world, generates the storm, and populates the model with agents (randomly distributed, based on population density, or based on census data). Assigns social networks to each citizen.
;1. Generate-Storm: Translates the best track data to the model grid and interpolates storm characteristics to 1-hourly data. Currently, brute-force interpolation is used to convert 6-hourly data to 1-hourly data. Draws a line that represents the actual track of the storm.
;1. Calculate-Time-Between-Storm-Info: Calculates the time interal between best track times.
;2. Create-Citizen-Agent-Population: Populates the model with citizens. Sets various attributes for each citizen (i.e., evac-zone, self-trust, trust-authority, networks lists, risk thresholds).
;1. Check-Zone: Determines the evacuation zone of each citizen, which depends on the number of grid points the citizen is away from the coast (i.e., zone “A” is 1.5 grid points from the coast).
;3. Create-Other-Agents: Populates the model with the various breeds of agents other than citizens (i.e., forecasters officials, broadcasters, and aggregators).
;4. Create-Citizen-Agents-From-Census-Tracts: Populates the model with citizens based on census data. Other agents (i.e., forecasters, officials, broadcasters, and aggregators) are populated similarly to create-agents.
;1. Create-More-Cit-Ags-Based-On-Census: Populates the model with more agents based on the census.
;2. Check-For-Swimmers: Moves citizens located at an ocean patch to a land patch.
;3. Add-Census-Factor: Set to true for each citizen that has the census information in their tract (e.g., kids under 18, adults over 65, limited English, use food stamps, no vehicle, no internet). This information is used in the decision-making process to calculate risk parameters.
;4;. Social-Network: Assigns a social network for each citizen. Each citizen is also assigned broadcasters and aggregators.
;Go: This procedure moves the hurricane in the Netlogo interface, forecasters publish new forecasts, broadcasters and aggregators update their forecast, citizens receive the updated forecast and produces a mental model of the storm, officials potentially issue evacuation orders, and citizens evaluate their risk to potentially make protective decisions.
;1. Move-Hurricane: Moves the hurricane symbol in the Netlogo interface.
;2. Past-Forecasts: Forecaster publishes the most recent forecast from forecast-matrix. A new forecast is published every 6 hours.
;3. Publish-New-Mental-Model: Each citizen has a mental model of where they think the hurricane will go and how severe it will be.
;1. Interpolate-Cone: Interpolates the cone of uncertainty (given at 0,12,24,36,48,72,96,120 h) to hourly cone data.
;4. Coastal-Patches-Alerts: Coastal patches diagnose if their patch is within an intensity threshold and distance threshold to issue an alert. If so, the patch communicates with the official to issue an alert.
;5. Issue-Alerts: The official issues an evacuation order after coastal-patches-alerts issues an alert.
;6. Decision-Module: The main Protective Action Decision-Making process called by citizen agents. Citizens check environmental cues, collect and process information, assess risk, assess alternative protective actions, and decide whether to act.
;7. Process-Forecasts: Citizens who have already evacuated just collect information (no DM).
;Not called in code:
;1. Save-Individual-Cit-Ag-Evac-Records
;2. Save-Global-Evac-Statistics
;3. Save-View: Saves a .png of the Netlogo model space for each time step.
;Buttons but not called in the code:
;1. Show-Links: Creates lines that show which citizens are in which social network.
; Declare netlogo extensions needed for the model
extensions [gis profiler csv nw]
; Declare global variables
globals [
clock ; keeps track of model time, same as ticks, but in days and hours
current-date ; used to track the numerical date and track when a new day occurs for county evacuations
county-seats ; import dataset from GIS - county seats
county-seat-list ; list of county seats
best-track-data ; holds matrix of hurricane track/intensity/size etc
hurricane-coords-best-track ; holds x-y coordinates of the hurricane best track information in the model
re0-0 ; center of the Netlogo world used when translating real-world coordinates to model-space coordinates
forecast-matrix ; holds the most recent forecast generated by the Forecaster agent
scale ; re-scales the modeled world to match the real world (n mi per degree)
grid-cell-size ; takes GIS world and converts grid cells to degrees
tract-points ; record the locations of census tracts
using-hpc? ; used to choose between two file paths one set is used when running the model on a HPC
which-region? ; determines which GIS files to load - was previously located in the GUI
land-patches ; patchset of land patches
ocean-patches ; patchset of ocean patches
coastal-patches ; patchset of ocean patches that are located along coastal areas and have a county number
hurricane-has-passed?
; These variables need to be checked SMB*
orang ; agentset for tracking evacuees in end-sim stats
all ; agentset for tracking all cit-ags in end-sim stats
really-affected ; agentset for tracking affected cit-ags in end-sim stats
data-dump ; holds agent data when exporting the whole simulation
output-filename
evac-filename
watching ; a single agent identified to track decisions
risk-total ; for display - to track watching's total risk
risk-funct ; for display - to track watching's risk function
risk-error ; for display - to track watching's risk error
risk-orders ; for display - to track watching's evacuation orders
risk-env ; for display - to track watching's environmental cues
risk-surge ; for display - to track watching's surge risk
county-evacuation-list ; used to record daily evacuation info for counties
]
;; Declare agent breeds
breed [hurricanes hurricane] ; hurricane, for display purposes only
breed [citizen-agents citizen-agent] ; citizen agents
breed [officials official] ; public officials, emergency managers
breed [forecasters forecaster] ; forecasters
breed [broadcasters broadcaster] ; broadcasters
breed [aggregators aggregator] ; aggregators
breed [forcstxs forcstx] ; visualizes forecast cone/circles
breed [drawers drawer] ; visualizes the forecast as a cone
breed [tracts tract] ; census tract points
;; Declare agent-specific variables
patches-own [
density ; population density (from GIS)
elev ; elevation (from GIS)
county ; county
alerts ; whether or not the county official has issued evacuation orders
land? ; true or false variable for patches
]
hurricanes-own [ ]
citizen-agents-own [
environmental-cues ; environmental cues (based on distance from storm)
evac-zone ; agent's perceived risk zone (based on distance from the coast)
distance-to-storm-track
decision-module-interval ; sets the frequency that agents run the risk-decision module
previous-dm-interval ; agent remembers feedback1 in case of evacuation (reverts to original value)
decision-module-turn ; helps agents determine when it's their turn to run the risk-decision module
my-network-list ; agent's social network (modified preferential attachment, see below)
broadcaster-list ; the set of broadcasters linked to the agent
aggregator-list ; the set of aggregators linked to the agent
forecast-options ; list of forecasts available to the agent
interpreted-forecast ; an agent's interpretation of the forecast
self-trust ; sets confidence in own interpretation of storm forecast
memory ; holds the agent's intepretation of the forecast for use in next time through risk-decision loop
trust-authority ; sets confidence in evac orders from officials / SB 12.3.19 - this looks unused
when-evac-1st-ordered ; variable for recording when an evacuation is first ordered
risk-watcher ; used in plotting risk
risk-life-threshold ; characteristic sets threshold for determining risk to life
risk-property-threshold ; characteristic sets threshold for determining risk to property
info-up ; characteristic sets threshold for determining to collect more info (changes feedback1 loop)
info-down ; characteristic sets threshold for determining to delay collecting more info (changes feedback1 loop)
risk-estimate ; keeps a list of risk calculations
completed ; keeps a list of previous decisons (and when they were made)
risk-packet ; List the final risk, followed by the three main inputs to the risk function (forecast info, evac orders, env cues)
;; Census Tract Information
tract-information ; information from a census tract
my-tract-population ; population from census tract
my-tract-household ; total number of households from a census tract
census-tract-number ; number assigned to each census tract - assigned by the US government
kids-under-18? ; records if the census tract has kids under 18
adults-over-65? ; records if the census tract has adults over 65
limited-english? ; records if the census tract has limited english speakers
food-stamps? ; records if the census tract uses food stamps
no-vehicle? ; records if the census tract does not have a vehicle
no-internet? ; records if the census tract has access to interent
county-fips ; records the county FIPS number. Multiple census tracts may have the same number.
risk-forecast ;forecast risk (weight is included)
risk-official-orders ;evacuation order risk (weight is included)
risk-environmental-cues ;environmental cue risk (weight is included)
final-risk-assesment ;total risk ( risk-forecast + risk-official-orders + risk-environmental-cues )
evacuated? ;has the citizen evacuated
evac-day ;evacuation date
]
officials-own [
orders ; keeps track of whether the official has issued evacuation orders
distance-to-track ; distance from the storm track (actual
county-id ; sets the county of the official (from GIS)
when-issued ; tracks when evacuation orders were issued
]
forecasters-own [current-forecast] ; current forecast (set from the read-in historical forecasts, usually)
broadcasters-own [ broadcast ] ; current broadcast (interpreted from the forecast)
aggregators-own [ info ] ; current info (interpreted from the forecast, same as the broadcasters...)
forcstxs-own [ ] ;
drawers-own [ cone-size ] ; stores the cone size at the relevant hour (for drawing only)
;; MODEL PROCEDURES
;; Setup calls a handfull of other procedures to build the world and create the agents
;; Usually called from a button on the interface AFTER 1. loading the GIS, 2. loading the storm, and 3. loading the forecasts
to Setup
__clear-all-and-reset-ticks
;;Load Geographic Data Used in the Simulation
Load-GIS
;Where to have the legend displayed on the Netlogo interface
let legend-location where-to-place-legend? ;1=upper-right...2=upper-left...3=lower-left...4=lower-right
if legend-location = "upper-right" [import-drawing "Legend/Legend_Upper_Right.png"]
if legend-location = "upper-left" [import-drawing "Legend/Legend_Upper_Left.png"]
if legend-location = "lower-left" [import-drawing "Legend/Legend_Lower_Left.png"]
if legend-location = "lower-right" [import-drawing "Legend/Legend_Lower_Right.png"]
Load-Hurricane
;; *SMB We can change this once we finish redoing the forecasts
ifelse which-storm? = "IRMA" or which-storm? = "MICHAEL" [ Load-Forecasts-New ] [Load-Forecasts]
Generate-Storm ;; generates the hurricane
set clock list item 3 item ticks hurricane-coords-best-track item 4 item ticks hurricane-coords-best-track ;; defines the clock
set county-evacuation-list []
set hurricane-has-passed? false
;; Setup Agents Based on if the Census Information is Being Used
if use-census-data and which-region? != "FLORIDA"
[print "*** WARNING: Census Data is only available for Florida and will not be used for locations or decisions. ***"]
ifelse use-census-data and which-region? = "FLORIDA"
[Create-Citizen-Agents-From-Census-Tracts];; creates agents based on census data and assigns them
[Create-Citizen-Agent-Population];; creates the agents and distribtues them randomly or based on population density
Create-Other-Agents;; Officials, Broadcasters and Aggregators are created
Social-Network ;; defines the agents' social networks
set risk-total 0 ;; these are all related to the risk function plot on the interface
set risk-funct 0
set risk-error 0
set risk-orders 0
set risk-env 0
set risk-surge 0
set current-date item 0 clock
end
to Go
; INFO: The go procedure calls the various procedures that happen every time step in the model
; VARIABLES MODIFIED:
; PROCEDURES CALLED:
; CALLED BY:
;show ticks
;;The hurricane moves to its historical location based on the time.
;ifelse using-hpc? [][Move-Hurricane] ;; calls procedure to move the hurricane one time step - only show the visualization if using a local computer copy
Move-Hurricane
;; update the forecast
ask forecasters [ set current-forecast Publish-Forecasts ]
let from-forecaster Publish-New-Mental-Model ;; temporary variable to hold the interpreted version of the forecast (publish-new-mental-model is a reporter defined below)
;; officials take forecast info from broadcaster and generate an evacuation order code
Coastal-Patches-Alerts
ask officials with [any? coastal-patches with [county = [[county] of patch-here] of myself]] [ Issue-Alerts ]
;; broadcasters translate and publish forecast
ask broadcasters [ set broadcast from-forecaster ]
;; aggregators are like broadcasters, just translate and publish forecast (1/4 chance of running this code every time step)
ask aggregators [ if random 3 = 2 [ set info from-forecaster] ]
ask citizen-agents[
ifelse empty? completed or item 0 item 0 completed != "evacuate" [
ifelse decision-module-turn < decision-module-interval [ set decision-module-turn decision-module-turn + 1 ]
[
set decision-module-turn 0 ;; update the counter that decides how often to check info
Decision-Module ;; runs the decision model code
]
]
[;; the citizen agents that have evacuated run this code - they update so that their network connections still get up to date info
ifelse decision-module-turn < decision-module-interval [ set decision-module-turn decision-module-turn + 1 ]
[ set decision-module-turn 0 ;; update the counter that decides how often to check info
;Just-Collect-Info
Process-Forecasts
set interpreted-forecast list interpreted-forecast ["no surge forecast"]
]
]
]
ask citizen-agents with [color = black] [set color blue] ;; updates colors
ask citizen-agents with [color = white] [set color blue]
if hurricane-has-passed? = false [ set clock list item 3 item ticks hurricane-coords-best-track item 4 item ticks hurricane-coords-best-track ]
; Save data that records every timestep
if save-agent-data-each-step [let x save-data-timestep] ;behaviorspace requires a reporter but the value reported is not real
if save-images-each-step [ save-view-images ]
if save-county-evacuation-data and current-date != item 0 clock [record-county-evac-data current-date]
set current-date item 0 clock
; Stop the Model and record output that only saves at the end of the model
if which-storm? = "IRMA" and ticks = 132 and using-hpc? = true [ set hurricane-has-passed? true ]
if which-storm? = "CHARLEY_REAL" and ticks = 114 and using-hpc? = true [ set hurricane-has-passed? true ]
if hurricane-has-passed? = true[
if save-county-evacuation-data [record-county-evac-data current-date save-county-evac-data-csv]
set output-filename "test"
if save-global-evacuation-statistics [let x save-global-evac-statistics]
ifelse file-exists? "output" [ set evac-filename word "output/inidividual-evac-statistics_" behaviorspace-run-number ]
[set evac-filename word "inidividual-evac-statistics_" behaviorspace-run-number]
if save-citizen-data-at-end-of-simulation [let x save-individual-cit-ag-evac-records ]
stop
]
tick ;; advances the model one time step
end
to Load-GIS
; INFO: Imports various GIS layers for use by the model
; VARIABLES MODIFIED:
; PROCEDURES CALLED:
; CALLED BY:
__clear-all-and-reset-ticks
if which-storm? = "WILMA" or which-storm? = "WILMA_IDEAL" or which-storm? = "CHARLEY_REAL" or which-storm? = "CHARLEY_IDEAL" or which-storm? = "CHARLEY_BAD" or which-storm? = "IRMA" [set which-region? "FLORIDA"]
if which-storm? = "HARVEY" [set which-region? "GULF"]
if which-storm? = "MICHAEL" [set which-region? "GULF_AND_SE"]
let elevation 0
let density-map 0
let counties 0
if which-region? = "FLORIDA" [
gis:load-coordinate-system "REGION/FLORIDA/GIS/block_density.prj" ; NetLogo needs a prj file to set up the conversion from GIS to netlogo grid
set elevation gis:load-dataset "REGION/FLORIDA/GIS/Florida_SRTM_1215.asc" ; Raster map - SRTM elevation data (downscaled using GRASS GIS)
set density-map gis:load-dataset "REGION/FLORIDA/GIS/Pop_Density_1215.asc" ; Raster map - Population density (calculated by census tract, modified for use w/ GRASS)
set county-seat-list[]
set county-seats gis:load-dataset "REGION/FLORIDA/GIS/county_seats.shp" ; Vector map (points) - location of county seats
set counties gis:load-dataset "REGION/FLORIDA/GIS/counties_1.asc" ; Raster map - counties
foreach but-last gis:feature-list-of county-seats [ ?1 ->
set county-seat-list lput list gis:property-value ?1 "CAT" (gis:location-of (first (first (gis:vertex-lists-of ?1)))) county-seat-list
]]
if which-region? = "GULF" [
gis:load-coordinate-system "REGION/GULF/GIS/block_density.prj" ; NetLogo needs a prj file to set up the conversion from GIS to netlogo grid
set elevation gis:load-dataset "REGION/GULF/GIS/gulf_states_extended.asc" ; Raster map - SRTM elevation data (downscaled using GRASS GIS)
set density-map gis:load-dataset "REGION/GULF/GIS/gulf_states_pop_density_extended.asc" ; Raster map - Population density (calculated by census tract, modified for use w/ GRASS)
set county-seat-list []
set county-seats gis:load-dataset "REGION/GULF/GIS/gulf_states_county_seats.shp" ; Vector map (points) - location of county seats
set counties gis:load-dataset "REGION/GULF/GIS/gulf_states_counties_extended.asc" ; Raster map - counties
foreach but-last gis:feature-list-of county-seats [ ?1 ->
set county-seat-list lput list gis:property-value ?1 "CAT" (gis:location-of (first (first (gis:vertex-lists-of ?1)))) county-seat-list
]]
if which-region? = "GULF_AND_SE" [
;set elevation gis:load-dataset "REGION/GULF_SE/GIS/elevation_reduced_by2.asc" ; Raster map - SRTM elevation data (downscaled by a factor of 2 using QGIS)
set elevation gis:load-dataset "REGION/GULF_SE/GIS/se_elevation.asc" ; Raster map - SRTM elevation data
gis:set-world-envelope-ds gis:envelope-of elevation
set density-map gis:load-dataset "REGION/GULF_SE/GIS/pop_density.asc" ; Raster map - Population density (calculated by census tract (downscaled by a factor of 3 using QGIS)
set county-seat-list []
set counties gis:load-dataset "REGION/GULF_SE/GIS/counties_lowres4.asc" ; Raster map - counties (downscaled by a factor of 4 using QGIS)
set county-seats gis:load-dataset "REGION/GULF_SE/GIS/county_centroid_clipped.shp" ; Vector map (points) - location of county centers (not county seats)
foreach but-last gis:feature-list-of county-seats [ ?1 ->
set county-seat-list lput list gis:property-value ?1 "CNTY_FIPS" (gis:location-of (first (first (gis:vertex-lists-of ?1)))) county-seat-list ;;;county_seat_list is a list: [county_seat_number [x and y points of county seats in Netlogo world]]
;set county-seat-list lput list gis:property-value ?1 "OBJECTID" (gis:location-of (first (first (gis:vertex-lists-of ?1)))) county-seat-list ;;;county_seat_list is a list: [county_seat_number [x and y points of county seats in Netlogo world]]
]]
gis:set-world-envelope-ds gis:envelope-of elevation
let world gis:world-envelope
let degree-x abs (item 1 world - item 0 world) / (world-width) ;; sets grid cell size in degrees
let degree-y abs (item 3 world - item 2 world) / (world-height)
set grid-cell-size list degree-x degree-y ;; holds x and y grid cell size in degrees
set re0-0 list (((item 0 world - item 1 world) / 2) + item 1 world) (((item 2 world - item 3 world) / 2) + item 3 world)
let avg-grid-size (item 0 grid-cell-size + item 1 grid-cell-size ) / 2
set scale ( avg-grid-size * 60) ;; This is an approximation. The distance between longitude degrees is based on the location. In florida longitude is around 52 nautical miles while latitude is aronud 60.
file-close-all
gis:set-sampling-method elevation "NEAREST_NEIGHBOR"
gis:set-sampling-method density-map "NEAREST_NEIGHBOR"
gis:set-sampling-method counties "NEAREST_NEIGHBOR"
ask patches [
let coords ( list [ pxcor ] of self [ pycor ] of self )
set elev gis:raster-sample elevation coords
set density gis:raster-sample density-map coords
set county gis:raster-sample counties coords ]
if display-dem? [gis:paint elevation 0 ] ;; the painted raster does not necessarily correspond to the elevation
ask patches [set land? true]
ask patches with [not (elev >= 0 or elev <= 0)] [set pcolor 102 set land? false]
set land-patches patches with [land? = true]
set ocean-patches patches with [land? = false]
; set coastal-patches ocean-patches with [county > 0] ; *SB are coastal patches land or water
set using-hpc? false
set coastal-patches land-patches with [any? neighbors with [land? = false]]
end
to Load-Hurricane
; INFO: Loads hurricane best track data from a text or csv file. Defines a list called "best-track-data" that stores the best track data (sublists exist for each time of best track data).
; VARIABLES MODIFIED: "best-track-data" contains best track data in the format for each time: [status of system,lat,lon,intensity,pressure,date,hour,radii (4 quadrants) of 34-kt winds, radii (4 quadrants) of 64-kt winds]
; PROCEDURES CALLED: None
; CALLED BY: Setup-Everything
; Best track data is every 6 hours in the format: [date,hour,identifier,status of system,lat,lon,wind speed,pressure,34-kt wind radii in quadrants (NE,SE,SW,NW), radii of 50 kt winds, radii of 64 kt winds]
; Here is a description of the best track format: https://www.nhc.noaa.gov/data/hurdat/hurdat2-format-nov2019.pdf
let storm-file "" ; storm-file is set to the directory and file that contains the best track information.
if which-storm? = "HARVEY" [ set storm-file "STORMS/HARVEY/HARVEY.txt" ]
if which-storm? = "WILMA" [ set storm-file "STORMS/WILMA/WILMA_NEW.csv" ]
if which-storm? = "WILMA_IDEAL" [set storm-file "STORMS/WILMA_IDEAL/WILMA_NEW.csv" ]
if which-storm? = "CHARLEY_REAL" [ set storm-file "STORMS/CHARLEY_REAL/CHARLEY.txt" ]
if which-storm? = "CHARLEY_IDEAL" [ set storm-file "STORMS/CHARLEY_IDEAL/CHARLEY.txt" ]
if which-storm? = "CHARLEY_BAD" [ set storm-file "STORMS/CHARLEY_BAD/CHARLEY.txt" ]
if which-storm? = "IRMA" [ set storm-file "STORMS/IRMA/IRMA.txt" ]
if which-storm? = "DORIAN" [ set storm-file "STORMS/DORIAN/DORIAN.txt" ]
if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/AL142018_best_track_cut.txt" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/idealized_linear_fast_slow/AL142018_best_track_cut_linear.txt" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/idealized_linear_fast_slow/AL142018_best_track_cut_slow_rapid.txt" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/idealized_linear_fast_slow/AL142018_best_track_cut_rapid_slow.txt" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/various_categories/best_track_cat3.txt" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/various_categories/best_track_cat4.txt" ]
file-open storm-file ; imports the best track data
; This code block parses the text/csv file and places the best track information in a "hurricane-file" list. Each new line of the best track data is appended, resulting in one big list.
; Example of hurricane-file: [20181006, 1800, , LO, 17.8N, 86.6W, 25, 1006, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20181007, 0000,.....]
let hurricane-file []
while [ not file-at-end? ]
[ set hurricane-file sentence hurricane-file file-read-line ]
file-close
let Tparsed "" ; "Tparsed" is an individual string from the list "hurricane-file"
let parsed [] ; "parsed" is a list that combines all of the strings in "hurricane-file", but with commas removed
let all-parsed [] ; "all-parsed" is a list with data for each best track time, with commas removed, and sublists for each time
foreach hurricane-file [ ?1 -> ; "?1" represents each line in "hurricane-file"
let i 0
while [i < length ?1] [
set Tparsed word Tparsed item i ?1 ; "Tparsed" is set to a value in "hurricane-file". Once a comma is found, the comma is removed and "Tparsed" is reset
if item i ?1 = "," [ set parsed lput remove "," Tparsed parsed ; Removes commas from "Tparsed". "parsed" is in format: [20181006 1800 LO 17.8N 86.6W 25 1006 0 0 0 0 0 0 0 0 0 0 0 0]
set Tparsed ""
]
set i i + 1 ]
set all-parsed lput parsed all-parsed ; Adds the list "parsed" to the end of the list "all_parsed". "all_parsed" is a list with sublists for each best track time.
set parsed [] ]
; This line makes sure the best track first time is AT or AFTER the first time of the forecast advisories (so the forecast starts at or before the best track data).
; Example of the issue: For Hurricane Michael, advisories (starting at 2100 UTC) would start after the best track time (starting at 1800 UTC), which means the forecast does not cover the first best track time.
set all-parsed but-first all-parsed
set best-track-data map [ ?1 -> (list item 3 ?1 but-last item 4 ?1 replace-item 1 but-last item 5 ?1 ;Re-orders the data in "all-parsed". "replace-item" adds a negative sign to lon, and "but-last" removes the "N" and "W" from the lat-lon coordinates in the best track file.
"-" item 6 ?1 item 7 ?1 item 0 ?1 item 1 ?1 item 8 ?1 item 9 ?1 item 10 ?1 item 11 ?1 item 16 ?1
item 17 ?1 item 18 ?1 item 19 ?1) ] all-parsed ;"best-track-data" is a list of best track data with a sublist for each time. Each sublist is: [status of system,lat,lon,intensity,pressure,date,hour,radii (4 quadrants) of 34-kt winds, radii (4 quadrants) of 64-kt winds]
set best-track-data Calendar-Check-Storm-Track best-track-data
end
to Load-Forecasts
; INFO: Load hurricane forecast information based on the hurricane selected in the interface
; VARIABLES MODIFIED:
; PROCEDURES CALLED:
; CALLED BY:
set forecast-matrix []
let storm-file ""
if which-storm? = "HARVEY" [ set storm-file "STORMS/HARVEY/HARVEY ADVISORIES.txt" ]
if which-storm? = "WILMA" [ set storm-file "STORMS/WILMA/WILMA ADVISORIES.txt" ] ;; defines the correct list of advisories from pull-down menu
if which-storm? = "WILMA_IDEAL" [set storm-file "STORMS/WILMA_IDEAL/FAKE_WILMA ADVISORIES.txt" ]
if which-storm? = "CHARLEY_REAL" [ set storm-file "STORMS/CHARLEY_REAL/CHARLEY ADVISORIES.txt" ]
if which-storm? = "CHARLEY_IDEAL" [ set storm-file "STORMS/CHARLEY_IDEAL/CHARLEY_IDEAL ADVISORIES.txt" ]
if which-storm? = "CHARLEY_BAD" [set storm-file "STORMS/CHARLEY_BAD/BAD_FAKE_CHARLEY ADVISORIES.txt" ]
if which-storm? = "IRMA" [ set storm-file "STORMS/IRMA/IRMA ADVISORIES.txt" ]
if which-storm? = "DORIAN" [ set storm-file "STORMS/DORIAN/DORIAN ADVISORIES.txt" ]
let file-list []
;; the storm-file is a list of all the advisories, which are stored as separate text files directly from NOAA/NHC website
;; this index file is parsed and then each of the advisories is parsed for relevant forecast information
file-open storm-file
while [not file-at-end?] [ set file-list lput file-read-line file-list] ;; transfer the list of advisories to a netlogo list
file-close
foreach file-list [ ?1 -> ;; Open each of the files located in "Storm"_advisories
file-open ?1
let forecast-file []
while [ not file-at-end? ]
[
set forecast-file sentence forecast-file word file-read-line " "
]
file-close
let Tparsed ""
let parsed []
let all_parsed []
;; The advisory parser is fairly complicated... because the advisories themselves are much more than a simple rectangular data file...
foreach forecast-file [ ??1 ->
let i 0
while [i < length ??1 ] [
set Tparsed word Tparsed item i ??1
if item i ??1 = " " [ set parsed lput remove " " Tparsed parsed
set Tparsed ""
]
set i i + 1
]
set all_parsed lput parsed all_parsed
set parsed []
]
let s-line remove "" item 4 all_parsed
let schedule list read-from-string item 3 s-line read-from-string but-last item 0 s-line
let forecasts filter [ ??1 -> length ??1 > 2 and item 1 ??1 = "VALID" ] all_parsed
set forecasts map [ ??1 -> remove "" ??1 ] forecasts
while [length item 2 last forecasts > 10 and substring item 2 last forecasts (length item 2 last forecasts - 5) (length item 2 last forecasts - 0) = "ORBED"] [set forecasts but-last forecasts]
let winds but-first filter [ ??1 -> length ??1 > 2 and item 0 ??1 = "MAX" ] all_parsed
while [length winds < length forecasts] [ set winds (sentence winds "")]
set winds map [ ??1 -> remove "" ??1 ] winds
let dia64 map [ ??1 -> remove "" ??1 ] filter [ ??1 -> item 0 ??1 = "64" ] all_parsed
let dia34 map [ ??1 -> remove "" ??1 ] filter [ ??1 -> item 0 ??1 = "34" ] all_parsed
let dia34-list []
if not empty? dia34 [
set dia34-list map [ ??1 -> map [ ???1 -> read-from-string ???1 ] but-first map [ ???1 -> but-last but-last ???1 ] remove "" map [ ???1 -> remove "KT" remove "." ???1 ] ??1 ] dia34
set dia34-list but-first dia34-list ]
while [length dia34-list < length forecasts] [
set dia34-list (sentence dia34-list "") ]
let dia64-list []
if not empty? dia64 [
set dia64-list map [ ??1 -> map [ ???1 -> read-from-string ???1 ] but-first map [ ???1 -> but-last but-last ???1 ] remove "" map [ ???1 -> remove "KT" remove "." ???1 ] ??1 ] dia64
set dia64-list but-first dia64-list ]
while [length dia64-list < length forecasts] [
set dia64-list (sentence dia64-list "") ]
set forecast-matrix lput fput schedule (map [ [??1 ??2 ??3 ??4] -> (sentence
read-from-string substring item 2 ??1 0 position "/" item 2 ??1
read-from-string substring item 2 ??1 (position "/" item 2 ??1 + 1) position "Z" item 2 ??1
(( read-from-string substring item 3 ??1 0 4 - item 1 re0-0) / item 1 grid-cell-size) ; lat
(((-1 * read-from-string substring item 4 ??1 0 4) - item 0 re0-0) / item 0 grid-cell-size) ; lon
read-from-string item 2 ??2 ; wind max
(list ??3) (list ??4) ) ; wind dia34 (NE SE SW NW) and dia64 (NE SE SW NW)
]
forecasts winds dia34-list dia64-list) forecast-matrix
]
;print "final forecast:"
;show forecast-matrix
file-close-all
end
to Load-Forecasts-New
; INFO: Load hurricane forecast information based on the hurricane selected in the interface
; VARIABLES MODIFIED: The main variable modified is the forecast-matrix. The forecasts include historical predictions about the storm based on the amount of time before the storm hits
; PROCEDURES CALLED: Calculate-Advisory-Time is called and used to convert forecast times that are saved in forecast-matrix
; CALLED BY: Setup
set forecast-matrix [] ; This is the main variable that will be modified in this procedure and records forecasts that will be used throughout the simulation
let storm-file "" ; The storm file is a csv that is read and parsed into the forecast-matrix
if which-storm? = "HARVEY" [ set storm-file "STORMS/HARVEY/HARVEY_ADVISORIES_NEW.csv" ]
if which-storm? = "WILMA" [ set storm-file "STORMS/WILMA/WILMA_ADVISORIES_NEW.csv" ]
if which-storm? = "WILMA_IDEAL" [set storm-file "STORMS/WILMA_IDEAL/FAKE_WILMA ADVISORIES.txt" ]
if which-storm? = "CHARLEY_REAL" [ set storm-file "STORMS/CHARLEY_REAL/CHARLEY_ADVISORIES_NEW.csv" ]
if which-storm? = "CHARLEY_IDEAL" [ set storm-file "STORMS/CHARLEY_IDEAL/CHARLEY_IDEAL ADVISORIES.txt" ]
if which-storm? = "CHARLEY_BAD" [set storm-file "STORMS/CHARLEY_BAD/BAD_FAKE_CHARLEY ADVISORIES.txt" ]
if which-storm? = "IRMA" [ set storm-file "STORMS/IRMA/IRMA_ADVISORIES.csv" ]
if which-storm? = "DORIAN" [ set storm-file "STORMS/DORIAN/DORIAN ADVISORIES.txt" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/perfect_forecast.csv" ]
if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/perfect_forecast_hourly.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/perfect_forecast_2day_leadtime.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/NHC_forecast_perfect_track.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/NHC_forecast_perfect_track_hourly.csv" ]
if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/NHC_forecast_perfect_track_hourly.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/idealized_linear_fast_slow/nonperfect_forecast_hourly_linear.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/idealized_linear_fast_slow/perfect_forecast_hourly_linear.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/idealized_linear_fast_slow/nonperfect_forecast_hourly_slow_fast.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/idealized_linear_fast_slow/perfect_forecast_hourly_slow_fast.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/idealized_linear_fast_slow/nonperfect_forecast_hourly_fast_slow.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/idealized_linear_fast_slow/perfect_forecast_hourly_fast_slow.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/various_categories/nonperfect_forecast_hourly_cat3.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/various_categories/perfect_forecast_hourly_cat3.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/various_categories/nonperfect_forecast_hourly_cat4.csv" ]
;if which-storm? = "MICHAEL" [ set storm-file "STORMS/MICHAEL/various_categories/perfect_forecast_hourly_cat4.csv" ]
let all-advisories csv:from-file storm-file
;; If it needs to be added later, a similar batch of code to that below could be used to sort for ofcl forecasts
let advisories-parsed []; the first list used to hold information from the first parsing of all-advisories
;; First filter out rows that are NOT used which have a time and pressure of 0 and save them in advisories-parsed
foreach all-advisories [ this-advisory ->
let this-forecast-time item 5 this-advisory
let pressure-value item 9 this-advisory
ifelse this-forecast-time = 0 and pressure-value = 0 [][
set advisories-parsed lput this-advisory advisories-parsed
]
]
let forecast-time 0
let all-forecasts [] ;; the new list that holds the parsed information
let unique-advisory [] ;; a sub list that is saved to the all-forecasts list
;; This next section of code below is to move each row into a new list entry by date to replicate the previous format
;; This results in a list which contains a list of all information for each day in one row
;; Previous Format: [ [Day 1 Time 1]
;; [Day 1 Time 2]
;; [Day 2 Time 1]
;; [Day 2 Time 2]]
;; New Format: [[Day 1 Time 1 Time 2]
;; [Day 2 Time 1 Time 2]]
foreach advisories-parsed [this-advisory ->
; same forecast time - so keep adding it to the list for that day
ifelse forecast-time = (item 2 this-advisory) [
set unique-advisory lput this-advisory unique-advisory
]
; Each unique forecast is added to its own list called unique-advisory. When a new forecast time is detected, that sub-list is added to the list of all information, all-forecasts
;new forecast time
[
if forecast-time != 0 [set all-forecasts lput unique-advisory all-forecasts]
set forecast-time item 2 this-advisory
set unique-advisory []
set unique-advisory lput this-advisory unique-advisory
]
]
;; all-forecasts now contatins the partially parsed information that has each forecast time recorded as its own sublist
set forecast-time 0
let entries-for-one-day []
let entries-for-all-days []
; Now parse each day into one entry that follows the format used to load previous information
; The format contains different types of information within sub-lists as shown below:
; [Date of Forecast [ individual forecast time, netlogo coordinates, max wind [wind 34] [wind 64] ]
; EXAMPLE: [5 1200 [5 1800 -198.23361282214213 470.7438061089692 155 [130 100 80 110] [40 35 30 35]]]
foreach all-forecasts [whole-advisory-day ->
let first-entry item 0 whole-advisory-day
let date item 2 first-entry
let hours-away item 5 first-entry ; used to id the current time for this list entry
let schedule Calculate-Advisory-Time date hours-away
set entries-for-one-day []
set entries-for-one-day lput schedule entries-for-one-day ;; uses a reporter that update the time correctly
let entries-for-one-time-on-one-day []
let list-34 []
let list-64 []
let new-time-entry false
let first-entry-from-this-advisory true
let current-forecast-time 0
; This section goes through each forecast entry for a unique forecast time and parses the information
foreach whole-advisory-day [ this-advisory ->
;; we don't save the forecast info that is currently occuring - just future ones, so get rid of a few
let entry-hours-away item 5 this-advisory
if entry-hours-away != hours-away[
; set wind-speed
let wind-speed item 11 this-advisory
; check to see if its a new time
ifelse current-forecast-time != (item 5 this-advisory) and first-entry-from-this-advisory = false [
set new-time-entry true
][set new-time-entry false
set first-entry-from-this-advisory false]
ifelse new-time-entry[
; save the info and reset lists to 0
ifelse length list-34 > 0 [set schedule lput list-34 schedule]
[let empty (word list-34 "")
set schedule lput empty schedule]
ifelse length list-64 > 0 [set schedule lput list-64 schedule]
[
let empty (word list-64 "")
set schedule lput empty schedule]
set entries-for-one-day lput schedule entries-for-one-day
set current-forecast-time item 5 this-advisory
set entries-for-one-time-on-one-day []
set list-34 []
set list-64 []
; save current info
set date item 2 this-advisory
let this-hours-away item 5 this-advisory ; used to id the current time
set schedule Calculate-Advisory-Time date this-hours-away
;;[5 1800 -198.23361282214213 470.7438061089692 155 [130 100 80 110] [40 35 30 35]]
;; add the coordinates and the max windspeed to schedule
let coords Calculate-Coordinates item 7 this-advisory item 6 this-advisory
set schedule lput item 1 coords schedule
set schedule lput item 0 coords schedule
set schedule lput item 8 this-advisory schedule
;set schedule
;save windspeed list
if wind-speed = 34[
set list-34 lput item 13 this-advisory list-34
set list-34 lput item 14 this-advisory list-34
set list-34 lput item 15 this-advisory list-34
set list-34 lput item 16 this-advisory list-34
]
if wind-speed = 64[
set list-64 lput item 13 this-advisory list-64
set list-64 lput item 14 this-advisory list-64
set list-64 lput item 15 this-advisory list-64
set list-64 lput item 16 this-advisory list-64
]
][ ; Repeat the same steps as above, this is for a different time from the same forecast
; save current info
;save windspeed list
set date item 2 this-advisory
let this-hours-away item 5 this-advisory ; used to id the current time
set schedule Calculate-Advisory-Time date this-hours-away
;; General format: [5 1800 -198.23361282214213 470.7438061089692 155 [130 100 80 110] [40 35 30 35]]
;; add the coordinates and the max windspeed to schedule
let coords Calculate-Coordinates item 7 this-advisory item 6 this-advisory
set schedule lput item 1 coords schedule
set schedule lput item 0 coords schedule
set schedule lput item 8 this-advisory schedule
if wind-speed = 34[
set list-34 lput item 13 this-advisory list-34
set list-34 lput item 14 this-advisory list-34
set list-34 lput item 15 this-advisory list-34
set list-34 lput item 16 this-advisory list-34
]
if wind-speed = 64[
set list-64 lput item 13 this-advisory list-64
set list-64 lput item 14 this-advisory list-64
set list-64 lput item 15 this-advisory list-64
set list-64 lput item 16 this-advisory list-64
]
set current-forecast-time item 5 this-advisory
]
]
]
; save the last forecast time from each day here:
ifelse length list-34 > 0 [set schedule lput list-34 schedule]
[let empty (word list-34 "")
set schedule lput empty schedule]
ifelse length list-64 > 0 [set schedule lput list-64 schedule]
[
let empty (word list-64 "")
set schedule lput empty schedule]
set entries-for-one-day lput schedule entries-for-one-day
set entries-for-all-days lput entries-for-one-day entries-for-all-days
]
; The parsing is complete and the forecast-matrix is set
; The format is as follows:
; [Date of Forecast [ individual forecast time, netlogo coordinates, max wind [wind 34] [wind 64]] [[ individual forecast time, netlogo coordinates, max wind [wind 34] [wind 64]] ...]
; [Date of Forecast [ individual forecast time, netlogo coordinates, max wind [wind 34] [wind 64]] [[ individual forecast time, netlogo coordinates, max wind [wind 34] [wind 64]] ...]
set entries-for-all-days Calendar-Check-Forecast entries-for-all-days
set forecast-matrix entries-for-all-days
end
to-report Calculate-Advisory-Time [time hours-away]
; INFO: This procedure translates times from the file to the date and the hour.
; 2017090506 6 -> 5 1200
; VARIABLES MODIFIED: Converts the time and hours away to a different format - see above line
; PROCEDURES CALLED: Its used when the forecast info is parsed during the setup of the model.
; CALLED BY: Load-Forecast
;JA: What happens if the month changes for a storm? - SB - The immediate effect is an extra day. We could try and prevent this - but I'm waiting till we get to past-forecast so that I can understand how these forecasts are read
let advisory-time[]
let time-word (word time)
;parse the individual numbers from the incoming variable time
let day substring time-word 6 8
let hour substring time-word 8 10
set day read-from-string day
set hour read-from-string hour
set hour hour + hours-away
if hour > 23 [ ; adjust the date of a forecast to account for periods of time greater than 24 hours
let days-to-add 0
let hours-past-0 hour
while [hours-past-0 > 23] [
set days-to-add days-to-add + 1
set hours-past-0 hours-past-0 - 24
]
set day day + days-to-add
set hour hours-past-0
]
set hour hour * 100 ; to make 12, look like 1200 etc.
; report a two entry list that contains the parsed day and hour
set advisory-time lput day advisory-time
set advisory-time lput hour advisory-time
report advisory-time
end
to-report Calendar-Check-Forecast [forecast-entries]
; used to prevent issues that may occur when a forecast covers two different months
; if the next date in the list is less than the previous date, the date is changed to one more than the original
; so 29, 30, 1, 2 -> 29, 30, 31, 32
let clean-forecast[]
;determine the first date in the forecast
let original-value 0
let previous-date 0
foreach forecast-entries [ unique-entry ->
let first-entry item 0 unique-entry
let date item 0 first-entry
if date < previous-date [
ifelse date = original-value[
set original-value date
set date previous-date
set first-entry replace-item 0 first-entry date
set unique-entry replace-item 0 unique-entry first-entry
][
set original-value date
set date previous-date + 1
set first-entry replace-item 0 first-entry date
set unique-entry replace-item 0 unique-entry first-entry
]
]
set previous-date date
set clean-forecast lput unique-entry clean-forecast
]
;report forecast-entries
report clean-forecast
end
to-report Calendar-Check-Storm-Track [storm-track]
; used to prevent issues that may occur when a forecast covers two different months
; if the next date in the list is less than the previous date, the date is changed to one more than the original
; so 29, 30, 1, 2 -> 29, 30, 31, 32
let original-value 0
let previous-date 0
let clean-storm-track []
foreach storm-track [unique-entry ->
let full-date item 5 unique-entry
let date read-from-string (substring full-date 6 8)
if date < previous-date [
ifelse date = original-value[
set original-value date
set date previous-date
][
set original-value date
set date previous-date + 1
]
set full-date substring full-date 0 6
set full-date word full-date date
set unique-entry replace-item 5 unique-entry full-date
]
set clean-storm-track lput unique-entry clean-storm-track
set previous-date date
]
report clean-storm-track
end
to-report Calculate-Coordinates [long lat]
; INFO: Covert latitude and longitude coordinates to Netlogo world coordinates
; VARIABLES MODIFIED: long and lat to long-coord and lat-coord
; PROCEDURES CALLED: None
; CALLED BY: Load-Forecasts-New
let lat-coord but-last lat
let long-coord but-last long
set lat-coord read-from-string lat-coord
set long-coord read-from-string long-coord
; for some reason there are no decimal places in the incoming coordinates that should be there... e.g. 577 should be 57.7
let coordinates []
set lat-coord lat-coord / 10
set long-coord -1 * (long-coord / 10)
; the math that converts coordinates from lat/long to netlogo
set lat-coord (lat-coord - item 1 re0-0) / (item 1 grid-cell-size) ; lat
set long-coord (long-coord - item 0 re0-0) / (item 0 grid-cell-size) ; lon
set coordinates lput long-coord coordinates
set coordinates lput lat-coord coordinates
report coordinates
end
to Generate-Storm
; INFO: Translates the best track data and interpolates its characteristics for the in-between hours
; VARIABLES MODIFIED: modifies best-track-data and creates hurricane-coords-best-track which is used to draw the hurricane
; PROCEDURES CALLED
; CALLED BY: SETUP
let re-scaled best-track-data
;; first the hurricane_info array is re-worked to model-space coordinates and strings converted to numbers. Values are intially saved as strings when read from text files
;; Lat/Long coordinates are converted to Netlogo coordinates
;; The hour is extracted from the time stamp
;; For Example:
;; [[ LO 18.1 -86.9 25 1004 20181007 0000 0 0 0 0 0 0 0 0] ......
;; [[ LO -215.33360000140334 -32.462238805294746 25 1004 7 0 0 0 0 0 0 0 0 0]
set re-scaled map [ ?1 -> (list item 0 ?1 (( read-from-string item 1 ?1 - item 1 re0-0) / item 1 grid-cell-size )
((read-from-string item 2 ?1 - item 0 re0-0) / item 0 grid-cell-size ) read-from-string item 3 ?1
read-from-string item 4 ?1 (read-from-string word last but-last item 5 ?1 last item 5 ?1) read-from-string item 6 ?1
read-from-string item 7 ?1 read-from-string item 8 ?1 read-from-string item 9 ?1
read-from-string item 10 ?1 read-from-string item 11 ?1 read-from-string item 12 ?1 read-from-string item 13 ?1
read-from-string item 14 ?1) ] re-scaled
;; Temporary variables used in the calculation of interpoloated storm characteristics
let t-y 0
let t-x 0
let t-z 0
let t-34-ne 0
let t-34-se 0
let t-34-sw 0
let t-34-nw 0
let t-64-ne 0
let t-64-se 0
let t-64-sw 0
let t-64-nw 0
let day item 5 item 0 re-scaled
let hour item 6 item 0 re-scaled
let i 1
set hurricane-coords-best-track [] ; the list that will contain the newly interpolated storm location information: [x_coord,y_coord,intensity,day,hour,34-kt wind (4 items),64-kt wind(4 items)]
;; the following is basically brute-force interpoloation. The code marches through the array of storm info
;; and takes the difference from one best track time to the next, then calculates the interpolated points
;; It does this for all of the dozen or so characteristics of the storm at each point
;; We assume that the difference between each storm info is less than a day (e.g., most best track data is supplied every 6 hours)
;;For best track data that does not follow the same temporal format as the rest of the data (e.g., data is every 6 hours, but landfall is at 5.3 hours), delete the lines that do not follow the same temporal format
while [i < length re-scaled] [
set t-y item 1 item i re-scaled - item 1 item (i - 1) re-scaled
set t-x item 2 item i re-scaled - item 2 item (i - 1) re-scaled
set t-z item 3 item i re-scaled - item 3 item (i - 1) re-scaled
set t-34-ne item 7 item i re-scaled - item 7 item (i - 1) re-scaled
set t-34-se item 8 item i re-scaled - item 8 item (i - 1) re-scaled
set t-34-sw item 9 item i re-scaled - item 9 item (i - 1) re-scaled
set t-34-nw item 10 item i re-scaled - item 10 item (i - 1) re-scaled
set t-64-ne item 11 item i re-scaled - item 11 item (i - 1) re-scaled
set t-64-se item 12 item i re-scaled - item 12 item (i - 1) re-scaled
set t-64-sw item 13 item i re-scaled - item 13 item (i - 1) re-scaled