WaDemEsT

WaDemEsT preview image

1 collaborator

Dsc_0679 Kamil Aybuğa (Author)

Tags

(This model has yet to be categorized with any tags)
Visible to everyone | Changeable by the author
Model was written in NetLogo 6.4.0 • Viewed 3 times • Downloaded 2 times • Run 0 times
Download the 'WaDemEsT' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


Info tab cannot be displayed because of an encoding error

Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

extensıons [csv]          ;; Import the CSV extension for handling data files

globals [                 ;; Define global variables accessible throughout the model
  data                    ;; Stores the dataset read from a CSV file
  data-source             ;; Specifies the file path or source of the data
  data-pointer            ;; Tracks the current position in the dataset
  data-length             ;; Holds the total number of data entries

  data-date               ;; Stores the date information for data entries (e.g., "01.01.2020")
  DayofYear               ;; Represents the day number in a year (1-365 or 1-366 for leap years)
  DayofMonth              ;; Represents the day number in a month (1-31)
  Month                   ;; Stores the month number (1-12)
  Week                    ;; Stores the week number of the year
  data-weekday            ;; Stores the day of the week (e.g., Monday, Tuesday)
  data-vacation           ;; Indicates if the day is a vacation day (e.g., "none", "weekend", or another label)
  data-temp               ;; Stores temperature data for each day
  data-prcp               ;; Stores precipitation data for each day

  data-housesMonthly      ;; Tracks the number of houses per month from the CSV
  data-popMonthly         ;; Tracks the population per month from the CSV
  data-totalMonthly       ;; Stores the total consumption per month from the CSV
  HeuristicMonthlyTotal   ;; Stores heuristic estimates for monthly total consumption from the CSV
  data-avgDaily           ;; Stores the average daily consumption from the CSV
  HeuristicDailyTotal     ;; Stores heuristic estimates for daily total consumption from the CSV
  AverageWeekly           ;; Stores the average weekly consumption from the CSV
  HeuristicWeekly         ;; Stores heuristic estimates for weekly consumption from the CSV
  fwcf                    ;; Represents the weather correction factor (float) from the CSV file

  number-of-humans        ;; Stores the total number of humans in the model
  number-of-houses        ;; Stores the total number of houses in the model
  remaining               ;; Tracks the remaining number of houses to be added into the world in each simulation time
  workingPeople           ;; Stores the count of working individuals (i.e., is-outsider?)
  vacationistPeople       ;; Stores the count of vacationists
  weekenderPeople         ;; Stores the count of people who go outside on weekends
  num-under5              ;; Stores the number of children under 5 years old
  num-5&17                ;; Stores the number of children aged 5 to 17
  num-seniors             ;; Stores the number of senior citizens (e.g., > 65)
  num-adults              ;; Stores the number of adults (e.g., 18-65)
  num-singles             ;; Stores the number of single individuals
  num-2adults             ;; Stores the number of households with two adults
  num-1parent+child       ;; Stores the number of single-parent households with children
  start-res               ;; Represents the number of starting residents on each tick
  water-consumption       ;; Stores the total water consumption of the district at each tick

  worldSize               ;; Stores the size of the simulated world (used to calculate worldDmnsn)
  worldDmnsn              ;; Stores the dimensions of the simulated world (sqrt of worldSize)
  logfile                 ;; Stores the log file name or path
  previous-outsiders      ;; Stores the count of outsiders from the previous period
  previous-weekenders     ;; Stores the count of weekenders from the previous period
  previous-vacationists   ;; Stores the count of vacationers from the previous period

  temp-outsiders          ;; Temporary storage for outsider ratio
  temp-weekenders         ;; Temporary storage for weekender ratio
  temp-vacationists       ;; Temporary storage for vacationist ratio

  temp-change-active?     ;; Flag indicating whether a temporary ratio change is active
  temp-change-pending?    ;; Flag indicating whether a temporary ratio change is scheduled (waiting to start)
  temp-change-start-tick  ;; The tick at which the temporary ratio change started
  temp-change-end-tick    ;; The tick at which the temporary ratio change ends

  daily-consumption       ;; Tracks daily water consumption
  monthly-consumption     ;; Tracks monthly water consumption
  weekly-consumption      ;; Tracks weekly water consumption
  yearly-consumption      ;; Tracks yearly water consumption (if needed)
  data-loaded?            ;; Indicates if data has been loaded successfully

  simulation-start-date   ;; Numerical representation of the start date from CSV
  simulation-end-date     ;; Numerical representation of the end date from CSV

  current-month           ;; Tracks the current month (for aggregating monthly consumption)
  current-week            ;; Tracks the current week (for aggregating weekly consumption)
  current-data-index      ;; An index to navigate through unique months/weeks if needed
  unique-custom-months    ;; A list of unique "custom months" (if used)
  unique-months           ;; A list of unique months read from CSV
  unique-weeks            ;; A list of unique weeks read from CSV
  current-custom-month    ;; Tracks a custom month index if needed
  unique-custom-weeks     ;; A list of unique "custom weeks" if used

  average-monthly-consumption  ;; Average monthly consumption (running average over the simulation)
  average-weekly-consumption   ;; Average weekly consumption (running average over the simulation)
  average-daily-consumption    ;; Average daily consumption (running average over the simulation)

  monthly-consumption-list     ;; A list collecting monthly consumption values
  weekly-consumption-list      ;; A list collecting weekly consumption values
  daily-consumption-list       ;; A list collecting daily consumption values
  total-water-consumption      ;; Accumulated water consumption since start of sim

  weekday-consumption          ;; Water consumption recorded for weekdays
  weekend-consumption          ;; Water consumption recorded for weekends
  vacation-consumption         ;; Water consumption recorded for vacation days
  weekday-consumption-total    ;; Total water consumption for all weekdays so far
  weekend-consumption-total    ;; Total water consumption for all weekends so far
  vacation-consumption-total   ;; Total water consumption for all vacation days so far
  weekday-count                ;; Number of weekday ticks encountered so far
  weekend-count                ;; Number of weekend ticks encountered so far
  vacation-count               ;; Number of vacation-day ticks encountered so far
  avg-weekday-consumption      ;; Average consumption for weekdays
  avg-weekend-consumption      ;; Average consumption for weekends
  avg-vacation-consumption     ;; Average consumption for vacation days
]

