def test_model_run_2(self): """Coastal Blue Carbon: Test CBC without analysis year.""" from natcap.invest.coastal_blue_carbon \ import coastal_blue_carbon as cbc self.args['analysis_year'] = None self.args['lulc_baseline_year'] = 2000 self.args['lulc_transition_maps_list'] = [ self.args['lulc_transition_maps_list'][0] ] self.args['lulc_transition_years_list'] = [2005] cbc.execute(self.args) netseq_output_raster = os.path.join( self.args['workspace_dir'], 'outputs_core/total_net_carbon_sequestration_test.tif') netseq_array = _read_array(netseq_output_raster) # (Explanation for why netseq is 10.5.) # LULC Code: Baseline: 1 --> Year 2000: 1, Year 2005: 2 # Initial Stock from Baseline: 5+5=10 # Sequest: # 2000-->2005: (1+1.1)*5=10.5 netseq_test = numpy.array([[cbc.NODATA_FLOAT, 10.5], [10.5, 10.5]]) # just a simple regression test. this demonstrates that a NaN value # will properly propagate across the model. the npv raster was chosen # because the values are determined by multiple inputs, and any changes # in those inputs would propagate to this raster. numpy.testing.assert_allclose(netseq_array, netseq_test, rtol=0, atol=1e-4)
def test_model_no_valuation(self): """Coastal Blue Carbon: Test main model without valuation.""" from natcap.invest.coastal_blue_carbon \ import coastal_blue_carbon as cbc self.args = _get_args(valuation=False, workspace=self.workspace_dir) self.args['lulc_baseline_year'] = 2000 self.args['lulc_transition_years_list'] = [2005, 2010] self.args['analysis_year'] = None cbc.execute(self.args) netseq_output_raster = os.path.join( self.args['workspace_dir'], 'outputs_core/total_net_carbon_sequestration_test.tif') netseq_array = _read_array(netseq_output_raster) # (Explanation for why netseq is 31.) # LULC Code: Baseline: 1 --> Year 2000: 1, Year 2005: 2, Year 2010: 2 # Initial Stock from Baseline: 5+5=10 # Sequest: # 2000-->2005: (1+1.1)*5=10.5, 2005-->2010: (2+2.1)*5=20.5 # Total: 10.5 + 20.5 = 31. netseq_test = numpy.array([[cbc.NODATA_FLOAT, 31.], [31., 31.]]) # just a simple regression test. this demonstrates that a NaN value # will properly propagate across the model. the npv raster was chosen # because the values are determined by multiple inputs, and any changes # in those inputs would propagate to this raster. numpy.testing.assert_array_almost_equal( netseq_array, netseq_test, decimal=4)
def test_no_transitions_with_analysis_year(self): """Coastal Blue Carbon: Model can run w/o trans., w/analysis yr.""" from natcap.invest.coastal_blue_carbon \ import coastal_blue_carbon as cbc args = CBCRefactorTest.create_args( workspace=self.workspace_dir, transition_tuples=None, analysis_year=2010) cbc.execute(args)
def test_no_transitions(self): """Coastal Blue Carbon: Verify model can run without transitions.""" from natcap.invest.coastal_blue_carbon \ import coastal_blue_carbon as cbc args = CBCRefactorTest.create_args( workspace=self.workspace_dir, transition_tuples=None, analysis_year=None) cbc.execute(args)
def test_model_one_transition_no_analysis_year(self): """CBC: Test the model on one transition with no analysis year. This test came up while looking into an issue reported on the forums: https://community.naturalcapitalproject.org/t/coastal-blue-carbon-negative-carbon-stocks/780/12 """ args = TestCBC2._create_model_args(self.workspace_dir) args['workspace_dir'] = os.path.join(self.workspace_dir, 'workspace') prior_snapshots = coastal_blue_carbon._extract_snapshots_from_table( args['landcover_snapshot_csv']) baseline_year = min(prior_snapshots.keys()) baseline_raster = prior_snapshots[baseline_year] with open(args['landcover_snapshot_csv'], 'w') as snapshot_csv: snapshot_csv.write('snapshot_year,raster_path\n') snapshot_csv.write(f'{baseline_year},{baseline_raster}\n') snapshot_csv.write(f'2010,{prior_snapshots[2010]}\n') del args['analysis_year'] # Use valuation parameters rather than price table. args['use_price_table'] = False args['inflation_rate'] = 4 args['price'] = 1.0 coastal_blue_carbon.execute(args) # Check sequestration raster expected_sequestration_2000_to_2010 = numpy.array([[83.5, 0.]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', ('total-net-carbon-sequestration-between-' '2000-and-2010.tif')) try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_sequestration_2000_to_2010) finally: raster = None # Check valuation raster # Discount rate here matches the inflation rate, so the value of the 10 # years' accumulation is just 1*(10 years of accumulation). expected_net_present_value_at_2010 = numpy.array([[835.0, 0.]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', 'net-present-value-at-2010.tif') try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_net_present_value_at_2010, rtol=1e-6) finally: raster = None
def test_model_no_transitions(self): """CBC: Test model without transitions. When the model executes without transitions, we still evaluate carbon sequestration (accumulation only) for the whole baseline period. """ args = TestCBC2._create_model_args(self.workspace_dir) args['workspace_dir'] = os.path.join(self.workspace_dir, 'workspace') prior_snapshots = coastal_blue_carbon._extract_snapshots_from_table( args['landcover_snapshot_csv']) baseline_year = min(prior_snapshots.keys()) baseline_raster = prior_snapshots[baseline_year] with open(args['landcover_snapshot_csv'], 'w') as snapshot_csv: snapshot_csv.write('snapshot_year,raster_path\n') snapshot_csv.write(f'{baseline_year},{baseline_raster}\n') args['analysis_year'] = baseline_year + 10 # Use valuation parameters rather than price table. args['use_price_table'] = False args['inflation_rate'] = 4 args['price'] = 1.0 coastal_blue_carbon.execute(args) # Check sequestration raster expected_sequestration_2000_to_2010 = numpy.array([[83.5, 0.]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', ('total-net-carbon-sequestration-between-' '2000-and-2010.tif')) try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_sequestration_2000_to_2010) finally: raster = None # Check valuation raster # Discount rate here matches the inflation rate, so the value of the 10 # years' accumulation is just 1*(10 years of accumulation). expected_net_present_value_at_2010 = numpy.array([[835.0, 0.]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', 'net-present-value-at-2010.tif') try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_net_present_value_at_2010, rtol=1e-6) finally: raster = None
def test_one_transition(self): """Coastal Blue Carbon: Verify model can run with 1 transition.""" from natcap.invest.coastal_blue_carbon \ import coastal_blue_carbon as cbc transition_tuples = [ (numpy.ones((10, 10)), 2010), ] args = CBCRefactorTest.create_args(workspace=self.workspace_dir, transition_tuples=transition_tuples, analysis_year=None) cbc.execute(args)
def test_duplicate_lulc_classes(self): """CBC: Raise an execption if duplicate lulc-classes.""" args = TestCBC2._create_model_args(self.workspace_dir) args['workspace_dir'] = os.path.join(self.workspace_dir, 'workspace') with open(args['biophysical_table_path'], 'r') as table: lines = table.readlines() with open(args['biophysical_table_path'], 'a') as table: last_line_contents = lines[-1].strip().split(',') last_line_contents[0] = '3' # assign a new code table.write(','.join(last_line_contents)) with self.assertRaises(ValueError) as context: coastal_blue_carbon.execute(args) self.assertIn("`lulc-class` column must be unique", str(context.exception))
def test_1_transition_passes(self): """Coastal Blue Carbon: Test model runs with only 1 transition. This is a regression test addressing issue #3572 (see: https://bitbucket.org/natcap/invest/issues/3572) """ from natcap.invest.coastal_blue_carbon \ import coastal_blue_carbon as cbc self.args['lulc_transition_maps_list'] = \ [self.args['lulc_transition_maps_list'][0]] self.args['lulc_transition_years_list'] = \ [self.args['lulc_transition_years_list'][0]] self.args['analysis_year'] = None try: cbc.execute(self.args) except AttributeError as error: LOGGER.exception("Here's the traceback encountered: %s" % error) self.fail('CBC should not crash when only 1 transition provided')
def test_model_run(self): """Coastal Blue Carbon: Test run function in main model.""" from natcap.invest.coastal_blue_carbon \ import coastal_blue_carbon as cbc self.args['suffix'] = 'xyz' self.args['lulc_baseline_year'] = 2000 self.args['lulc_transition_years_list'] = [2005, 2010] self.args['analysis_year'] = None cbc.execute(self.args) netseq_output_raster = os.path.join( self.args['workspace_dir'], 'outputs_core/total_net_carbon_sequestration_test.tif') npv_output_raster = os.path.join( self.args['workspace_dir'], 'outputs_core/net_present_value_at_2010_test.tif') netseq_array = _read_array(netseq_output_raster) npv_array = _read_array(npv_output_raster) # (Explanation for why netseq is 31.) # LULC Code: Baseline: 1 --> Year 2000: 1, Year 2005: 2, Year 2010: 2 # Initial Stock from Baseline: 5+5=10 # Sequest: # 2000-->2005: (1+1.1)*5=10.5, 2005-->2010: (2+2.1)*5=20.5 # Total: 10.5 + 20.5 = 31. netseq_test = numpy.array([[cbc.NODATA_FLOAT, 31.], [31., 31.]]) npv_test = numpy.array([[cbc.NODATA_FLOAT, 60.27801514], [60.27801514, 60.27801514]]) # just a simple regression test. this demonstrates that a NaN value # will properly propagate across the model. the npv raster was chosen # because the values are determined by multiple inputs, and any changes # in those inputs would propagate to this raster. numpy.testing.assert_allclose(netseq_array, netseq_test, rtol=0, atol=1e-4) numpy.testing.assert_allclose(npv_array, npv_test, rtol=0, atol=1e-4)
def test_binary(self): """Coastal Blue Carbon: Test CBC model against InVEST-Data.""" from natcap.invest.coastal_blue_carbon \ import coastal_blue_carbon as cbc args = { 'workspace_dir': self.args['workspace_dir'], 'carbon_pool_initial_uri': os.path.join( REGRESSION_DATA, 'outputs_preprocessor/carbon_pool_initial_sample.csv'), 'carbon_pool_transient_uri': os.path.join( REGRESSION_DATA, 'outputs_preprocessor/carbon_pool_transient_sample.csv'), 'discount_rate': 6.0, 'do_economic_analysis': True, 'do_price_table': True, 'inflation_rate': 3.0, 'lulc_lookup_uri': os.path.join( REGRESSION_DATA, 'inputs', 'lulc_lookup.csv'), 'lulc_baseline_map_uri': os.path.join( REGRESSION_DATA, 'inputs/GBJC_2010_mean_Resample.tif'), 'lulc_baseline_year': 2010, 'lulc_transition_maps_list': [ os.path.join( REGRESSION_DATA, 'inputs/GBJC_2030_mean_Resample.tif'), os.path.join( REGRESSION_DATA, 'inputs/GBJC_2050_mean_Resample.tif')], 'lulc_transition_years_list': [2030, 2050], 'price_table_uri': os.path.join( REGRESSION_DATA, 'inputs/Price_table_SCC3.csv'), 'lulc_transition_matrix_uri': os.path.join( REGRESSION_DATA, 'outputs_preprocessor/transitions_sample.csv'), 'price': 10.0, 'results_suffix': '150225' } cbc.execute(args) npv_raster = os.path.join( os.path.join( args['workspace_dir'], 'outputs_core/net_present_value_at_2050_150225.tif')) npv_array = _read_array(npv_raster) # this is just a regression test, but it will capture all values # in the net present value raster. the npv raster was chosen because # the values are determined by multiple inputs, and any changes in # those inputs would propagate to this raster. u = numpy.unique(npv_array) u.sort() a = numpy.array([-76992.05, -40101.57, -34930., -34821.32, 0., 108.68, 6975.94, 7201.22, 7384.99], dtype=numpy.float32) a.sort() numpy.testing.assert_array_almost_equal(u, a, decimal=2) # walk through all files in the workspace and assert that outputs have # the file suffix. non_suffixed_files = [] for root_dir, dirnames, filenames in os.walk(self.args['workspace_dir']): for filename in filenames: if not filename.lower().endswith('.txt'): # ignore logfile basename, extension = os.path.splitext(filename) if not basename.endswith('_150225'): path_rel_to_workspace = os.path.relpath( os.path.join(root_dir, filename), self.args['workspace_dir']) non_suffixed_files.append(path_rel_to_workspace) if non_suffixed_files: self.fail('%s files are missing suffixes: %s' % (len(non_suffixed_files), pprint.pformat(non_suffixed_files)))
def test_model(self): """CBC: Test the model's execution.""" args = TestCBC2._create_model_args(self.workspace_dir) args['workspace_dir'] = os.path.join(self.workspace_dir, 'workspace') coastal_blue_carbon.execute(args) # Sample values calculated by hand. Pixel 0 only accumulates. Pixel 1 # has no accumulation (per the biophysical table) and also has no # emissions. expected_sequestration_2000_to_2010 = numpy.array([[83.5, 0]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', ('total-net-carbon-sequestration-between-' '2000-and-2010.tif')) try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_sequestration_2000_to_2010) finally: raster = None expected_sequestration_2010_to_2020 = numpy.array([[-176.9792, 73.5]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', ('total-net-carbon-sequestration-between-' '2010-and-2020.tif')) try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_sequestration_2010_to_2020, rtol=1e-6) finally: raster = None expected_sequestration_2020_to_2030 = numpy.array([[73.5, -28.698004]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', ('total-net-carbon-sequestration-between-' '2020-and-2030.tif')) try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_sequestration_2020_to_2030, rtol=1e-6) finally: raster = None # Total sequestration is the sum of all the previous sequestration. expected_total_sequestration = (expected_sequestration_2000_to_2010 + expected_sequestration_2010_to_2020 + expected_sequestration_2020_to_2030) raster_path = os.path.join(args['workspace_dir'], 'output', 'total-net-carbon-sequestration.tif') try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_total_sequestration, rtol=1e-6) finally: raster = None expected_net_present_value_at_2030 = numpy.array( [[-373.67245, 837.93445]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', 'net-present-value-at-2030.tif') try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_net_present_value_at_2030, rtol=1e-6) finally: raster = None # For emissions, make sure that each of the emissions sum rasters in # the output folder match the sum of all annual emissions from the time # period. for emissions_raster_path in glob.glob( os.path.join(args['workspace_dir'], 'output', 'carbon-emissions-between-*.tif')): try: raster = gdal.OpenEx(emissions_raster_path) band = raster.GetRasterBand(1) emissions_in_period = band.ReadAsArray() finally: band = None raster = None basename = os.path.splitext( os.path.basename(emissions_raster_path))[0] parts = basename.split('-') start_year = int(parts[3]) end_year = int(parts[5]) summed_emissions_over_time_period = numpy.array( [[0.0, 0.0]], dtype=numpy.float32) for year in range(start_year, end_year): for pool in ('soil', 'biomass'): yearly_emissions_raster = os.path.join( args['workspace_dir'], 'intermediate', f'emissions-{pool}-{year}.tif') try: raster = gdal.OpenEx(yearly_emissions_raster) band = raster.GetRasterBand(1) summed_emissions_over_time_period += band.ReadAsArray() finally: band = None raster = None numpy.testing.assert_allclose(emissions_in_period, summed_emissions_over_time_period)
def test_model_no_analysis_year_no_price_table(self): """CBC: Test the model's execution.""" args = TestCBC2._create_model_args(self.workspace_dir) args['workspace_dir'] = os.path.join(self.workspace_dir, 'workspace') del args['analysis_year'] # final year is 2020. args['use_price_table'] = False args['inflation_rate'] = 5 args['price'] = 10.0 coastal_blue_carbon.execute(args) # Sample values calculated by hand. Pixel 0 only accumulates. Pixel 1 # has no accumulation (per the biophysical table) and also has no # emissions. expected_sequestration_2000_to_2010 = numpy.array([[83.5, 0]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', ('total-net-carbon-sequestration-between-' '2000-and-2010.tif')) try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_sequestration_2000_to_2010) finally: raster = None expected_sequestration_2010_to_2020 = numpy.array([[-176.9792, 73.5]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', ('total-net-carbon-sequestration-between-' '2010-and-2020.tif')) try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_sequestration_2010_to_2020, rtol=1e-6) finally: raster = None # Total sequestration is the sum of all the previous sequestration. expected_total_sequestration = (expected_sequestration_2000_to_2010 + expected_sequestration_2010_to_2020) raster_path = os.path.join(args['workspace_dir'], 'output', 'total-net-carbon-sequestration.tif') try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_total_sequestration, rtol=1e-6) finally: raster = None expected_net_present_value_at_2020 = numpy.array( [[-20506.314, 16123.521]], dtype=numpy.float32) raster_path = os.path.join(args['workspace_dir'], 'output', 'net-present-value-at-2020.tif') try: raster = gdal.OpenEx(raster_path) numpy.testing.assert_allclose(raster.ReadAsArray(), expected_net_present_value_at_2020, rtol=1e-6) finally: raster = None