Source code for cwatm.hydrological_modules.water_demand.domestic

# -------------------------------------------------------------------------
# Name:        Waterdemand modules
# Purpose: Domestic water demand module for household and municipal water requirements.
# Calculates residential water consumption based on population and per-capita use rates.
# Supports urban water demand modeling with temporal and spatial variations.
#
# Authors:      PB, YS, MS, JdB, DF
# Created:     15/07/2016
# CWatM is licensed under GNU GENERAL PUBLIC LICENSE Version 3.
# -------------------------------------------------------------------------

from cwatm.management_modules import globals
import numpy as np
from cwatm.management_modules.data_handling import (returnBool, binding, cbinding, loadmap, readnetcdf2,
                                                     divideValues)


[docs]class waterdemand_domestic: """ Domestic water demand module for household and municipal water requirements. This class calculates residential water consumption based on population and per-capita use rates. It supports urban water demand modeling with temporal and spatial variations. The module handles both agent-based and traditional demand calculations, supporting surface water and groundwater abstraction fractions. **Global variables** =================================== ========== ====================================================================== ===== Variable [self.var] Type Description Unit =================================== ========== ====================================================================== ===== domWithdrawalVar List Input, domesticWithdrawalvarname, variable name for netCDF str domConsumptionVar List Input, domesticConsuptionvarname, variable name for netCDF str domestic_agent_SW_request_month_m3 Array map of domestic agent surface water request, in million m3 per month Mm3 domestic_agent_GW_request_month_m3 Array map of domestic agent groundwater request, in million m3 per month Mm3 pot_domesticConsumption Array -- M3toM Array Coefficient to change units -- domesticTime List Monthly' when domesticTimeMonthly = True, and 'Yearly' otherwise. str InvCellArea Array Inverse of cell area of each simulated mesh 1/m2 activate_domestic_agents Flag Input, True if activate_domestic_agents = True bool domesticDemand Array Domestic demand m swAbstractionFraction_domestic Array With domestic agents, derived from surface water over total water requ % demand_unit Flag -- sectorSourceAbstractionFractions Array -- swAbstractionFraction_Channel_Domes Array Input, Fraction of Domestic demands to be satisfied with Channel % swAbstractionFraction_Lift_Domestic Array Input, Fraction of Domestic demands to be satisfied with Lift % swAbstractionFraction_Res_Domestic Array Input, Fraction of Domestic demands to be satisfied with Reservoirs % swAbstractionFraction_Lake_Domestic Array Input, Fraction of Domestic demands to be satisfied with Lake % gwAbstractionFraction_Domestic Array Fraction of domestic water demand to be satisfied by groundwater % dom_efficiency Array -- =================================== ========== ====================================================================== ===== Attributes ---------- var : object Model variables container from parent model model : object Parent CWatM model instance """ def __init__(self, model): """ Initialize the domestic water demand module. Parameters ---------- model : object The CWatM model instance containing variables and methods """ self.var = model.var self.model = model
[docs] def initial(self): """ Initialize domestic water demand parameters and variables. Sets up time resolution (monthly/yearly), variable names for withdrawal and consumption, agent-based domestic demand parameters, and abstraction fractions for different water sources (surface water, groundwater, channels, reservoirs, lakes). """ if "domesticTimeMonthly" in binding: if returnBool('domesticTimeMonthly'): self.var.domesticTime = 'monthly' else: self.var.domesticTime = 'yearly' else: self.var.domesticTime = 'monthly' if "domesticWithdrawalvarname" in binding: self.var.domWithdrawalVar = cbinding("domesticWithdrawalvarname") else: self.var.domWithdrawalVar = "domesticGrossDemand" if "domesticConsuptionvarname" in binding: self.var.domConsumptionVar = cbinding("domesticConsuptionvarname") else: self.var.domConsumptionVar = "domesticNettoDemand" self.var.domestic_agent_SW_request_month_m3 = globals.inZero.copy() self.var.domestic_agent_GW_request_month_m3 = globals.inZero.copy()
[docs] def dynamic(self, wd_date): """ Calculate dynamic domestic water demand for the current time step. Reads monthly or yearly water demand from NetCDF files and transforms units to m/day if necessary. Handles both agent-based domestic demand (with predefined monthly requests) and traditional demand calculation from input files. Applies scaling factors and calculates abstraction fractions for different water sources. Parameters ---------- wd_date : datetime Current simulation date for reading time-dependent data """ if self.var.domesticTime == 'monthly': new = 'newMonth' else: new = 'newYear' if globals.dateVar['newStart'] or globals.dateVar[new]: if self.var.activate_domestic_agents: # Domestic agents have monthly surface and groundwater requests, at CWatM cellular resolution. # # The settings sw_agentsDomestic_month_m3, and gw_agentsDomestic_month_m3 are static maps # with the monthly water demand in cubic metres at CWatM resolution. # # The setting domestic_agents_fracConsumptionWithdrawal is a static map # with the ratio of consumption to withdrawal for domestic agents. if 'domestic_agent_SW_request_month_m3' in binding: self.var.domestic_agent_SW_request_month_m3 = ( loadmap('domestic_agent_SW_request_month_m3') + globals.inZero.copy()) if 'domestic_agent_GW_request_month_m3' in binding: self.var.domestic_agent_GW_request_month_m3 = ( loadmap('domestic_agent_GW_request_month_m3') + globals.inZero.copy()) self.var.domesticDemand = (self.var.domestic_agent_SW_request_month_m3 + self.var.domestic_agent_GW_request_month_m3) self.var.swAbstractionFraction_domestic = np.where( self.var.domesticDemand > 0, divideValues(self.var.domestic_agent_SW_request_month_m3, self.var.domesticDemand), 0) # domesticDemand and domesticConsumption are transformed below from million m3 per month to m/day self.var.demand_unit = False self.var.domesticDemand /= 1000000 if 'domestic_agents_fracConsumptionWithdrawal' in binding: self.var.pot_domesticConsumption = ( self.var.domesticDemand.copy() * loadmap('domestic_agents_fracConsumptionWithdrawal')) else: self.var.pot_domesticConsumption = self.var.domesticDemand.copy() * 0.2 if self.var.sectorSourceAbstractionFractions: self.var.swAbstractionFraction_Channel_Domestic *= self.var.swAbstractionFraction_domestic self.var.swAbstractionFraction_Lift_Domestic *= self.var.swAbstractionFraction_domestic self.var.swAbstractionFraction_Res_Domestic *= self.var.swAbstractionFraction_domestic self.var.swAbstractionFraction_Lake_Domestic *= self.var.swAbstractionFraction_domestic self.var.gwAbstractionFraction_Domestic = 1 - self.var.swAbstractionFraction_domestic else: self.var.swAbstractionFraction_Channel_Domestic = ( self.var.swAbstractionFraction_domestic.copy()) self.var.swAbstractionFraction_Lift_Domestic = ( self.var.swAbstractionFraction_domestic.copy()) self.var.swAbstractionFraction_Res_Domestic = ( self.var.swAbstractionFraction_domestic.copy()) self.var.swAbstractionFraction_Lake_Domestic = ( self.var.swAbstractionFraction_domestic.copy()) self.var.gwAbstractionFraction_Domestic = 1 - self.var.swAbstractionFraction_domestic else: self.var.domesticDemand = readnetcdf2('domesticWaterDemandFile', wd_date, self.var.domesticTime, value=self.var.domWithdrawalVar) self.var.pot_domesticConsumption = readnetcdf2('domesticWaterDemandFile', wd_date, self.var.domesticTime, value=self.var.domConsumptionVar) # Allows for user to scale domestic demand and potential consumption through the settings file. # Domestic demand and potential consumption will be multiplied by the scaling factor. if 'scale_domestic_demand' in binding: scale_domestic_demand = loadmap('scale_domestic_demand') + globals.inZero self.var.domesticDemand = self.var.domesticDemand * scale_domestic_demand self.var.pot_domesticConsumption = ( self.var.pot_domesticConsumption * scale_domestic_demand) # avoid small values (less than 1 m3): self.var.domesticDemand = np.where(self.var.domesticDemand > self.var.InvCellArea, self.var.domesticDemand, 0.0) self.var.pot_domesticConsumption = np.where( self.var.pot_domesticConsumption > self.var.InvCellArea, self.var.pot_domesticConsumption, 0.0) self.var.dom_efficiency = divideValues(self.var.pot_domesticConsumption, self.var.domesticDemand) # transform from mio m3 per year (or month) to m/day if necessary if not self.var.demand_unit: if self.var.domesticTime == 'monthly': timediv = globals.dateVar['daysInMonth'] else: timediv = globals.dateVar['daysInYear'] self.var.domesticDemand = self.var.domesticDemand * 1000000 * self.var.M3toM / timediv self.var.pot_domesticConsumption = (self.var.pot_domesticConsumption * 1000000 * self.var.M3toM / timediv)