breed [humans human]           ;; Define a "humans" breed of turtles
humans-own [
  age
  house
  workplace
  category
  education-age
  clmt-strtgy
  daily-strtgy
  status
  is-outsider?
  is-weekender?
  is-vacationist?
]

patches-own [
  hhs                 ;; The number of humans (household size) associated with a patch
  working             ;; Number of "working" humans in that patch
  employees           ;; Possibly used to store employees in that patch
  income              ;; Household income or patch-level income if used
  hhtype              ;; String describing patch type: "outside", "household", "workplace"
  avgHHAge            ;; Average household age
  lvng-strtgy         ;; Lifestyle strategy placeholder
  eat-strategy        ;; Eating strategy placeholder
  clean-strategy      ;; Cleaning strategy placeholder
  maintenance-strategy;; Maintenance strategy placeholder
  water-cnsmptn       ;; Total water consumption in that patch
  tap-water           ;; Water consumption from tap usage
  dw-water            ;; Water consumption from dishwasher usage
  wm-water            ;; Water consumption from washing machine usage
  toilet-water        ;; Water consumption from toilet flushing
  shower-water        ;; Water consumption from shower usage
  tap-use             ;; Frequency or usage intensity for tap
  dw-use              ;; Frequency or usage intensity for dishwasher
  wm-use              ;; Frequency or usage intensity for washing machine
  toilet-use          ;; Frequency or usage intensity for toilet
  shower-use          ;; Frequency or usage intensity for shower
  eat-and-drink-water ;; Subtotal consumption for eating/drinking
  cleaning-water      ;; Subtotal consumption for cleaning
  maintenance-water   ;; Subtotal consumption for maintenance
  insiders            ;; Number of "insider" humans in this patch
  dw-load             ;; A running counter to track when a dishwasher load is triggered
  wm-load             ;; A running counter to track when a washing machine load is triggered
  weekender           ;; A counter or flag for weekenders in this patch
  vacationist         ;; A counter or flag for vacationists in this patch

  tap-eat-drink       ;; Detailed breakdown of tap usage for eating/drinking
  tap-clean-up        ;; Detailed breakdown of tap usage for cleaning
  tap-maintenance     ;; Detailed breakdown of tap usage for maintenance
  dw-eat-drink        ;; Detailed breakdown of dishwasher usage for eating/drinking
  dw-clean-up         ;; Detailed breakdown of dishwasher usage for cleaning
  wm-clean-up         ;; Detailed breakdown of washing machine usage for cleaning
  wm-maintenance      ;; Detailed breakdown of washing machine usage for maintenance
]

; ===== SETUP PROCEDURES =====

to setup
  ;; Primary setup procedure. Calls various sub-setup procedures only if data is loaded.
  ifelse data != 0 and data != false [
    ;; Only proceed if 'data' is not empty or false. This checks if the user has loaded CSV data.

    clear-all-plots
    clear-patches
    clear-turtles
    clear-drawing
    clear-all-plots
    reset-ticks

    ;; Initialize simulation environment
    set-globals
    set-the-world
    set-the-household
    setup-human-types

    ;; Set up data tracking variables
    set data-length length data
    set current-data-index 0
    set current-month 0
    set current-week 0
    set monthly-consumption 0
    set weekly-consumption 0
    set total-water-consumption 0

    ;; Initialize consumption tracking counters
    set weekday-consumption-total 0
    set weekend-consumption-total 0
    set vacation-consumption-total 0
    set weekday-count 0
    set weekend-count 0
    set vacation-count 0

    ;; Initialize consumption tracking lists
    set monthly-consumption-list []
    set weekly-consumption-list []
    set daily-consumption-list []

    ;; Set up logging
    set logfile "simulation_log.txt"  ;; Default log file name

    ;; Extract simulation date range from data (the first and last rows)
    if not empty? data [
      set simulation-start-date date-to-number item 0 (item 0 data)
      set simulation-start-date date-to-number item 0 (item 0 data)
      set simulation-end-date date-to-number item 0 (last data)
      set unique-months remove-duplicates map [d -> extract-month item 0 d] data
      set unique-weeks remove-duplicates map [d -> extract-week item 0 d] data
    ]
    ;;  setup-water-consumption-plots (if you have a separate procedure for that)

    set simulation-start-date date-to-number (item 0 (item 0 data))  ;; Convert first row's date to a number
    set simulation-end-date date-to-number (item 0 (last data))      ;; Convert last row's date to a number

    ;; Initialize temporary change tracking
    set temp-change-active? false
    set temp-change-pending? false
    set temp-change-start-tick 0
    set temp-change-end-tick 0

    ;; Store initial population ratios
    set previous-outsiders Outsiders
    set previous-weekenders Weekenders
    set previous-vacationists Vacationists

    ;; Update population ratios once at the start
    update-population-ratios

    output-print "Simulation environment has been set up succesfully."
  ] [
    user-message "Please first load the data using 'Load Data' button."
  ]
