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 153 times • Downloaded 15 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.)


WHAT IS IT?

This model simulates household water consumption patterns in an urban environment.

Its current setup compares monthly water consumption data, and the results of a daily heuristic water demand model with the simulation results produced by household demographics that is fine tuned via some base demand model.

It's designed to estimate and analyze water demand based on various factors including:

  • Household demographics
  • Daily routines of residents (working, weekending, vacation patterns)
  • Weather conditions (temperature and precipitation)
  • Appliance usage patterns
  • Seasonal variations
  • Special periods (weekends and holidays)

The model aims to help understand how different factors influence residential water consumption and can be used for water demand forecasting and management planning.

HOW IT WORKS

The model operates through several key mechanisms:

SimulationFlow

Here all of the key specifications would be explained briefly.

Spatial Environment:

  • Creates a grid world representing residential areas, workplaces, and outside areas
  • Households are represented by yellow patches
  • Workplaces are represented by grey patches
  • Other areas are represented by black patches

SpatialEnvironment

Population Dynamics:

Creates human agents with different characteristics:

Age groups (infants, school-age, adults, seniors) Movement patterns (outsiders, weekenders, vacationists)

Each household has a variable number of residents

Population

Water Consumption Calculation:

WaterConsumption

Tracks usage of different water-consuming appliances:

  • Taps
  • Toilets
  • Showers
  • Washing machines
  • Dishwashers

Calculates consumption based on:

  • Number of occupants present
  • Usage frequency
  • Water efficiency rates
  • Weather factors
  • Day type (weekday/weekend/vacation)

ConsumptionCalculation

Decision Procedure:

Decisions are taken under the effect of a few different procedures.

DecisionProcedure

HOW TO USE IT

  • WaDemEsT 1.0 requires you to load a CSV file that contains required information to handle some external simulation parameters. Current configuration of the CSV file is as shown below:

CSV File

However you could easily drop out unwanted parameters from your CSV setup. Just don't forget to drop the related parts of the code corresponding to CSV variables that you cancelled.

DataCode

  • WaDemEsT 1.0 requires you to adjust certain parameters before producing simulations.

AdjustingParameters

Those steps are shown above, and explained below starting from "Setting Simulation Environment" step. But "Simulation Controls" deserve mentioning beforehand:

Simulation Controls:

  1. Load Data - Load the CSV file with required time series data
  2. Setup - Initialize the simulation environment
  3. Clear All - Reset the entire simulation
  4. Restart Data - Restarts the data variables coming for CSV file, to prepare restarting the simulation
  5. Delete log - Deletes the log file refreshing the simulation memory
  6. Clear All - Reset the entire simulation
  7. Go-Data - Runs data alone for viewing the change of environmental conditions shown on "Simulation Starters" plot.
  8. Go-Once - just lets simulation environment to run along one tick only.
  9. Go-forever - lets simulation run till the end of the date value indicated on CSV file.
  10. Go-until - lets user to indicate a date to stop the simulation, to adjust parameters of the simulation,if needed.

Controls

Setting Simulation Environment

  • householdSize - Average number of people per household
  • varHHS - Variance in household size
  • residenceRatio - Ratio of residential to non-residential areas

SetupEnvironment

  1. Adjust residenceRatio (lets the simluation environment to be shaped as yellow and gray patches, so you can approximate the residental areas real conditions)
  2. Adjust the householdSize (you should give simulation an average number of inhabitants to fill the created houses)
  3. Adjust varHHS (Variance of average household number makes you able to indicate the extreme points in your household population such as single person or 4 or more people households)

Demographic Parameters:

  • %Under5 - Percentage of population under 5 years
  • %5&17 - Percentage of population between 5-17 years
  • %Seniors - Percentage of senior population

