Skip to content

Commit a2854be

Browse files
committed
remove any occurrence of sys.exit(); set to custom exception; removed redundant calculations for masking in intensification and expansion methods
1 parent 423a24f commit a2854be

8 files changed

Lines changed: 74 additions & 62 deletions

File tree

demeter/change/expansion.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,13 @@ def _expansion(diagnostic, diag_file, spat_ludataharm_sub, kernel_vector_sub, co
109109
trans_mat = np.zeros((l_shs, l_ord, l_ord))
110110

111111
# process PFTs in order
112-
for pft_ord in sorted(order_rules):
112+
for pft_ord in np.unique(order_rules):
113113

114114
# create a copy of the cons_data_sub array
115115
cons_data_sub = cons_data_sub_o.copy()
116116

117-
# lookup PFT and land class name
118-
pft = order_rules.index(pft_ord)
117+
# lookup PFT and final land class
118+
pft = np.where(order_rules == pft_ord)[0][0]
119119
fcs = final_landclasses[pft]
120120

121121
# define intensification targets
@@ -237,22 +237,23 @@ def apply_expansion(log, c, allregnumber, allregmet, spat_ludataharm, spat_regio
237237

238238
# get region and metric from index
239239
regnumber = allregnumber[reg_idx]
240-
metnumber = np.unique(spat_met)[met_idx]
241-
met_ref = met_idx
240+
metnumber = allregmet[reg_idx][met_idx]
241+
metnum_idx = metnumber - 1
242242

243243
# create data subset
244-
spat_ludataharm_sub = spat_ludataharm[(spat_region == regnumber) & (spat_met == metnumber)]
245-
kernel_vector_sub = kernel_vector[(spat_region == regnumber) & (spat_met == metnumber)]
246-
cons_data_sub = cons_data[(spat_region == regnumber) & (spat_met == metnumber)]
244+
reg_met_mask = (spat_region == regnumber) & (spat_met == metnumber)
245+
spat_ludataharm_sub = spat_ludataharm[reg_met_mask]
246+
kernel_vector_sub = kernel_vector[reg_met_mask]
247+
cons_data_sub = cons_data[reg_met_mask]
247248

248249
# calculate expansion for each PFT
249250
exp = _expansion(c.diagnostic, diag_file, spat_ludataharm_sub, kernel_vector_sub, cons_data_sub, reg_idx,
250-
met_ref, order_rules, final_landclasses, c.errortol, constrain_rules, transition_rules,
251+
metnum_idx, order_rules, final_landclasses, c.errortol, constrain_rules, transition_rules,
251252
c.stochastic_expansion, c.selection_threshold, land_mismatch, target_change)
252253

253254
# apply expansion and update transitions
254-
spat_ludataharm[(spat_region == regnumber) & (spat_met == metnumber)], target_change, trans_mat = exp
255-
transitions[(spat_region == regnumber) & (spat_met == metnumber), :, :] += trans_mat
255+
spat_ludataharm[reg_met_mask], target_change, trans_mat = exp
256+
transitions[reg_met_mask, :, :] += trans_mat
256257

257258
# calculate non-achieved change
258259
non_chg = np.sum(abs(target_change[:, :, :])) / 2.

demeter/change/intensification.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,12 @@ def _convert_pft(notdone, int_target, metnumber, pft_toconv, spat_ludataharm_sub
9292
spat_ludataharm_sub[exist_cells, pft_toconv] -= actexpansion
9393

9494
# update the target change values
95-
target_change[reg, metnumber - 1, pft] -= np.sum(actexpansion)
96-
int_target -= np.sum(actexpansion)
97-
target_intensification[metnumber - 1, pft] -= np.sum(actexpansion)
98-
target_change[reg, metnumber - 1, pft_toconv] += np.sum(actexpansion)
99-
target_intensification[metnumber - 1, pft_toconv] += np.sum(actexpansion)
95+
actual_expansion_sum = np.sum(actexpansion)
96+
target_change[reg, metnumber - 1, pft] -= actual_expansion_sum
97+
int_target -= actual_expansion_sum
98+
target_intensification[metnumber - 1, pft] -= actual_expansion_sum
99+
target_change[reg, metnumber - 1, pft_toconv] += actual_expansion_sum
100+
target_intensification[metnumber - 1, pft_toconv] += actual_expansion_sum
100101
trans_mat[exist_cells, pft, pft_toconv] += actexpansion
101102

102103
# account for target change minuscule values when evaluating notdone
@@ -312,20 +313,21 @@ def apply_intensification(log, pass_number, c, spat_region, order_rules, allregn
312313
metnumber = allregmet[reg_idx][met_idx]
313314

314315
# create data subset
315-
spat_ludataharm_sub = spat_ludataharm[(spat_region == regnumber) & (spat_met == metnumber)]
316-
kernel_vector_sub = kernel_vector[(spat_region == regnumber) & (spat_met == metnumber)]
317-
cons_data_sub = cons_data[(spat_region == regnumber) & (spat_met == metnumber)]
316+
reg_met_mask = (spat_region == regnumber) & (spat_met == metnumber)
317+
spat_ludataharm_sub = spat_ludataharm[reg_met_mask]
318+
kernel_vector_sub = kernel_vector[reg_met_mask]
319+
cons_data_sub = cons_data[reg_met_mask]
318320

319321
# calculate intensification
320322
citz = _intensification(c.diagnostic, diag_file, spat_ludataharm_sub, target_intensification, kernel_vector_sub,
321323
cons_data_sub, reg_idx, metnumber, order_rules, final_landclasses, c.errortol,
322324
constrain_rules, target_change, transition_rules, land_mismatch)
323325

324326
# apply intensification
325-
spat_ludataharm[(spat_region == regnumber) & (spat_met == metnumber)], trans_mat, target_change, target_intensification = citz
327+
spat_ludataharm[reg_met_mask], trans_mat, target_change, target_intensification = citz
326328

327329
# log transition
328-
transitions[(spat_region == regnumber) & (spat_met == metnumber), :, :] += trans_mat
330+
transitions[reg_met_mask, :, :] += trans_mat
329331

330332
# calculate non-achieved change
331333
non_chg = np.sum(abs(target_change[:, :, :])) / 2.

demeter/config_reader.py

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
from configobj import ConfigObj
1717

1818

19+
class ValidationException(Exception):
20+
def __init__(self,*args,**kwargs):
21+
Exception.__init__(self,*args,**kwargs)
22+
23+
1924
class ReadConfig:
2025

2126
def __init__(self, config_file):
@@ -191,14 +196,14 @@ def ck_ts(t, st_y, ed_y):
191196
ts = int(t)
192197

193198
if (rng == 0) and (ts != 1):
194-
raise RuntimeError('Parameter "timestep" value must be 1 if only running one year. Your start year and end year are the same in your config file. Exiting...')
199+
raise ValidationException('Parameter "timestep" value must be 1 if only running one year. Your start year and end year are the same in your config file. Exiting...')
195200
elif (rng == 0) and (ts == 1):
196201
return ts
197202

198203
ck = rng / ts
199204

200205
if ck == 0:
201-
raise RuntimeError('Parameter "timestep" value "{0}" is too large for start year of "{1}" and end year of "{2}". Max time step available based on year range is "{3}". Exiting...'.format(t, st_y, ed_y, ed_y - st_y))
206+
raise ValidationException('Parameter "timestep" value "{0}" is too large for start year of "{1}" and end year of "{2}". Max time step available based on year range is "{3}". Exiting...'.format(t, st_y, ed_y, ed_y - st_y))
202207
else:
203208
return ts
204209

@@ -212,7 +217,7 @@ def ck_yr(y, p):
212217
:return: int
213218
"""
214219
if len(y) != 4:
215-
raise RuntimeError('Year must be in four digit format (e.g., 2005) for parameter "{}". Value entered was "{}". Exiting...'.format(p, y))
220+
raise ValidationException('Year must be in four digit format (e.g., 2005) for parameter "{}". Value entered was "{}". Exiting...'.format(p, y))
216221
else:
217222
return int(y)
218223

@@ -227,7 +232,7 @@ def ck_len(s, p, l=30):
227232
:return: string
228233
"""
229234
if len(s) > l:
230-
raise RuntimeError('Length of "{}" exceeds the max length of 20. Please revise. Exiting...'.format(p))
235+
raise ValidationException('Length of "{}" exceeds the max length of 20. Please revise. Exiting...'.format(p))
231236
else:
232237
return s
233238

@@ -244,7 +249,7 @@ def ck_vals(v, p, l):
244249
if v in l:
245250
return v
246251
else:
247-
raise RuntimeError('Value "{0}" not in acceptable values for parameter "{1}". Acceptable values are: {2}. Exiting...'.format(v, p, l))
252+
raise ValidationException('Value "{0}" not in acceptable values for parameter "{1}". Acceptable values are: {2}. Exiting...'.format(v, p, l))
248253

249254
@staticmethod
250255
def ck_limit(v, p, l):
@@ -259,7 +264,7 @@ def ck_limit(v, p, l):
259264
if (v >= l[0]) and (v <= l[1]):
260265
return v
261266
else:
262-
raise RuntimeError('Value "{0}" does not fall within acceptable range of values for parameter {1} where min >= {2} and max <= {3}. Exiting...'.format(v, p, l[0], l[1]))
267+
raise ValidationException('Value "{0}" does not fall within acceptable range of values for parameter {1} where min >= {2} and max <= {3}. Exiting...'.format(v, p, l[0], l[1]))
263268

264269
@staticmethod
265270
def check_exist(f, kind, log):
@@ -296,7 +301,7 @@ def create_dir(d, log):
296301
except Exception as e:
297302
log.error(e)
298303
log.error("ERROR: Failed to create directory.")
299-
sys.exit(1)
304+
raise
300305

301306
@staticmethod
302307
def ck_agg(a, log):
@@ -307,11 +312,11 @@ def ck_agg(a, log):
307312
agg = int(a)
308313
except TypeError:
309314
log.error('"agg_level" parameter must be either 1 or 2. Exiting...')
310-
sys.exit(1)
315+
raise
311316

312317
if agg < 1 or agg > 2:
313318
log.error('"agg_level" parameter must be either 1 or 2. Exiting...')
314-
sys.exit(1)
319+
raise ValidationException
315320

316321
else:
317322
return agg
@@ -433,7 +438,7 @@ def ck_limit(v, p, l):
433438
if (v >= l[0]) and (v <= l[1]):
434439
return v
435440
else:
436-
raise RuntimeError('Value "{0}" does not fall within acceptable range of values for parameter {1} where min >= {2} and max <= {3}. Exiting...'.format(v, p, l[0], l[1]))
441+
raise ValidationException('Value "{0}" does not fall within acceptable range of values for parameter {1} where min >= {2} and max <= {3}. Exiting...'.format(v, p, l[0], l[1]))
437442

438443
@staticmethod
439444
def ck_len(s, p, l=20):
@@ -446,7 +451,7 @@ def ck_len(s, p, l=20):
446451
:return: string
447452
"""
448453
if len(s) > l:
449-
raise RuntimeError('Length of "{}" exceeds the max length of 20. Please revise. Exiting...'.format(p))
454+
raise ValidationException('Length of "{}" exceeds the max length of 20. Please revise. Exiting...'.format(p))
450455
else:
451456
return s
452457

@@ -696,14 +701,14 @@ def ck_ts(t, st_y, ed_y):
696701
ts = int(t)
697702

698703
if (rng == 0) and (ts != 1):
699-
raise RuntimeError('Parameter "timestep" value must be 1 if only running one year. Your start year and end year are the same in your config file. Exiting...')
704+
raise ValidationException('Parameter "timestep" value must be 1 if only running one year. Your start year and end year are the same in your config file. Exiting...')
700705
elif (rng == 0) and (ts == 1):
701706
return ts
702707

703708
ck = rng / ts
704709

705710
if ck == 0:
706-
raise RuntimeError('Parameter "timestep" value "{0}" is too large for start year of "{1}" and end year of "{2}". Max time step available based on year range is "{3}". Exiting...'.format(t, st_y, ed_y, ed_y - st_y))
711+
raise ValidationException('Parameter "timestep" value "{0}" is too large for start year of "{1}" and end year of "{2}". Max time step available based on year range is "{3}". Exiting...'.format(t, st_y, ed_y, ed_y - st_y))
707712
else:
708713
return ts
709714

@@ -717,7 +722,7 @@ def ck_yr(y, p):
717722
:return: int
718723
"""
719724
if len(y) != 4:
720-
raise RuntimeError('Year must be in four digit format (e.g., 2005) for parameter "{}". Value entered was "{}". Exiting...'.format(p, y))
725+
raise ValidationException('Year must be in four digit format (e.g., 2005) for parameter "{}". Value entered was "{}". Exiting...'.format(p, y))
721726
else:
722727
return int(y)
723728

@@ -732,7 +737,7 @@ def ck_len(s, p, l=20):
732737
:return: string
733738
"""
734739
if len(s) > l:
735-
raise RuntimeError('Length of "{}" exceeds the max length of 20. Please revise. Exiting...'.format(p))
740+
raise ValidationException('Length of "{}" exceeds the max length of 20. Please revise. Exiting...'.format(p))
736741
else:
737742
return s
738743

@@ -749,7 +754,7 @@ def ck_vals(v, p, l):
749754
if v in l:
750755
return v
751756
else:
752-
raise RuntimeError('Value "{0}" not in acceptable values for parameter "{1}". Acceptable values are: {2}. Exiting...'.format(v, p, l))
757+
raise ValidationException('Value "{0}" not in acceptable values for parameter "{1}". Acceptable values are: {2}. Exiting...'.format(v, p, l))
753758

754759
@staticmethod
755760
def ck_limit(v, p, l):
@@ -764,7 +769,7 @@ def ck_limit(v, p, l):
764769
if (v >= l[0]) and (v <= l[1]):
765770
return v
766771
else:
767-
raise RuntimeError('Value "{0}" does not fall within acceptable range of values for parameter {1} where min >= {2} and max <= {3}. Exiting...'.format(v, p, l[0], l[1]))
772+
raise ValidationException('Value "{0}" does not fall within acceptable range of values for parameter {1} where min >= {2} and max <= {3}. Exiting...'.format(v, p, l[0], l[1]))
768773

769774

770775
@staticmethod
@@ -779,11 +784,11 @@ def check_exist(f, kind, log):
779784
if kind == 'file' and os.path.isfile(f) is False:
780785
log.error("File not found: {0}".format(f))
781786
log.error("Confirm path and retry.")
782-
sys.exit()
787+
raise IOError
783788
elif kind == 'dir' and os.path.isdir(f) is False:
784789
log.error("Directory not found: {0}".format(f))
785790
log.error("Confirm path and retry.")
786-
sys.exit()
791+
raise IOError
787792
else:
788793
return f
789794

@@ -802,7 +807,7 @@ def create_dir(d, log):
802807
except Exception as e:
803808
log.error(e)
804809
log.error("ERROR: Failed to create directory.")
805-
sys.exit()
810+
raise ValidationException
806811

807812
@staticmethod
808813
def ck_agg(a, log):
@@ -813,11 +818,11 @@ def ck_agg(a, log):
813818
agg = int(a)
814819
except TypeError:
815820
log.error('"agg_level" parameter must be either 1 or 2. Exiting...')
816-
sys.exit(1)
821+
raise ValidationException
817822

818823
if agg < 1 or agg > 2:
819824
log.error('"agg_level" parameter must be either 1 or 2. Exiting...')
820-
sys.exit(1)
825+
raise ValidationException
821826
else:
822827
return agg
823828

@@ -870,10 +875,4 @@ def get_constraints(self):
870875
return l
871876

872877
else:
873-
return list()
874-
875-
if __name__ == "__main__":
876-
877-
ini = '/users/ladmin/repos/github/demeter/example/config.ini'
878-
879-
ReadConfigShuffle(ini, '/users/ladmin/Desktop')
878+
return list()

demeter/constraints.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@
99
"""
1010
import os
1111
import numpy as np
12-
import sys
1312

1413
import demeter.demeter_io.reader as rdr
1514

1615

16+
class ValidationException(Exception):
17+
def __init__(self,*args,**kwargs):
18+
Exception.__init__(self,*args,**kwargs)
19+
20+
1721
class ApplyConstraints:
1822

1923
def __init__(self, allreg, allaez, final_landclasses, user_years, ixr_ixm, allregaez, spat_region, allregnumber,
@@ -97,7 +101,7 @@ def apply_spat_constraints(self):
97101
print("\nERROR: Aggregation numbers for PFT {0} in spatial allocation file sum up to more than 1.".format(i))
98102
print("Please correct and try again.")
99103
print("Exiting...\n")
100-
sys.exit()
104+
raise ValidationException
101105

102106
# if individual values sum to greater than 1
103107
if np.sum(t > 0) > 1:
@@ -193,7 +197,7 @@ def apply_gcam_constraints(self, yr_idx, gcam_landmatrix, spat_landmatrix, ixr_i
193197
print("\nERROR: No aggregation class defined for PFT {0} in the GCAM allocation file".format(self.gcam_landclasses(gix)))
194198
print("Please correct and try again.")
195199
print("Exiting...\n")
196-
sys.exit()
200+
raise ValidationException
197201

198202
# Examine the case of one-to-many recombination (e.g., rockicedesert to snow and sparse). Data is split into
199203
# the new categories following their share in the base land use layer within the considered region,

demeter/logger.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,6 @@ def close_logger(self, log):
8686
"""
8787
handlers = log.handlers[:]
8888
for h in handlers:
89+
h.flush()
8990
h.close()
9091
log.removeHandler(h)

demeter/model.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
from demeter.weight.kernel_density import KernelDensity
2323

2424

25+
class ValidationException(Exception):
26+
def __init__(self,*args,**kwargs):
27+
Exception.__init__(self,*args,**kwargs)
28+
29+
2530
class Demeter(Logger):
2631

2732
def __init__(self,
@@ -301,7 +306,7 @@ def _shuffle(dir, i, oc):
301306
2) the type of run you wish to conduct "standard" or "ensemble"
302307
""")
303308
print('Exiting...')
304-
sys.exit(1)
309+
raise ValidationException
305310

306311
# explode args
307312
ini = args[0]
@@ -313,12 +318,12 @@ def _shuffle(dir, i, oc):
313318
print('ERROR: Config file not found.')
314319
print('You entered: {0}'.format(ini))
315320
print('Please enter a full path file name with extension to config file and retry.')
316-
sys.exit(1)
321+
raise ValidationException
317322

318323
if mode.lower() not in ('standard', 'ensemble'):
319324
print("""ERROR: Run mode passed '{0}' not a valid option. Either select 'standard' or 'ensemble' """.format(mode))
320325
print('Exiting...')
321-
sys.exit(1)
326+
raise ValidationException
322327

323328
# instantiate demeter
324329
dm = Demeter(config=ini)

0 commit comments

Comments
 (0)