end 

; ===== DATA LOADING AND MANAGEMENT =====

to startup
  ;; This procedure runs automatically when the model is first opened. We initialize empty data structures.
  set data []
  set data-length 0
  set data-loaded? false
end 

to Data-Load
  ;; Called from a button to load a CSV file. Uses the NetLogo 'carefully' to catch any errors during file operations.
  carefully [
    let file user-file
    ifelse file != false [
      ;; If the user selected a file:
      ;; Check if file is CSV format by checking the last 4 chars
      ifelse (substring file (length file - 4) length file) = ".csv" [
        set data csv:from-file file  ;; Use the CSV extension to read the file into 'data'

        if not empty? data [
          ;; If data is not empty, store file info and handle potential header row
          set data-source file
          ;; Remove header row if the first row has strings in item 0
          if length first data > 0 and is-string? item 0 first data [
            set data but-first data
          ]
          set data-pointer 0
          set data-length length data
          set-current-vals  ;; Load values from the first row into the model's global variables
          output-print (word "Data has been successfully loaded: " data-source)
          output-print (word "Number of data points: " data-length)
        ]
      ] [
        ;; If the file doesn't end with ".csv", show an error
        user-message "Please select a CSV file. The selected file does not appear to be a CSV file."
        output-print "Error: Non-CSV file selected."
      ]
    ] [
      ;; If user canceled or no file selected
      output-print "No file was selected or the operation was cancelled."
    ]
  ] [
    ;; 'carefully' error block: if anything goes wrong, show a user message
    user-message (word "An unexpected error has occurred while reading the file: " error-message)
    output-print (word "Error Details: " error-message)
    ;; Save error log if needed
    carefully [
      file-open "error_log.txt"
      file-print (word date-and-time " - File Reading Error: " error-message)
      file-close
    ] []
  ]
end 

to-report read-data [ file-name ]
  ;; A helper reporter to read CSV data from a file
  let rows []
  if file-name != false [
    set data-source file-name
    file-open file-name
    set rows csv:from-file file-name
    file-close
  ]
  report rows
end 

to update-population-ratios
  ;; Reassigns humans to outsider, weekender, or vacationist groups based on global ratio variables
  let total-humans count humans
  let new-outsiders round (total-humans * Outsiders)
  let new-weekenders round (total-humans * Weekenders)
  let new-vacationists round (total-humans * Vacationists)

  ;; Reset all humans to default (no special type)
  ask humans [
    set is-outsider? false
    set is-weekender? false
    set is-vacationist? false
  ]

  ;; Assign 'Outsiders'
  let available-humans humans
  let outsiders-to-assign min (list new-outsiders count available-humans)
  ask n-of outsiders-to-assign available-humans [
    set is-outsider? true
  ]

  ;; Update who is left
  set available-humans humans with [not is-outsider?]

  ;; Assign 'Weekenders'
  let weekenders-to-assign min (list new-weekenders count available-humans)
  ask n-of weekenders-to-assign available-humans [
    set is-weekender? true
  ]

  ;; Update who is left
  set available-humans humans with [not is-outsider? and not is-weekender?]

  ;; Assign 'Vacationists'
  let vacationists-to-assign min (list new-vacationists count available-humans)
  ask n-of vacationists-to-assign available-humans [
    set is-vacationist? true
  ]

  ;; Update global reference sets
  set workingPeople humans with [is-outsider?]
  set weekenderPeople humans with [is-weekender?]
  set vacationistPeople humans with [is-vacationist?]

  ;; Update any dependent variables or patch-level variables
  update-dependent-variables
end 

to set-current-vals
  ;; Reads the current row in 'data' at 'data-pointer' and sets global variables.
  let vals-list item data-pointer data
  set data-date item 0 vals-list
  set DayofYear item 1 vals-list
  set DayofMonth item 2 vals-list
  set Month item 3 vals-list
  set Week item 4 vals-list
  set data-weekday item 5 vals-list
  set data-vacation item 6 vals-list
  set data-temp item 7 vals-list
  set data-prcp item 8 vals-list
  set data-housesMonthly item 9 vals-list
  set data-popMonthly item 10 vals-list
  set data-totalMonthly item 11 vals-list
  set HeuristicMonthlyTotal item 12 vals-list
  set data-avgDaily item 13 vals-list
  set HeuristicDailyTotal item 14 vals-list
  set AverageWeekly item 15 vals-list
  set HeuristicWeekly item 16 vals-list
  set fwcf item 17 vals-list
