Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derive per county patch library #10

Merged
merged 10 commits into from
Jun 25, 2020
Prev Previous commit
calib: add patch library per subregion
  • Loading branch information
petrasovaa committed May 29, 2020
commit 32180299cd0c1650e2dc8481eaaf7ad1822d0b52
4 changes: 4 additions & 0 deletions r.futures/r.futures.calib/r.futures.calib.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ <h3>Patch size</h3>
produces patch size distribution file specified in <b>patch_sizes</b> parameter,
which contains sizes (in cells) of all new patches observed
in the reference period. The format of this file is one patch size per line.
If flag <b>-s</b> is used, patch sizes will be analyzed per each subregion,
and written as a CSV file with columns representing patch library for each
subregion and header containing
the categories of subregions.
FUTURES uses this file to determine the size of the simulated patches.
Often the length of the reference time period does not match
the time period which we are trying to simulate.
Expand Down
76 changes: 70 additions & 6 deletions r.futures/r.futures.calib/r.futures.calib.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@
#% required: yes
#% guisection: Calibration
#%end
#%flag
#% key: s
#% description: Derive patch sizes per subregions
#% guisection: Calibration
#%end
#%option G_OPT_F_OUTPUT
#% key: calibration_results
#% description: Output file with calibration results
Expand Down Expand Up @@ -219,6 +224,10 @@
#% description: Control file with number of cells to convert
#% guisection: PGA
#%end
#%option G_OPT_F_SEP
#% label: Separator used in output patch file
#% answer: comma
#%end
#%flag
#% key: l
#% description: Only create patch size distribution file
Expand Down Expand Up @@ -270,6 +279,7 @@

import grass.script.core as gcore
import grass.script.raster as grast
import grass.script.utils as gutils
from grass.exceptions import CalledModuleError


Expand Down Expand Up @@ -361,6 +371,7 @@ def run_simulation(development_start, development_end, compactness_mean,
development_pressure_approach=fut_options['development_pressure_approach'], gamma=fut_options['gamma'],
scaling_factor=fut_options['scaling_factor'],
subregions=fut_options['subregions'], demand=fut_options['demand'],
separator=fut_options['separator'],
output=development_end, random_seed=seed, quiet=True)
parameters.update(futures_parameters)
for not_required in ('potential_weight', 'num_steps', 'incentive_power', 'subregions_potential'):
Expand All @@ -380,6 +391,23 @@ def new_development(development_end, development_diff):
dev_end=development_end), overwrite=True, quiet=True)


def patch_analysis_per_subregion(development_diff, subregions, threshold, tmp_clump, tmp_clump_cat):
gcore.run_command('r.clump', input=development_diff, output=tmp_clump, overwrite=True, quiet=True)
cats = gcore.read_command("r.describe", flags="1", map=subregions, quiet=True).strip().splitlines()
subregions_data = {}
env = os.environ.copy()
for cat in cats:
grast.mapcalc('{new} = if ({reg} == {cat}, {clump}, null())'.format(new=tmp_clump_cat, reg=subregions,
cat=cat, clump=tmp_clump),
overwrite=True)
env['GRASS_REGION'] = gcore.region_env(zoom=tmp_clump_cat)
data = gcore.read_command('r.object.geometry', input=tmp_clump_cat,
flags='m', separator='comma', env=env, quiet=True).strip()
data = np.loadtxt(StringIO(data), delimiter=',', usecols=(1, 2), skiprows=1)
subregions_data[cat] = data[data[:, 0] > threshold]
return subregions_data


def patch_analysis(development_diff, threshold, tmp_clump):
gcore.run_command('r.clump', input=development_diff, output=tmp_clump, overwrite=True, quiet=True)
data = gcore.read_command('r.object.geometry', input=tmp_clump, flags='m', separator='comma', quiet=True).strip()
Expand All @@ -399,10 +427,34 @@ def create_histograms(data, hist_bins_area_orig, hist_range_area_orig, hist_bins
return histogram_area, histogram_compactness


def write_patches_file(data, cell_size, output_file):
areas = data[:, 0]
areas = np.round(areas / cell_size)
np.savetxt(fname=output_file, X=np.sort(areas.astype(int)), fmt='%u')
def write_patches_file(data, cell_size, output_file, separator):
if isinstance(data, dict):
array_list = []
keys = list(data.keys())
for key in keys:
areas = data[key][:, 0]
areas = np.round(areas / cell_size)
areas = np.sort(areas.astype(int))
array_list.append(areas)

max_patches = max([len(x) for x in array_list])
new_array_list = []
for array in array_list:
new_array_list.append(np.pad(array, (0, max_patches - len(array)),
'constant', constant_values=-1))
data = np.column_stack(new_array_list)
np.savetxt(output_file, X=data, fmt='%u')
data = np.loadtxt(output_file, dtype=str)
data[data == '-1'] = ''
with open(output_file, 'wb') as f:
f.write(separator.join(keys).encode())
f.write(b'\n')
np.savetxt(f, X=data, delimiter=separator, fmt='%s')
else:
areas = data[:, 0]
areas = np.round(areas / cell_size)
np.savetxt(fname=output_file, X=np.sort(areas.astype(int)),
delimiter=separator, fmt='%u')


def compare_histograms(hist1, hist2):
Expand Down Expand Up @@ -446,13 +498,15 @@ def main():
dev_start = options['development_start']
dev_end = options['development_end']
only_file = flags['l']
patches_per_subregion = flags['s']
if not only_file:
repeat = int(options['repeat'])
compactness_means = [float(each) for each in options['compactness_mean'].split(',')]
compactness_ranges = [float(each) for each in options['compactness_range'].split(',')]
discount_factors = [float(each) for each in options['discount_factor'].split(',')]
patches_file = options['patch_sizes']
threshold = float(options['patch_threshold'])
sep = gutils.separator(options['separator'])
# v.clean removes size <= threshold, we want to keep size == threshold
threshold -= 1e-6

Expand All @@ -469,11 +523,21 @@ def main():
TMP.append(orig_patch_diff)
tmp_clump = tmp_name + 'tmp_clump'
TMP.append(tmp_clump)
if patches_per_subregion:
tmp_cat_clump = tmp_name + 'tmp_cat_clump'
TMP.append(tmp_cat_clump)

gcore.message(_("Analyzing original patches..."))
diff_development(dev_start, dev_end, options['subregions'], orig_patch_diff)
data = patch_analysis(orig_patch_diff, threshold, tmp_clump)
write_patches_file(data, cell_size, patches_file)
data = write_data = patch_analysis(orig_patch_diff, threshold, tmp_clump)
if patches_per_subregion:
subregions_data = patch_analysis_per_subregion(orig_patch_diff, options['subregions'],
threshold, tmp_clump, tmp_cat_clump)
# if there is just one column, write the previous analysis result
if len(subregions_data.keys()) > 1:
write_data = subregions_data
write_patches_file(write_data, cell_size, patches_file, sep)

if only_file:
return

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
discount_factor,compactness_mean,compactness_range,area_error,compactness_error,combined_error
0.10,0.10,0.10,0.97,1.00,0.99
0.10,0.80,0.10,1.00,0.98,0.99
Loading