Demographics

  1. Set the rate of seniors via %Seniors slider (You should indicate the rate of people above 65)
  2. Set the rate of infants via %Under5 slider (This indicates the rate of children living dependent on mother's care, thus leads the rise of people staying home)
  3. Set the rate of students via %5%17 slider (This parameter lets you control the preference of people going outside during the weekdays)

Number of adults calculated subtracting the total numbers of groups above from the >total number of people set by the CSV file.

Appliance Performance and Usage Parameters:

  • tapUse - Frequency of tap usage
  • toiletUse - Frequency of toilet usage
  • showerUse - Frequency of shower usage
  • wmUse - Frequency of washing machine usage
  • dwUse - Frequency of dishwasher usage

  • Tap-Lt-m - Liters per minute for taps

  • Flush-Lt - Liters per toilet flush

  • Shower-Lt-m - Liters per minute for showers

  • WM-Lt - Liters per washing machine cycle

  • DW-Lt - Liters per dishwasher cycle

Appliances

Behavioral Parameters:

  • Outsiders - Proportion of people who leave for work
  • Weekenders - Proportion of people who leave during weekends
  • Vacationists - Proportion of people who leave during vacations

Preferences

Rates of the people going outside for different calendar day types, should be indicated via respective sliders.

All preferences could be dynamically adjusted during the simulation time. Only thing to consider for calculation consistency, just avoid changing sliders
without stopping the simulation, to make sure producing correct results.

Output Options:

  • print-to-logfile? - Toggle logging to file
  • print-to-output? - Toggle console output

Outputs

THINGS TO NOTICE

Consumption Patterns:

  • Observe how water consumption varies between weekdays and weekends
  • Notice the impact of vacations on overall consumption
  • Watch for seasonal patterns in water usage

Population Movement:

  • Track how people move between homes, workplaces, and outside areas
  • Observe the effect of weather on movement patterns

Visualization:

Multiple plots showing different aspects of water consumption:

  • Daily consumption patterns
  • Monthly trends
  • Weekly variations
  • Appliance-specific usage

Weather Effects:

  • Notice how temperature and precipitation affect behavior and consumption
  • Observe seasonal variations in water usage patterns

THINGS TO TRY

Demographic Experiments:

  1. Adjust household size and variance to see impact on consumption
  2. Modify age group distributions and observe changes
  3. Change the ratio of outsiders/weekenders/vacationists

Appliance Usage Scenarios:

  1. Modify appliance efficiency parameters
  2. Adjust usage frequencies
  3. Compare impact of different appliances on total consumption

Weather Impact Analysis:

  1. Run simulation during different seasons
  2. Compare consumption patterns during extreme weather conditions
  3. Analyze how precipitation affects outdoor water usage

Special Period Analysis:

  1. Compare weekday vs weekend consumption
  2. Analyze holiday period water usage
  3. Study vacation period patterns

EXTENDING THE MODEL

Additional Features:

  • Add water pricing mechanisms
  • Implement water conservation behaviors
  • Include commercial water usage
  • Add water supply constraints
  • Implement emergency scenarios

Enhanced Demographics:

  • Add income levels
  • Include cultural factors
  • Implement household types (apartments, houses)
  • Add social network effects

Environmental Factors:

  • Include humidity effects
  • Add seasonal activities
  • Implement drought conditions
  • Add water quality factors

Behavioral Patterns:

  • Add learning behaviors
  • Implement conservation awareness
  • Include peer influence
  • Add policy response behaviors

RELATED NETLOGO MODELS

  1. SequentialtimeseriesusingCSV by Doug Edmunds (Author) https://modelingcommons.org/browse/onemodel/4990#modeltabsbrowse_info

CREDITS AND REFERENCES

Author: Kamil AYBUĞA 2024

Key References:

  1. Edmunds, Doug (2017). TimeSeries-core.nlogo v1.5
  2. Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.

Model code and documentation developed using NetLogo 6.4.0.

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 4 months ago by Kamil Aybuğa.

Attached files

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

This model does not have any ancestors.

This model does not have any descendants.