end 

to set-globals
  ;; Initialize some global variables at setup
  set number-of-houses data-housesMonthly
  set start-res count patches with [pcolor = yellow]
  set number-of-humans count humans with [pcolor = yellow]
end 

to set-the-world
  ;; Resizes and configures the NetLogo world based on the number of houses
  set worldSize number-of-houses * 3
  set worldDmnsn sqrt worldSize
  resize-world (- worldDmnsn) worldDmnsn (- worldDmnsn) worldDmnsn

  ask patches [
    set pcolor black
    set hhtype "outside"
  ]

  ;; Color some patches yellow to represent houses
  ask n-of number-of-houses patches [
    set pcolor yellow
    set hhtype "household"
  ]

  ;; Convert a fraction of patches into workplaces
  ask n-of (number-of-houses * (100 - residenceRatio) * 0.01) patches with [pcolor = black] [
    set pcolor grey
    set hhtype "workplace"
  ]
end 

to set-the-household
  ;; Assign household sizes (hhs) to each household patch and create humans
  ask patches with [hhtype = "household"] [
    set hhs round random-normal householdSize varHHS
    while [hhs < 1] [set hhs round random-normal householdSize varHHS]
  ]

  ;; Calculate sub-population sizes
  set num-under5 round (data-popMonthly * %Under5)
  set num-5&17 round (data-popMonthly * %5&17)
  set num-seniors round (data-popMonthly * %Seniors)
  set num-adults (data-popMonthly - num-under5 - num-5&17 - num-seniors)

  ;; Create humans in total equal to 'data-popMonthly'
  create-humans data-popMonthly [
    set house one-of patches with [hhtype = "household"]
    move-to house
    set age assign-age
    set-human-category
  ]
end 

to-report assign-age
  ;; Randomly assign an age to a new human based on population percentages
  let r random-float 1
  (ifelse
    r < %Under5 [report random 5]
    r < (%Under5 + %5&17) [report 5 + random 13]
    r < (1 - %Seniors) [report 18 + random 48]
    [report 66 + random 35])
end 

to set-human-category
  ;; Assign a category (infant, school-age, adult, senior) and color
  (ifelse
    age < 6 [set category "infant" set color lime]
    age >= 6 and age < 18 [set category "school-age" set color cyan]
    age >= 18 and age < 66 [set category "adult" set color sky]
    [set category "senior" set color blue])
end 

to setup-human-types
  ;; Assign each human a boolean for is-outsider?, is-weekender?, is-vacationist?
  ask humans [
    set is-outsider? random-float 1 < Outsiders
    set is-weekender? random-float 1 < Weekenders
    set is-vacationist? random-float 1 < Vacationists
  ]
end 

; ===== SIMULATION CONTROL PROCEDURES =====

to go
  ;; Main simulation loop, typically called by a "go" button

  ;; 1. Check for temporary population ratio changes
  if temp-change-active? and ticks >= temp-change-end-tick [
    ;; If the current tick passes the end tick for a temporary change, revert
    revert-to-original-ratios
  ]

  ;; 2. Update population ratios if needed
  check-and-update-ratios

  ;; 3. Update the current date (if you store or display it)
  update-current-date

  ;; 4. Stop if we've reached the end of data
  if data-pointer >= data-length [stop]

  ;; 5. Execute main simulation steps
  get-next-record
  check-for-change         ;; Check if number of houses changed this month
  move-humans             ;; Humans move to workplaces, outside, or stay at home
  consume-water           ;; Calculate water usage

  ;; 6. Update consumption tracking
  update-water-consumption
  set total-water-consumption total-water-consumption + water-consumption
  track-water-consumption

  ;; 7. Log results for analysis
  specifics-logfile

  tick  ;; Advance NetLogo's time
end 

to get-next-record
  ;; Moves the data pointer to the next row in 'data'
  set data-pointer data-pointer + 1
  if data-pointer >= data-length [stop]
  set-current-vals
end 

to check-and-update-ratios
  ;; Adjust population ratios if the global ratio variables changed or if a temporary change is in effect
  ifelse temp-change-active? [
    ;; If a temporary change is active, ensure the ratio variables match the temporary ones
    if Outsiders != temp-outsiders or
       Weekenders != temp-weekenders or
       Vacationists != temp-vacationists [
      set Outsiders temp-outsiders
      set Weekenders temp-weekenders
      set Vacationists temp-vacationists
      update-population-ratios
    ]
  ] [
    ;; If not in a temporary change, watch if the user changed the ratio sliders
    if previous-outsiders != Outsiders or
       previous-weekenders != Weekenders or
       previous-vacationists != Vacationists [
      update-population-ratios
      set previous-outsiders Outsiders
      set previous-weekenders Weekenders
      set previous-vacationists Vacationists
    ]
  ]
end 

to check-for-change
  ;; If the monthly data shows a different # of houses than we currently have, adjust the world
  if data-housesMonthly != number-of-houses [
    let diff data-housesMonthly - number-of-houses
    ifelse diff > 0
      [create-new-houses diff]
      [remove-houses (- diff)]
  ]
  set number-of-houses data-housesMonthly
end 

