def simulate_water_quality(tree, cell_res, fn, current_cell=None, precolumbian=False): """ Perform a water quality simulation by doing simulations on each of the cell types (leaves), then adding them together by summing the values of a node's subtrees and storing them at that node. `tree` is the (sub)tree of cell distributions that is currently under consideration. `cell_res` is the size of each cell (used for turning inches of water into volumes of water). `fn` is a function that takes a cell type and a number of cells and returns a dictionary containing runoff, et, and inf as volumes. `current_cell` is the cell type for the present node. """ # Internal node. if 'cell_count' in tree and 'distribution' in tree: n = tree['cell_count'] # simulate subtrees if n != 0: tally = {} for cell, subtree in tree['distribution'].items(): simulate_water_quality(subtree, cell_res, fn, cell, precolumbian) subtree_ex_dist = subtree.copy() subtree_ex_dist.pop('distribution', None) tally = dict_plus(tally, subtree_ex_dist) tree.update(tally) # update this node # effectively a leaf elif n == 0: for pol in get_pollutants(): tree[pol] = 0.0 # Leaf node. elif 'cell_count' in tree and 'distribution' not in tree: n = tree['cell_count'] split = current_cell.split(':') if (len(split) == 2): split.append('') if precolumbian: split[1] = make_precolumbian(split[1]) result = fn('%s:%s:%s' % tuple(split), n) # runoff, et, inf tree.update(result) # water quality if n != 0: soil_type, land_use, bmp = split runoff = result['runoff-vol'] / n liters = get_volume_of_runoff(runoff, n, cell_res) for pol in get_pollutants(): tree[pol] = get_pollutant_load(land_use, pol, liters)
def simulate_water_quality(tree, cell_res, fn, parent_cell=None, current_cell=None): """ Perform a water quality simulation by doing simulations on each type of cells (leaves), then adding them together going upward (summing the values of a node's subtrees and storing them at that node). `parent_cell` is the cell type (a string with a soil type and land use separated by a colon) of the parent of the present node in tree. `current_cell` is the cell type for the present node. `cell_res` is the size of each cell (used for turning inches of water into volumes of water). `tree` is the (sub)tree of cell distributions that is currently under consideration. `fn` is a function that takes a cell type and a number of cells and returns a dictionary containing runoff, et, and inf as volumes. This typically just calls `simulate_cell_year`, but can be set to something else if e.g. a simulation over a different time-scale is desired. """ # Internal node. if 'cell_count' in tree and 'distribution' in tree: # simulate subtrees tally = {} for cell, subtree in tree['distribution'].items(): simulate_water_quality(subtree, cell_res, fn, current_cell, cell) subtree_ex_dist = subtree.copy() subtree_ex_dist.pop('distribution', None) tally = dict_plus(tally, subtree_ex_dist) # update this node tree.update(tally) # Leaf node. elif 'cell_count' in tree and 'distribution' not in tree: # runoff, et, inf n = tree['cell_count'] result = fn(current_cell, n) tree.update(result) # water quality if n != 0: runoff = result['runoff-vol'] / n liters = get_volume_of_runoff(runoff, n, cell_res) land_use = current_cell.split(':')[1] if is_bmp(land_use) or land_use == 'no_till' or \ land_use == 'cluster_housing': land_use = parent_cell.split(':')[1] for pol in get_pollutants(): tree[pol] = get_pollutant_load(land_use, pol, liters)
def simulate_water_quality(tree, cell_res, fn, pct=1.0, current_cell=None, precolumbian=False): """ Perform a water quality simulation by doing simulations on each of the cell types (leaves), then adding them together by summing the values of a node's subtrees and storing them at that node. `tree` is the (sub)tree of cell distributions that is currently under consideration. `pct` is the percentage of calculated water volume to retain. `cell_res` is the size of each cell (used for turning inches of water into volumes of water). `fn` is a function that takes a cell type and a number of cells and returns a dictionary containing runoff, et, and inf as volumes. `current_cell` is the cell type for the present node. """ # Internal node. if 'cell_count' in tree and 'distribution' in tree: n = tree['cell_count'] # simulate subtrees if n != 0: tally = {} for cell, subtree in tree['distribution'].items(): simulate_water_quality(subtree, cell_res, fn, pct, cell, precolumbian) subtree_ex_dist = subtree.copy() subtree_ex_dist.pop('distribution', None) tally = dict_plus(tally, subtree_ex_dist) tree.update(tally) # update this node # effectively a leaf elif n == 0: for pol in get_pollutants(): tree[pol] = 0.0 # Leaf node. elif 'cell_count' in tree and 'distribution' not in tree: # the number of cells covered by this leaf n = tree['cell_count'] # canonicalize the current_cell string split = current_cell.split(':') if (len(split) == 2): split.append('') if precolumbian: split[1] = make_precolumbian(split[1]) current_cell = '%s:%s:%s' % tuple(split) # run the runoff model on this leaf result = fn(current_cell, n) # runoff, et, inf runoff_adjustment = result['runoff-vol'] - (result['runoff-vol'] * pct) result['runoff-vol'] -= runoff_adjustment result['inf-vol'] += runoff_adjustment tree.update(result) # perform water quality calculation if n != 0: soil_type, land_use, bmp = split runoff_per_cell = result['runoff-vol'] / n liters = get_volume_of_runoff(runoff_per_cell, n, cell_res) for pol in get_pollutants(): tree[pol] = get_pollutant_load(land_use, pol, liters)