to create-new-houses [n]
  ;; Convert 'n' black patches into households, and create humans in each new house
  ask n-of n patches with [pcolor = black] [
    set pcolor yellow
    set hhtype "household"
    set hhs round random-normal householdSize varHHS
    sprout-humans hhs [
      set house patch-here
      set age assign-age
      set-human-category
      setup-human-types
    ]
  ]
end 

to remove-houses [n]
  ;; Convert 'n' household patches back to black patches, killing any humans there
  ask n-of n patches with [hhtype = "household"] [
    ask humans-here [die]
    set pcolor black
    set hhtype "outside"
  ]
end 

; ===== HUMAN MOVEMENT AND BEHAVIOR =====

to move-humans
  ;; Control movement of human agents based on their type and current conditions
  ask humans [
    ifelse should-go-out? [
      ;; If this human should go out, decide where based on type of day
      ifelse is-outsider? and data-vacation = "none" and not member? data-weekday ["Saturday" "Sunday"]
        ;; 1. Outsiders go to workplace on weekdays if not a vacation day
        [move-to one-of patches with [hhtype = "workplace"]]
        ;; 2. Otherwise, if it's a weekend or a vacation day, go 'outside'
        [if (is-weekender? and member? data-weekday ["Saturday" "Sunday"]) or
            (is-vacationist? and data-vacation != "none")
          [move-to one-of patches with [hhtype = "outside"]]]
    ]
    ;; If the human isn't going out, stay (or return) to their house
    [move-to house]
  ]
end 

to-report should-go-out?
  ;; Decide probabilistically if a human should leave home based on temperature, precip, day-type, etc.
  let temp-factor temperature-factor data-temp
  let precip-factor precipitation-factor data-prcp
  let day-factor day-type-factor data-weekday data-vacation

  let go-out-probability temp-factor * precip-factor * day-factor

  ;; Younger than 5 or older than 65 => reduce their likelihood by 50%
  if age < 5 or age > 65 [set go-out-probability go-out-probability * 0.5]

  report random-float 1 < go-out-probability and (is-outsider? or is-weekender? or is-vacationist?)
end 

to-report temperature-factor [temp]
  ;; Simple example that modifies a factor based on temperature ranges
  (ifelse
    temp < -10 [report 0.5]
    temp < 4 [report 0.5 + (temp + 10) / 28]
    temp < 13 [report 0.75 + (temp - 4) / 36]
    temp < 26 [report 1]
    [report 1 - (temp - 26) / 74])
end 

to-report precipitation-factor [precip]
  ;; A simple linear factor to reduce the probability if precipitation is high
  report 1 - (precip / 100)
end 

to-report day-type-factor [weekday vacation]
  ;; Returns a factor based on day type or vacation
  ifelse vacation != "none"
    [report Vacationists]
    [ifelse member? weekday ["Saturday" "Sunday"]
      [report Weekenders]
      [report Outsiders]]
end 

; ===== WATER CONSUMPTION CALCULATIONS =====

to consume-water
  ;; Calculates water consumption in each household patch and sums the total
  let total-consumption 0
  ask patches with [hhtype = "household"] [
    let occupants count humans-here
    ifelse occupants > 0 [
      ;; If there are occupants, calculate usage
      let tap-consumption occupants * tapUse * Tap-Lt-m
      set tap-eat-drink tap-consumption
      set tap-clean-up tap-consumption
      set tap-maintenance tap-consumption

      ;; Dishwasher usage
      set dw-eat-drink calculate-dw-usage occupants
      set dw-clean-up calculate-dw-usage occupants

      ;; Washing machine usage
      set wm-clean-up calculate-wm-usage occupants
      set wm-maintenance calculate-wm-usage occupants

      ;; Personal usage for toilet & shower
      set toilet-water occupants * toiletUse * Flush-Lt
      set shower-water occupants * showerUse * Shower-Lt-m

      ;; Group consumption by activity
      set eat-and-drink-water tap-eat-drink + dw-eat-drink
      set cleaning-water tap-clean-up + dw-clean-up + wm-clean-up + shower-water + toilet-water
      set maintenance-water tap-maintenance + wm-maintenance

      ;; Sum the consumption from all devices
      let total-appliance-consumption eat-and-drink-water + cleaning-water + maintenance-water

      ;; Apply weather correction factor (fwcf) from the CSV
      let adjusted-consumption ifelse-value (fwcf < 0)
        [total-appliance-consumption - (total-appliance-consumption * abs fwcf)]
        [total-appliance-consumption + (total-appliance-consumption * fwcf)]

      ;; Ensure at least a minimum consumption (base-demand-per-capita * occupants)
      set water-cnsmptn max list (occupants * base-demand-per-capita) adjusted-consumption

      ;; If we had to bump up consumption to meet the min threshold, scale each component
      if water-cnsmptn > adjusted-consumption [
        let scaling-factor water-cnsmptn / adjusted-consumption
        set eat-and-drink-water eat-and-drink-water * scaling-factor
        set cleaning-water cleaning-water * scaling-factor
        set maintenance-water maintenance-water * scaling-factor
      ]
    ][
      ;; If no occupants, consumption is 0
      set water-cnsmptn 0
      set eat-and-drink-water 0
      set cleaning-water 0
      set maintenance-water 0
    ]
    set total-consumption total-consumption + water-cnsmptn
  ]
  set water-consumption total-consumption
end 

to-report calculate-dw-usage [occupants]
  ;; Tracks dishwasher usage. If dw-load >= 1, we run the dishwasher once (DW-Lt).
  set dw-load dw-load + (dwUse * occupants)
  ifelse dw-load >= 1 [
    set dw-load dw-load - 1
    report DW-Lt
  ][
    report 0
  ]
end 

to-report calculate-wm-usage [occupants]
  ;; Tracks washing machine usage. If wm-load >= 1, we run the washing machine once (WM-Lt).
  set wm-load wm-load + (wmUse * occupants)
  ifelse wm-load >= 1 [
    set wm-load wm-load - 1
    report WM-Lt
  ][
    report 0
  ]
end 

to specifics-logfile
  ;; Creates a log entry for the current tick/day and writes it to file or output
  let monthly-water-use ifelse-value monthly-consumption != []
    [precision (monthly-consumption / 1000) 0]
    [0]

  let weekly-water-use ifelse-value weekly-consumption != []
    [precision (weekly-consumption / 1000) 0]
    [0]

  let log-entry (word "date:" data-date
                      " weekday:" data-weekday
                      " vacation:" data-vacation
                      " temp:" data-temp
                      " prcp:" data-prcp
                      " NumberOfHumans:" count humans
                      " NumberOfHouses:" number-of-houses
                      " TotalWaterUse:" (total-water-consumption / 1000)
                      " MonthlyWaterUse:" monthly-water-use
                      " WeeklyWaterUse:" weekly-water-use
                      " NumAdults:" count humans with [age > 17 and age < 66]
                      " NumSeniors:" count humans with [ age > 65]
                      " NumSchAge:" count humans with [ age > 5 and age < 18]
                      " NumInfants:" count humans with [age < 6]
                      " TapWater:" (sum [tap-eat-drink + tap-clean-up + tap-maintenance] of patches / 1000 )
                      " ToiletWater:" (sum [toilet-water] of patches / 1000)
                      " ShowerWater:" (sum [shower-water] of patches / 1000)
                      " WMWater:" (sum [wm-maintenance + wm-clean-up] of patches / 1000)
                      " DWWater:" (sum [dw-eat-drink + dw-clean-up] of patches / 1000) )

  if print-to-logfile? [
    print-to-file log-entry
  ]
  if print-to-output? [
    output-print log-entry
  ]
end 

to print-to-file [file-text]
  ;; Appends a line to the log file (if logfile is valid)
  if is-string? logfile and logfile != "" [
    carefully [
      file-open logfile
      file-print file-text
      file-close
    ] [
      print (word "Error writing to log file: " error-message)
    ]
  ]
end 

to restart-data
  ;; Resets the data pointer and re-initializes consumption counters
  set data-pointer 0
  set data-length length data
  set-current-vals
  output-print "Reset to first record"

  let log-entry (word "\r -- New Session -- " date-and-time)
  if print-to-logfile? [
    carefully [
      print-to-file log-entry
      print-to-file logfile
      print-to-file data-source
    ] [
      print "Error writing to log file"
    ]
  ]

  ;; Reset tracking variables
  set monthly-consumption []
  set weekly-consumption []
  set weekday-consumption 0
  set weekend-consumption 0
  set vacation-consumption 0
  set weekday-consumption-total 0
  set weekend-consumption-total 0
  set vacation-consumption-total 0
  set weekday-count 0
  set weekend-count 0
  set vacation-count 0

  ask patches [
    set water-cnsmptn 0
    set eat-and-drink-water 0
    set cleaning-water 0
    set maintenance-water 0
  ]
  set water-consumption 0

  specifics-logfile
  clear-plots
  reset-ticks
end 

to delete-logfile
  ;; Deletes the current log file if it exists
  if is-string? logfile and file-exists? logfile [
    file-delete logfile
    output-print "Log file deleted"
  ]
end 

to go-data
  ;; If you want to just advance one day in the data, call get-next-record and log, then consume
  get-next-record
  specifics-logfile
  consume-water
  tick
end 

to report-ratio-achievement
  ;; Prints how close we are to the desired ratio of outsiders/weekenders/vacationists
  let total-humans count humans
  let actual-outsiders count humans with [is-outsider?]
  let actual-weekenders count humans with [is-weekender?]
  let actual-vacationists count humans with [is-vacationist?]

  print (word "Desired Outsiders: " Outsiders " Actual: " (actual-outsiders / total-humans))
  print (word "Desired Weekenders: " Weekenders " Actual: " (actual-weekenders / total-humans))
  print (word "Desired Vacationists: " Vacationists " Actual: " (actual-vacationists / total-humans))
end 

to parse-and-set-temp-change [input-string new-outsiders new-weekenders new-vacationists]
  ;; Reads the user input string in format "DD.MM.YYYY duration" and sets temporary ratio changes
  let parts read-from-string (word "[" input-string "]")
  if length parts != 2 [
    user-message "Invalid input format. Please use 'DD.MM.YYYY duration' format."
    stop
  ]

  set temp-outsiders new-outsiders
  set temp-weekenders new-weekenders
  set temp-vacationists new-vacationists
  set temp-change-pending? true
end 

to activate-temporary-change
  ;; Activates a previously scheduled temporary ratio change
  set temp-change-active? true
  set temp-change-pending? false
  set temp-change-start-tick ticks

  set previous-outsiders Outsiders
  set previous-weekenders Weekenders
  set previous-vacationists Vacationists

  set Outsiders temp-outsiders
  set Weekenders temp-weekenders
  set Vacationists temp-vacationists

  update-population-ratios
end 

to revert-to-original-ratios
  ;; Reverts from the temporary ratios back to the original ones
  set Outsiders previous-outsiders
  set Weekenders previous-weekenders
  set Vacationists previous-vacationists
  set temp-change-active? false
  update-population-ratios
end 

to-report date-to-comparable [date-string]
  ;; An example procedure to convert a string date into a comparable numeric value
  let parts remove "." date-string
  report read-from-string (word (item 4 parts) (item 2 parts) (item 0 parts))
end 

to-report date-to-number [date-string]
  ;; Converts date "DD.MM.YYYY" into a single integer YYYYMMDD
  let parts splitt date-string "."
  if length parts != 3 [
    user-message (word "Invalid date format: " date-string ". Please use DD.MM.YYYY format.")
    report false
  ]
  let day read-from-string item 0 parts
  set month read-from-string item 1 parts
  let year read-from-string item 2 parts
  report (year * 10000) + (month * 100) + day
end 

to-report splitt [string delimiter]
  ;; Splits a string on a given delimiter and returns a list
  let result []
  while [not empty? string] [
    let index position delimiter string
    ifelse index != false [
      set result lput (substring string 0 index) result
      set string substring string (index + 1) length string
    ] [
      set result lput string result
      set string ""
    ]
  ]
  report result
end 

to-report extract-month [date-string]
  ;; Extracts the month portion from a "DD.MM.YYYY" string as a number
  let parts split date-string "."
  if length parts != 3 [
    user-message (word "Invalid date format: " date-string ". Please use DD.MM.YYYY format.")
    report false
  ]
  report read-from-string item 1 parts
end 

to-report extract-week [date-string]
  ;; Approximate function to get a week number from a date (not ISO standard)
  let parts split date-string "."
  if length parts != 3 [
    user-message (word "Invalid date format: " date-string ". Please use DD.MM.YYYY format.")
    report false
  ]
  let day read-from-string item 0 parts
  set month read-from-string item 1 parts
  let year read-from-string item 2 parts

  ;; Rough calculation (this is not calendar-accurate but might work for your needs)
  report (((month - 1) * 30 + day) / 7) + 1
end 

to update-current-date
  ;; A placeholder that could update data-date or other date variables each tick if needed.
  ;; For example:
  ;; set data-date read-next-date-from-file
end 

to apply-temporary-ratio-change [start-date new-outsiders new-weekenders new-vacationists duration]
  ;; Another placeholder for a user command that schedules a ratio change
  set temp-outsiders read-from-string2 new-outsiders
  set temp-weekenders read-from-string2 new-weekenders
  set temp-vacationists read-from-string2 new-vacationists
  set temp-change-pending? true
end 

to-report read-from-string2 [str]
  report read-from-string str
end 

to-report date-to-list [date-string]
  ;; Converts "DD.MM.YYYY" to a list [day month year]
  report map [ s -> read-from-string s ] split date-string "."
end 

to-report split [string delimiter]
  ;; Another version of 'split', similar to 'splitt' above
  let result []
  while [not empty? string] [
    let index position delimiter string
    ifelse index != false [
      set result lput (substring string 0 index) result
      set string substring string (index + 1) length string
    ] [
      set result lput string result
      set string ""
    ]
  ]
  report result
end 

to update-water-consumption
  ;; Aggregates daily consumption into monthly and weekly totals, storing them in lists
  ifelse Month != current-month [
    ;; If we have a new month, store the old month's consumption in a list
    if monthly-consumption > 0 [
      set monthly-consumption-list lput monthly-consumption monthly-consumption-list
    ]
    set monthly-consumption water-consumption
    set current-month Month
  ] [
    set monthly-consumption monthly-consumption + water-consumption
  ]

  ifelse Week != current-week [
    ;; If we have a new week, store the old week's consumption in a list
    if weekly-consumption > 0 [
      set weekly-consumption-list lput weekly-consumption weekly-consumption-list
    ]
    set weekly-consumption water-consumption
    set current-week Week
  ] [
    set weekly-consumption weekly-consumption + water-consumption
  ]

  ;; Track daily usage in a list
  set daily-consumption-list lput water-consumption daily-consumption-list

  ;; Update overall average values
  update-average-consumptions
end 

to update-average-consumptions
  ;; Calculate running averages for monthly, weekly, daily consumption
  set average-monthly-consumption ifelse-value not empty? monthly-consumption-list [mean monthly-consumption-list] [0]
  set average-weekly-consumption ifelse-value not empty? weekly-consumption-list [mean weekly-consumption-list] [0]
  set average-daily-consumption ifelse-value not empty? daily-consumption-list [mean daily-consumption-list] [0]
end 

to clear-plots
  ;; Clears named plots so they can be re-drawn
  set-current-plot "Simulation Starters"
  clear-plot
  set-current-plot "Water Demand Estimation"
  clear-plot
  set-current-plot "Household Consumption"
  clear-plot
  set-current-plot "Monthly Water Consumption"
  clear-plot
  set-current-plot "Weekly Water Consumption"
  clear-plot
  set-current-plot "Water Consumption Based on Day Type"
  clear-plot
end 

to update-dependent-variables
  ;; Update any variables that depend on outsider/weekender/vacationist counts
  ask patches with [hhtype = "household"] [
    set working count humans-here with [is-outsider?]
    set weekender count humans-here with [is-weekender?]
    set vacationist count humans-here with [is-vacationist?]
  ]
end 

to go-until
  ;; Run the simulation until a user-specified 'date-to-stop'
  if empty? date-to-stop [
    user-message "Please enter a date to stop in the 'date-to-stop' input box."
    stop
  ]

  let start-date-list date-to-list data-date
  let stop-date-list date-to-list date-to-stop

  if not is-valid-date? start-date-list or not is-valid-date? stop-date-list [
    ;; If either date is invalid, stop
    stop
  ]

  let days-to-run days-between start-date-list stop-date-list

  if days-to-run < 0 [
    user-message "Stop date must be after the current simulation date."
    stop
  ]

  let target-tick ticks + days-to-run

  while [ticks < target-tick and data-pointer < data-length] [
    go
  ]

  if ticks >= target-tick [
    output-print (word "Simulation stopped at " data-date)
  ]
  if data-pointer >= data-length [
    output-print "Reached end of data before stop date."
  ]
end 

to-report days-between [start-date-list stop-date-list]
  ;; Calculate how many days are between two dates (day, month, year)
  let start-day item 0 start-date-list
  let start-month item 1 start-date-list
  let start-year item 2 start-date-list

  let stop-day item 0 stop-date-list
  let stop-month item 1 stop-date-list
  let stop-year item 2 stop-date-list

  let days 0

  ;; Increment day-by-day until start date == stop date
  while [start-year < stop-year
         or (start-year = stop-year and start-month < stop-month)
         or (start-year = stop-year and start-month = stop-month and start-day < stop-day)] [
    set days days + 1
    set start-day start-day + 1
    if start-day > days-in-month start-month start-year [
      set start-day 1
      set start-month start-month + 1
      if start-month > 12 [
        set start-month 1
        set start-year start-year + 1
      ]
    ]
  ]

  report days
end 

to-report is-valid-date? [date-list]
  ;; Quick check that day, month, year are in plausible ranges
  if length date-list != 3 [
    user-message "Invalid date format. Please use DD.MM.YYYY format."
    report false
  ]
  let day item 0 date-list
  set month item 1 date-list
  let year item 2 date-list

  if day < 1 or day > 31 or month < 1 or month > 12 or year < 1900 or year > 2100 [
    user-message "Invalid date values. Please check your input."
    report false
  ]

  report true
end 

to-report days-in-month [month-num year]
  ;; Returns the number of days in a given month, accounting for leap years in February
  let days-list [31 28 31 30 31 30 31 31 30 31 30 31]
  if month-num = 2 and is-leap-year? year [
    report 29
  ]
  report item (month-num - 1) days-list
end 

to-report is-leap-year? [year]
  ;; Standard leap-year check
  report (year mod 4 = 0 and year mod 100 != 0) or (year mod 400 = 0)
end 

to track-water-consumption
  ;; Categorizes today's water consumption into weekday, weekend, or vacation
  set weekday-consumption 0
  set weekend-consumption 0
  set vacation-consumption 0

  ;; If it's not a vacation day
  if data-vacation = "none" [
    ;; Check if it's a weekday or weekend
    ifelse not member? data-weekday ["Saturday" "Sunday"] [
      ;; Weekday
      set weekday-consumption water-consumption
      set weekday-consumption-total weekday-consumption-total + water-consumption
      set weekday-count weekday-count + 1
    ]
    ;; Weekend
    [
      set weekend-consumption water-consumption
      set weekend-consumption-total weekend-consumption-total + water-consumption
      set weekend-count weekend-count + 1
    ]
  ]
  ;; If it is a vacation day, decide if it's specifically "weekend" or other
  ifelse data-vacation = "weekend" [
    set weekend-consumption water-consumption
    set weekend-consumption-total weekend-consumption-total + water-consumption
    set weekend-count weekend-count + 1
  ]
  [
    if data-vacation != "none" [
      set vacation-consumption water-consumption
      set vacation-consumption-total vacation-consumption-total + water-consumption
      set vacation-count vacation-count + 1
    ]
  ]

  ;; Update average usage for each day type
  set avg-weekday-consumption ifelse-value weekday-count > 0
    [weekday-consumption-total / weekday-count] [0]
  set avg-weekend-consumption ifelse-value weekend-count > 0
    [weekend-consumption-total / weekend-count] [0]
  set avg-vacation-consumption ifelse-value vacation-count > 0
    [vacation-consumption-total / vacation-count] [0]
end 

There is only one version of this model, created 16 days ago by Kamil Aybuğa.

Attached files

File Type Description Last updated
WaDemEsT.png preview Preview for 'WaDemEsT' 16 days ago, by Kamil Aybuğa Download

This model does not have any ancestors.

This model does not have any descendants.