├── README.md ├── data └── data.py ├── evaluation.py ├── ground_truth.py ├── hydraulics ├── boundary.py ├── saint_venant.py └── simulation_utils.py ├── main.py ├── models ├── averagenet.py ├── detour.py ├── edge_preserving.py └── swe_model.py ├── requirements.txt ├── source ├── 001 │ ├── ned232_20200818_172734.png │ └── ned232_20200818_172734.txt ├── 002 │ ├── ned69_20200818_175155.png │ └── ned69_20200818_175155.txt ├── 003 │ ├── ned173_20200818_174748.png │ └── ned173_20200818_174748.txt ├── source.py └── utils.py ├── trainer.py └── utils ├── __pycache__ └── tensorboard.cpython-38.pyc ├── evaluation_template.html ├── evaluation_viewer.py ├── meters.py ├── model_utils.py ├── optimization.py ├── tensorboard.py └── visualization.py /README.md: -------------------------------------------------------------------------------- 1 | # Physics Aware Downsampling 2 | 3 | This code was used to implement: Physics-Aware Downsampling with Deep Learning for Scalable Flood Modeling (2021) 4 | 5 | ## Dependencies 6 | ``` 7 | pip install -r requirements.txt 8 | pip install tensorboard 9 | ``` 10 | 11 | ## Data 12 | 13 | The data size (+source files) is around ~300GB. 14 | ### Downloading data 15 | 1. The source files are listed in the **source** directory. Run the following command to download tif source files: 16 | ``` 17 | wget -i source/001/ned232_20200818_172734.txt -P /home/usgs_dem_data_source/001 18 | wget -i source/002/ned69_20200818_175155.txt -P /home/usgs_dem_data_source/002 19 | wget -i source/003/ned173_20200818_174748.txt -P /home/usgs_dem_data_source/003 20 | ``` 21 | 2. After the tif files are downloaded, run **source.py** (under **source** directory). This will process the source files and construct an index for the dataset. 22 | 3. Lastly, run **ground_truth.py** to calculate fine resolution hydraulic solutions. To save time, the calculation is done in parallel. Configure the number of GPUs to use in **ground_truth.py**. 23 | 24 | ## Example 25 | 26 | For distributed training with 4 GPUs, batch size of 4 per GPU, and SGD optimization: 27 | ``` 28 | python -m torch.distributed.launch --nproc_per_node=4 main.py --batch_size 4 --epochs 50 --optimizer sgd 29 | ``` 30 | For a single sample evaluation, use the simulation mode: 31 | ``` 32 | python evaluation.py --sample #sample_num --model #path_to_model 33 | ``` 34 | For a complete test set evaluation: 35 | ``` 36 | python evaluation.py --model #path_to_model 37 | ``` 38 | -------------------------------------------------------------------------------- /data/data.py: -------------------------------------------------------------------------------- 1 | import enum 2 | import logging 3 | from ast import literal_eval 4 | 5 | import numpy as np 6 | import pandas as pd 7 | import torch 8 | 9 | 10 | class GroundTruthType(enum.Enum): 11 | RAIN, FLUX = range(2) 12 | 13 | 14 | FLUX_INDEX_PATH = '/home/usgs_dem_data/flux_ground_truth/' 15 | RAIN_INDEX_PATH = '/home/usgs_dem_data/rain_ground_truth/' 16 | TRAIN_INDEX_NAME = 'train_ground_truth_index.csv' 17 | TEST_INDEX_NAME = 'test_ground_truth_index.csv' 18 | 19 | INDEX_MAPPING = {GroundTruthType.RAIN: RAIN_INDEX_PATH, 20 | GroundTruthType.FLUX: FLUX_INDEX_PATH} 21 | 22 | 23 | class USGS(torch.utils.data.Dataset): 24 | def __init__(self, transform=None, target_transform=None, 25 | ground_truth_type=GroundTruthType.RAIN, train_set=True): 26 | file_name = TRAIN_INDEX_NAME if train_set else TEST_INDEX_NAME 27 | index_path = INDEX_MAPPING[ground_truth_type] + file_name 28 | self.ground_truth_type = ground_truth_type 29 | self.index = pd.read_csv(index_path, names=[ 30 | 'dem', 'influx', 'outflux', 'discharge', 'target_time', 31 | 'ground_truth', 'alpha', 'theta', 'min_h_n']) 32 | self.transform = transform 33 | self.target_transform = target_transform 34 | self.dtype = torch.float 35 | self.resolution = 1 # 1X1 meter resolution 36 | self.grid_size = 2000 # 2000X2000 pixels 37 | self.boundary_type = ( 38 | 'rain' if ground_truth_type == GroundTruthType.RAIN else 'flux') 39 | self.simulation = False # Flag for simulation mode 40 | self.simulation_sample = None 41 | 42 | def __len__(self): 43 | return len(self.index) 44 | 45 | def __getitem__(self, item): 46 | item = item if not self.simulation else self.simulation_sample 47 | if self.ground_truth_type == GroundTruthType.RAIN: 48 | return self._read_rain_index_row(item) 49 | else: 50 | return self._read_index_row(item) 51 | 52 | def simulation_mode(self, sample): 53 | logging.info(f'simulation mode enabled with sample number {sample}') 54 | self.simulation = True 55 | self.simulation_sample = sample 56 | 57 | def _read_index_row(self, row: int): 58 | if self.simulation: 59 | logging.info('DEM Path: ' + self.index.iloc[row]['dem']) 60 | logging.info( 61 | 'Ground-Truth Path: ' + self.index.iloc[row]['ground_truth']) 62 | dem = torch.from_numpy(np.load(self.index.iloc[row]['dem'])) 63 | dem = dem.reshape(1, *dem.shape) 64 | 65 | influx = torch.as_tensor( 66 | literal_eval(self.index.iloc[row]['influx']), dtype=self.dtype) 67 | outflux = torch.as_tensor( 68 | literal_eval(self.index.iloc[row]['outflux']), dtype=self.dtype) 69 | discharge = torch.as_tensor(self.index.iloc[row]['discharge'], 70 | dtype=self.dtype) 71 | time_stamp = torch.as_tensor(self.index.iloc[row]['target_time'], 72 | dtype=self.dtype) 73 | h_n = np.load(self.index.iloc[row]['ground_truth'], allow_pickle=True) 74 | h_n = torch.from_numpy(h_n).reshape(1, *h_n.shape) 75 | if self.transform is not None: 76 | dem = self.transform(dem) 77 | else: 78 | dem.sub_(dem.mean()) 79 | if self.target_transform is not None: 80 | h_n = self.target_transform(h_n) 81 | return dem, influx, outflux, discharge, time_stamp, h_n 82 | 83 | def _read_rain_index_row(self, row: int): 84 | dem = torch.from_numpy(np.load(self.index.iloc[row]['dem'])) 85 | dem = dem.reshape(1, *dem.shape) 86 | 87 | rain_fall = torch.as_tensor(self.index.iloc[row]['discharge'], 88 | dtype=self.dtype) 89 | time_stamp = torch.as_tensor(self.index.iloc[row]['target_time'], 90 | dtype=self.dtype) 91 | h_n = np.load(self.index.iloc[row]['ground_truth'], allow_pickle=True) 92 | h_n = torch.from_numpy(h_n).reshape(1, *h_n.shape) 93 | if self.transform is not None: 94 | dem = self.transform(dem) 95 | else: 96 | dem.sub_(dem.mean()) 97 | if self.target_transform is not None: 98 | h_n = self.target_transform(h_n) 99 | return dem, rain_fall, time_stamp, h_n 100 | -------------------------------------------------------------------------------- /evaluation.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import csv 3 | import datetime 4 | import json 5 | import os 6 | from typing import Dict, NamedTuple 7 | 8 | import torch 9 | import torch.nn as nn 10 | from absl import app 11 | from absl import flags 12 | from absl import logging 13 | from torch.utils.data import distributed as dist_data 14 | 15 | import trainer 16 | from data import data 17 | from hydraulics import boundary 18 | from hydraulics import saint_venant 19 | from models import averagenet 20 | from models import edge_preserving 21 | from models import detour 22 | from models import swe_model 23 | from utils import optimization 24 | from utils import visualization 25 | 26 | _get_dtype = {'float32': torch.float32, 27 | 'float16': torch.float16, 28 | 'float64': torch.float64} 29 | 30 | FLAGS = flags.FLAGS 31 | 32 | flags.DEFINE_string('comment', '', 33 | 'Comment for run. Ignored of log_dir is provided') 34 | flags.DEFINE_string('device', 'cuda', 'Device to use.') 35 | flags.DEFINE_string('dtype', 'float32', 36 | f'Data type to use. {_get_dtype.keys()}') 37 | flags.DEFINE_boolean('debug', False, 'Produces debugging output.') 38 | flags.DEFINE_integer('batch_size', 16, 'Batch size. Can be used only when' 39 | ' sample is not provided.') 40 | flags.DEFINE_enum('criterion', 'mse', ['mse', 'smooth_l1', 'inundation'], 41 | 'Loss function.') 42 | flags.DEFINE_enum('regularization', 'smooth_l1', ['mse', 'smooth_l1'], 43 | 'Regularization loss function.') 44 | flags.DEFINE_float('regularization_lambda', 0.0, 'Regularization lambda.') 45 | flags.DEFINE_enum('ground_truth_type', 'rain', ['flux', 'rain'], 46 | 'Type of ground truth.') 47 | flags.DEFINE_float('alpha', 0.7, 'CFL condition coefficient.') 48 | flags.DEFINE_float('theta', 0.7, 'q centered weighting. [0,1].') 49 | flags.DEFINE_integer('ds_factor', 16, 'Downsample factor from fine to coarse.') 50 | flags.DEFINE_enum('model_type', 'averaging', ['edge_preserve', 'averaging'], 51 | 'Down sample model') 52 | flags.DEFINE_string('model', '', 'Path to model to use. Default is AverageNet') 53 | flags.DEFINE_integer('sample', None, 'Sample number to simulate on.') 54 | flags.DEFINE_boolean('use_train_set', False, 55 | 'Use train set as index instead of test set.') 56 | 57 | 58 | def _get_criterion(criterion: str): 59 | return {'mse': nn.MSELoss, 'smooth_l1': nn.SmoothL1Loss, 60 | 'inundation': optimization.InundationLoss}[criterion]() 61 | 62 | 63 | def _flags_to_dict() -> Dict: 64 | names = [x.name for x in FLAGS.get_key_flags_for_module('evaluation.py')] 65 | values = [x.value for x in FLAGS.get_key_flags_for_module('evaluation.py')] 66 | return {name: value for name, value in zip(names, values)} 67 | 68 | 69 | def _namedtuple_to_json_file(args: NamedTuple, filename: str): 70 | """Converts namedtuple to readable dict format and saves it as json file.""" 71 | args_dict = [] 72 | for k, v in args._asdict().items(): 73 | if type(v) in {bool, str, int, float}: 74 | args_dict.append({'Name': k, 'Value': v}) 75 | elif k == 'criterion' or k == 'regularization': 76 | args_dict.append({'Name': k, 'Value': type(v).__name__}) 77 | with open(filename, 'w') as f: 78 | json.dump(args_dict, f) 79 | 80 | 81 | def _hyper_parameters(coarse_grid_size, coarse_resolution, 82 | train_data, log_dir): 83 | params = _flags_to_dict() 84 | 85 | params['scale_factor'] = coarse_resolution // train_data.resolution 86 | params['boundary_type'] = boundary.BoundaryType[ 87 | train_data.boundary_type.upper()] 88 | params['criterion'] = _get_criterion(FLAGS.criterion).to( 89 | FLAGS.device, dtype=_get_dtype[FLAGS.dtype]) 90 | params['dtype'] = _get_dtype[params['dtype']] 91 | params['coarse_dx'] = coarse_resolution 92 | params['coarse_n_x'] = coarse_grid_size 93 | params['fine_dx'] = train_data.resolution 94 | params['local_rank'] = -1 95 | params['log_dir'] = log_dir 96 | Args = collections.namedtuple('HyperParameters', sorted(params)) 97 | return Args(**params) 98 | 99 | 100 | def main(_): 101 | if FLAGS.debug: 102 | torch.set_printoptions(precision=5, linewidth=230, sci_mode=False) 103 | FLAGS.alsologtostderr = True 104 | current_time = datetime.datetime.now().strftime('%d-%m-%Y_%H-%M-%S') 105 | log_dir = os.path.join('evaluations', current_time + '_' + FLAGS.comment) 106 | if not os.path.exists(log_dir): 107 | os.mkdir(log_dir) 108 | logging.get_absl_handler().use_absl_log_file('Logger', log_dir) 109 | 110 | ground_truth_type = data.GroundTruthType[FLAGS.ground_truth_type.upper()] 111 | train_data = data.USGS(ground_truth_type=ground_truth_type, 112 | train_set=FLAGS.use_train_set) 113 | simulation_mode = True if FLAGS.sample is not None else False 114 | if simulation_mode: 115 | train_data.simulation_mode(FLAGS.sample) 116 | batch_size = 1 if simulation_mode else FLAGS.batch_size 117 | train_data_loader = torch.utils.data.DataLoader(train_data, 118 | batch_size=batch_size) 119 | coarse_grid_size = int(train_data.grid_size // FLAGS.ds_factor) 120 | coarse_resolution = train_data.resolution * FLAGS.ds_factor 121 | solver = saint_venant.SaintVenantFlux(coarse_grid_size, coarse_resolution, 122 | FLAGS.theta) 123 | solver.to_gpu() 124 | if bool(FLAGS.model): 125 | checkpoint = torch.load(FLAGS.model) 126 | use_group_norm = checkpoint['args']['group_norm'] 127 | downsample_model = detour.resnet(use_group_norm=use_group_norm) 128 | downsample_model.load_state_dict(checkpoint['state_dict']) 129 | logging.info(f'model state_dict loaded from {FLAGS.model}') 130 | else: 131 | if 'edge_preserve' == FLAGS.model_type: 132 | downsample_model = edge_preserving.edge_preserve() 133 | else: 134 | downsample_model = averagenet.AverageNet() 135 | model = swe_model.SweModel(downsample_model, solver, coarse_resolution, 136 | coarse_grid_size, FLAGS.alpha, simulation_mode) 137 | 138 | model = model.cuda() 139 | args = _hyper_parameters(coarse_grid_size, coarse_resolution, 140 | train_data, log_dir) 141 | logging.info(args) 142 | logging.info('Number of model parameters: %s', 143 | sum([p.numel() for p in model.parameters()])) 144 | _namedtuple_to_json_file(args, log_dir + '/args.json') 145 | torch.save(model.downsample_model.state_dict(), log_dir + '/model.pth') 146 | 147 | if simulation_mode: 148 | loss = trainer.simulate(model, train_data_loader, args) 149 | logging.info(f'\nResults: Loss {loss:.4f}') 150 | else: 151 | loss = trainer.validate(0, model, train_data_loader, args) 152 | logging.info(f'\nResults: Loss {loss:.5f}') 153 | 154 | 155 | if __name__ == '__main__': 156 | # CUDA_VISIBLE_DEVICES=0 python evaluation.py --debug --comment debug --ground_truth_type flux 157 | # --sample 10 158 | app.run(main) 159 | -------------------------------------------------------------------------------- /ground_truth.py: -------------------------------------------------------------------------------- 1 | import enum 2 | import logging 3 | import multiprocessing 4 | import os 5 | import time 6 | import tqdm 7 | 8 | import numpy as np 9 | import pandas as pd 10 | import torch 11 | 12 | from hydraulics import boundary 13 | from hydraulics import saint_venant 14 | from hydraulics import simulation_utils as sim_utils 15 | 16 | INDEX_PATH = '/home/usgs_dem_data/dem/index.csv' 17 | FLUX_OUTPUT_PATH = '/home/usgs_dem_data/flux_ground_truth' 18 | RAIN_OUTPUT_PATH = '/home/usgs_dem_data/rain_ground_truth' 19 | FLUX_GROUND_TRUTH_INDEX = FLUX_OUTPUT_PATH + '/ground_truth_index.csv' 20 | RAIN_GROUND_TRUTH_INDEX = RAIN_OUTPUT_PATH + '/ground_truth_index.csv' 21 | DX = 1 22 | N_X = 2000 23 | DEVICE = 'cuda' 24 | ALPHA = 0.7 25 | THETA = 0.7 26 | MIN_H_N = 0.01 27 | RAINFALL_DISCHARGE = [0.035 / 3600] # meters/second 35mm/hour - heavy rain 28 | FLUX_DISCHARGE = [200] # [m^3/s] cubic meters per second 29 | TARGET_TIME = 3600 # [sec] 30 | INDEX_COLUMN_NAMES = ['dem', 'influx', 'outflux', 'discharge', 31 | 'simulation time', 'ground_truth', 'alpha', 'theta', 32 | 'min_h_n'] 33 | 34 | 35 | class GroundTruthType(enum.Enum): 36 | RAIN, FLUX = range(2) 37 | 38 | 39 | def read_index_row(index: pd.DataFrame, row: int): 40 | dem = torch.from_numpy(np.load(index.iloc[row]['dem'])) 41 | dem = dem.reshape(1, 1, *dem.shape) 42 | dem.sub_(dem.mean()) 43 | return dem 44 | 45 | 46 | def exec_func(queue: multiprocessing.Queue, file_lock: multiprocessing.Lock, 47 | device_id: int, ground_truth_type: GroundTruthType): 48 | time.sleep(device_id) 49 | logging.basicConfig(filename=f'device_{device_id}.log', level=logging.INFO, 50 | format="%(asctime)s - %(levelname)s - %(message)s", 51 | datefmt="%Y-%m-%d %H:%M:%S", ) 52 | torch.cuda.set_device(device_id) 53 | logging.info(f'GPU {device_id} Online') 54 | if ground_truth_type == GroundTruthType.FLUX: 55 | ground_truth_output_path = FLUX_OUTPUT_PATH 56 | ground_truth_index = FLUX_GROUND_TRUTH_INDEX 57 | discharge_list = FLUX_DISCHARGE 58 | else: 59 | ground_truth_output_path = RAIN_OUTPUT_PATH 60 | ground_truth_index = RAIN_GROUND_TRUTH_INDEX 61 | discharge_list = RAINFALL_DISCHARGE 62 | logging.info(f'Ground truth type - {ground_truth_type.name}') 63 | logging.info(f'Index path - {INDEX_PATH}') 64 | logging.info(f'Output path - {ground_truth_output_path}') 65 | logging.info(f'Output index path - {ground_truth_index}') 66 | index = pd.read_csv(INDEX_PATH, names=['dem', 'influx', 'outflux']) 67 | while not queue.empty(): 68 | row = queue.get() 69 | z_n = read_index_row(index, row) 70 | output_name = ( 71 | '/'.join(index.iloc[row]['dem'].split('/')[-2:]).split('.')[0]) 72 | for idx, discharge in enumerate(discharge_list): 73 | output_full_path = os.path.join(ground_truth_output_path, 74 | output_name) 75 | if ground_truth_type == GroundTruthType.FLUX: 76 | discharge_text = f'{discharge:.0f}cms' 77 | else: 78 | discharge_text = f'{discharge * 3600 * 1000:.0f}mm_hour' 79 | output_full_path = ( 80 | output_full_path + f'_{discharge_text}_{TARGET_TIME}_{row}.npy') 81 | logging.info(f'Processing row {row}') 82 | logging.info(f'dx - {DX}, n_x - {N_X}, device - {DEVICE}, alpha - ' 83 | f'{ALPHA}, theta - {THETA}, min_h_n - {MIN_H_N}, ' 84 | f'target_time - {TARGET_TIME}, discharge - {discharge}') 85 | calculate_ground_truth(ground_truth_type, output_full_path, z_n, 86 | discharge, index.iloc[row]) 87 | rows = [ 88 | (index.iloc[row]['dem'], index.iloc[row]['influx'], 89 | index.iloc[row]['outflux'], discharge, TARGET_TIME, 90 | output_full_path, ALPHA, THETA, MIN_H_N) 91 | ] 92 | df = pd.DataFrame(rows, columns=INDEX_COLUMN_NAMES) 93 | file_lock.acquire() 94 | with open(ground_truth_index, 'a') as f: 95 | df.to_csv(f, index=False, header=False) 96 | file_lock.release() 97 | logging.info(f'Row {row} {idx + 1}/{len(discharge_list)} saved to ' 98 | 'disk and indexed') 99 | logging.info('GPU {} Done'.format(device_id)) 100 | 101 | 102 | def run_simulation(model: torch.nn.Module, dx: float, 103 | z_n: torch.Tensor, h_n: torch.Tensor, 104 | q_x_n: torch.Tensor, q_y_n: torch.Tensor, 105 | current_time, target_time): 106 | min_h_n = MIN_H_N * torch.ones(h_n.shape[0]).cuda() 107 | 108 | progress_bar = tqdm.tqdm(total=target_time.item()) 109 | while not torch.isclose(current_time, target_time, rtol=0, atol=0.5).all(): 110 | with torch.no_grad(): 111 | dt = sim_utils.cfl(dx, torch.max( 112 | h_n.view(h_n.shape[0], -1).max(dim=1).values, min_h_n), ALPHA) 113 | dt = torch.min( 114 | torch.abs(current_time - target_time), dt.squeeze() 115 | ).reshape_as(dt) 116 | current_time += dt.squeeze() 117 | progress_bar.update(dt.item()) 118 | h_n, q_x_n, q_y_n = model(z_n, h_n, q_x_n, q_y_n, dt) 119 | if torch.isnan(h_n).any(): 120 | raise RuntimeError('nan values found in coarse solver.') 121 | progress_bar.close() 122 | return h_n, q_x_n, q_y_n 123 | 124 | 125 | def calculate_ground_truth(ground_truth_type: GroundTruthType, output_path: str, 126 | z_n: torch.Tensor, discharge: float, 127 | index_row: pd.Series): 128 | model = saint_venant.SaintVenantFlux(N_X, DX, theta=THETA) 129 | if ground_truth_type == GroundTruthType.FLUX: 130 | boundary_conditions = boundary.FluxBoundaryConditions( 131 | DX, N_X, [eval(index_row['influx'])], 132 | [eval(index_row['outflux'])], [discharge], 1) 133 | else: 134 | discharge = torch.as_tensor(discharge, dtype=torch.float).to(DEVICE) 135 | boundary_conditions = boundary.RainBoundaryConditions(discharge) 136 | model.boundary_conditions = boundary_conditions 137 | model.to_gpu() 138 | z_n = z_n.to(DEVICE) 139 | h_n = torch.zeros(z_n.shape[0], z_n.shape[1], N_X, N_X).to(DEVICE) 140 | q_x_n = torch.zeros(z_n.shape[0], z_n.shape[1], N_X, N_X - 1).to(DEVICE) 141 | q_y_n = torch.zeros(z_n.shape[0], z_n.shape[1], N_X - 1, N_X).to(DEVICE) 142 | current_time = torch.zeros(1, dtype=torch.float).to(DEVICE) 143 | print(f'processing {output_path}') 144 | for time_target in [TARGET_TIME]: 145 | time_target = torch.tensor(time_target, dtype=torch.float).to(DEVICE) 146 | h_n, q_x_n, q_y_n = run_simulation(model, DX, z_n, h_n, q_x_n, q_y_n, 147 | current_time, time_target) 148 | np.save(output_path, h_n.cpu().numpy().squeeze()) 149 | 150 | 151 | if __name__ == '__main__': 152 | file_lock = multiprocessing.Lock() 153 | queue = multiprocessing.Queue() 154 | index = pd.read_csv(INDEX_PATH, names=['dem', 'influx', 'outflux']) 155 | ground_truth_type = GroundTruthType.FLUX 156 | for row in range(len(index)): 157 | queue.put(row) 158 | 159 | processes_num = 8 160 | processes = [ 161 | multiprocessing.Process(target=exec_func, args=(queue, file_lock, idx, 162 | ground_truth_type)) 163 | for idx in range(processes_num) 164 | ] 165 | for process in processes: 166 | process.start() 167 | for process in processes: 168 | process.join() 169 | -------------------------------------------------------------------------------- /hydraulics/boundary.py: -------------------------------------------------------------------------------- 1 | import abc 2 | import enum 3 | from typing import Sequence, Tuple 4 | 5 | import torch 6 | import torch.nn.functional as F 7 | 8 | G = 9.8 9 | OUTFLUX_SLOPE = 0.2 10 | 11 | 12 | def _flux_location_to_indices(dem_shape: int, flux_location: torch.Tensor, 13 | down_sample_factor: int): 14 | x, y, length = flux_location 15 | rows = dem_shape 16 | cols = dem_shape 17 | index = x if x > 0 else y 18 | index = int(index / down_sample_factor) 19 | dim = rows if x > 0 else cols 20 | if length > dim: 21 | raise ValueError(f'cross section length {length} is longer than DEM' 22 | f' dimension {dim}') 23 | indices = torch.arange(index - length // 2, index + length // 2) 24 | if index - length // 2 < 0: 25 | indices += abs(index - length // 2) 26 | if index + length // 2 > dim: 27 | indices -= index + length // 2 - dim 28 | return indices.to(torch.long) 29 | 30 | 31 | def calculate_boundaries(dx: float, dem_shape, 32 | influx_locations: Sequence[Sequence[int]], 33 | outflux_locations: Sequence[Sequence[int]], 34 | discharges: Sequence[float], down_sample_factor: int): 35 | rows = dem_shape 36 | cols = dem_shape 37 | influx_x_list = [] # left, right 38 | influx_y_list = [] # up, down 39 | outflux_x_list = [] 40 | outflux_y_list = [] 41 | for influx, outflux, discharge in zip(influx_locations, outflux_locations, 42 | discharges): 43 | influx_x, influx_y, influx_width = influx 44 | influx_width /= down_sample_factor 45 | influx_x_list.append(torch.zeros(rows, 2)) 46 | influx_y_list.append(torch.zeros(cols, 2)) 47 | influx_indices = _flux_location_to_indices(dem_shape, influx, 48 | down_sample_factor) 49 | if influx_x > 0 and influx_y == 0: 50 | influx_x_list[-1][:, 0][ 51 | influx_indices] += discharge / influx_width / dx 52 | if influx_x > 0 and influx_y == -1: 53 | influx_x_list[-1][:, 1][ 54 | influx_indices] -= discharge / influx_width / dx 55 | if influx_x == 0 and influx_y > 0: 56 | influx_y_list[-1][:, 0][ 57 | influx_indices] += discharge / influx_width / dx 58 | if influx_x == -1 and influx_y > 0: 59 | influx_y_list[-1][:, 1][ 60 | influx_indices] -= discharge / influx_width / dx 61 | outflux_x, outflux_y, outflux_width = outflux 62 | outflux_width /= down_sample_factor 63 | outflux_x_list.append(torch.zeros(rows, 2)) 64 | outflux_y_list.append(torch.zeros(cols, 2)) 65 | outflux_indices = _flux_location_to_indices(dem_shape, outflux, 66 | down_sample_factor) 67 | if outflux_x > 0 and outflux_y == 0: 68 | outflux_x_list[-1][:, 0][outflux_indices] = 1 69 | if outflux_x > 0 and outflux_y == -1: 70 | outflux_x_list[-1][:, 1][outflux_indices] = 1 71 | if outflux_x == 0 and outflux_y > 0: 72 | outflux_y_list[-1][:, 0][outflux_indices] = 1 73 | if outflux_x == -1 and outflux_y > 0: 74 | outflux_y_list[-1][:, 1][outflux_indices] = 1 75 | outflux_x = torch.stack(outflux_x_list) 76 | outflux_y = torch.stack(outflux_y_list) 77 | influx_x = torch.stack(influx_x_list) 78 | influx_y = torch.stack(influx_y_list) 79 | return influx_x, influx_y, outflux_x, outflux_y 80 | 81 | 82 | class BoundaryType(enum.Enum): 83 | FLUX, RAIN = range(2) 84 | 85 | 86 | class BoundaryConditions(abc.ABC): 87 | """A class for applying boundary conditions.""" 88 | 89 | @abc.abstractmethod 90 | def __call__(self, h_n: torch.Tensor, flux_x: torch.Tensor, 91 | flux_y: torch.Tensor 92 | ) -> Tuple[float, torch.Tensor, torch.Tensor]: 93 | """Applies boundary conditions. 94 | 95 | Returns homogeneous water difference, flux_x and flux_y""" 96 | raise NotImplementedError('Calling an abstract method.') 97 | 98 | 99 | class FluxBoundaryConditions(BoundaryConditions): 100 | def __init__(self, dx: float, dem_shape: int, 101 | influx_location: Sequence[Sequence[int]], 102 | outflux_location: Sequence[Sequence[int]], 103 | discharge: Sequence[float], down_sample_factor: int = 16): 104 | self.dx = dx 105 | self.down_sample_factor = down_sample_factor 106 | influx_x, influx_y, outflux_x, outflux_y = calculate_boundaries( 107 | dx, dem_shape, influx_location, outflux_location, discharge, 108 | self.down_sample_factor) 109 | self.influx_x = influx_x.unsqueeze(1).cuda() 110 | self.influx_y = influx_y.unsqueeze(1).cuda() 111 | self.outflux_x = outflux_x.unsqueeze(1).cuda() 112 | self.outflux_y = outflux_y.unsqueeze(1).cuda() 113 | 114 | def __call__(self, h_n: torch.Tensor, flux_x: torch.Tensor, 115 | flux_y: torch.Tensor 116 | ) -> Tuple[float, torch.Tensor, torch.Tensor]: 117 | flux_x = F.pad(flux_x, pad=[1, 1]) 118 | flux_y = F.pad(flux_y, pad=[0, 0, 1, 1]) 119 | flux_x[:, :, :, 0] += self.influx_x[:, :, :, 0].to(flux_x.device) 120 | flux_x[:, :, :, -1] += self.influx_x[:, :, :, 1].to(flux_x.device) 121 | flux_y[:, :, 0, :] += self.influx_y[:, :, :, 0].to(flux_y.device) 122 | flux_y[:, :, -1, :] += self.influx_y[:, :, :, 1].to(flux_y.device) 123 | flux_x[:, :, :, -1] += G * h_n[:, :, :, -1] * OUTFLUX_SLOPE * ( 124 | self.outflux_x[:, :, :, 1].to(flux_x.device)) 125 | flux_x[:, :, :, 0] -= G * h_n[:, :, :, 0] * OUTFLUX_SLOPE * ( 126 | self.outflux_x[:, :, :, 0].to(flux_x.device)) 127 | flux_y[:, :, 0, :] -= G * h_n[:, :, 0, :] * OUTFLUX_SLOPE * ( 128 | self.outflux_y[:, :, :, 0].to(flux_y.device)) 129 | flux_y[:, :, -1, :] += G * h_n[:, :, -1, :] * OUTFLUX_SLOPE * ( 130 | self.outflux_y[:, :, :, 1].to(flux_y.device)) 131 | return 0, flux_x, flux_y 132 | 133 | 134 | class RainBoundaryConditions(BoundaryConditions): 135 | def __init__(self, discharge: torch.Tensor): 136 | self.discharge = discharge # meters/second 137 | self.rainfall_per_pixel = self.discharge.reshape(-1, 1, 1, 1) 138 | 139 | def zero_discharge(self, indices_to_zero: torch.Tensor): 140 | self.discharge[indices_to_zero] = 0 141 | self.rainfall_per_pixel = self.discharge.reshape(-1, 1, 1, 1) 142 | 143 | def __call__(self, h_n: torch.Tensor, flux_x: torch.Tensor, 144 | flux_y: torch.Tensor 145 | ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: 146 | flux_x = F.pad(flux_x, pad=[1, 1]) 147 | flux_y = F.pad(flux_y, pad=[0, 0, 1, 1]) 148 | return self.rainfall_per_pixel, flux_x, flux_y 149 | -------------------------------------------------------------------------------- /hydraulics/saint_venant.py: -------------------------------------------------------------------------------- 1 | # Lint as: python3 2 | 3 | from typing import Optional, Tuple 4 | 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | 9 | G = 9.8 10 | MANNING_COEFF_FLOODPLAIN = 0.05 11 | 12 | _X_AXIS = 3 13 | _Y_AXIS = 2 14 | _EPSILON = 1e-8 15 | 16 | 17 | class SaintVenantFlux(nn.Module): 18 | """1D saint venant equations with flux and height variables. 19 | Implemented based on the papers of Bates et al. and Almeida et al. - "A 20 | simple inertial formulation of the shallow water equations for efficient 21 | two-dimensional flood inundation modelling.", "Improving the stability of a 22 | simple formulation of the shallow water equations for 2-D flood modeling". 23 | """ 24 | 25 | def __init__(self, spatial_samples_number: int, spatial_delta: float, 26 | theta: Optional[float] = 1): 27 | super(SaintVenantFlux, self).__init__() 28 | self.n_x = spatial_samples_number 29 | self.dx = spatial_delta 30 | self.dt = None 31 | self.theta = theta 32 | self.q_centered_weights = torch.tensor( 33 | [(1 - theta) / 2, theta, (1 - theta) / 2]).view(1, 1, 1, 3) 34 | self.replicate_padding = torch.nn.ReplicationPad1d((1, 1, 0, 0)) 35 | self.derivative_weights = torch.tensor( 36 | [-1 / spatial_delta, 1 / spatial_delta]).view(1, 1, 1, 2) 37 | self.average_weights = torch.tensor([0.25, 0.25, 0.25, 0.25]).view( 38 | 1, 1, 2, 2) 39 | self.minimum_flow = torch.tensor(1e-7) 40 | self.boundary_conditions = None 41 | 42 | def to_gpu(self): 43 | self.q_centered_weights = self.q_centered_weights.cuda() 44 | self.derivative_weights = self.derivative_weights.cuda() 45 | self.average_weights = self.average_weights.cuda() 46 | self.minimum_flow = self.minimum_flow.cuda() 47 | 48 | def _q_centered(self, q: torch.Tensor, 49 | transpose: Optional[bool] = False) -> torch.Tensor: 50 | if self.theta == 1: 51 | return q 52 | if transpose: 53 | return F.conv2d( 54 | self.replicate_padding(q.transpose(_Y_AXIS, _X_AXIS)), 55 | self.q_centered_weights).transpose(_Y_AXIS, _X_AXIS) 56 | else: 57 | return F.conv2d(self.replicate_padding(q), self.q_centered_weights) 58 | 59 | def _q_norm(self, q_x: torch.Tensor, q_y: torch.Tensor, dim: int): 60 | if dim == _Y_AXIS: 61 | x = F.conv2d(q_x, self.average_weights, padding=(0, 1)) 62 | return (q_y ** 2 + x ** 2 + _EPSILON) ** 0.5 63 | if dim == _X_AXIS: 64 | y = F.conv2d(q_y, self.average_weights, padding=(1, 0)) 65 | return (q_x ** 2 + y ** 2 + _EPSILON) ** 0.5 66 | 67 | def _cross_flow(self, water_level: torch.Tensor, stream_bed: torch.Tensor, 68 | dim: Optional[int] = _X_AXIS) -> torch.Tensor: 69 | if dim == _Y_AXIS: 70 | return torch.max(torch.max(water_level[:, :, 1:], 71 | water_level[:, :, :-1]) - torch.max( 72 | stream_bed[:, :, 1:], stream_bed[:, :, :-1]), self.minimum_flow) 73 | if dim == _X_AXIS: 74 | return torch.max(torch.max(water_level[:, :, :, 1:], 75 | water_level[:, :, :, :-1]) - torch.max( 76 | stream_bed[:, :, :, 1:], stream_bed[:, :, :, :-1]), 77 | self.minimum_flow) 78 | 79 | def _derivative(self, x: torch.Tensor, 80 | transpose: Optional[bool] = False) -> torch.Tensor: 81 | dim = _X_AXIS if transpose else _Y_AXIS 82 | return F.conv2d(x.transpose(_Y_AXIS, dim), 83 | self.derivative_weights).transpose(_Y_AXIS, dim) 84 | 85 | def forward( 86 | self, z_n: torch.Tensor, h_n: torch.Tensor, q_x_n: torch.Tensor, 87 | q_y_n: torch.Tensor, dt: torch.Tensor 88 | ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: 89 | """Performs one numerical step in time of saint-venant equations.""" 90 | if torch.isclose(dt, torch.zeros_like(dt)).all(): 91 | return h_n, q_x_n, q_y_n 92 | self.dt = dt 93 | # Momentum equation 94 | previous_x_flux = self._q_centered(q_x_n) 95 | previous_y_flux = self._q_centered(q_y_n, transpose=True) 96 | 97 | cross_flow_x = self._cross_flow(h_n + z_n, z_n, dim=_X_AXIS) 98 | cross_flow_y = self._cross_flow(h_n + z_n, z_n, dim=_Y_AXIS) 99 | 100 | slope_x = self._derivative(h_n + z_n) 101 | slope_y = self._derivative(h_n + z_n, transpose=True) 102 | 103 | numerator_x = previous_x_flux - G * self.dt.expand_as( 104 | cross_flow_x) * cross_flow_x * slope_x 105 | numerator_y = previous_y_flux - G * self.dt.expand_as( 106 | cross_flow_y) * cross_flow_y * slope_y 107 | 108 | denominator_x = (1 + G * self.dt.expand_as(numerator_x) * ( 109 | MANNING_COEFF_FLOODPLAIN ** 2) * self._q_norm( 110 | q_x_n, q_y_n, _X_AXIS) / (cross_flow_x ** (7 / 3))) 111 | denominator_y = (1 + G * self.dt.expand_as(numerator_y) * ( 112 | MANNING_COEFF_FLOODPLAIN ** 2) * self._q_norm( 113 | q_x_n, q_y_n, _Y_AXIS) / (cross_flow_y ** (7 / 3))) 114 | 115 | q_x_n_next = numerator_x / denominator_x 116 | q_y_n_next = numerator_y / denominator_y 117 | 118 | # q_x is q_x_n_next expanded with boundary conditions 119 | delta_h_n, q_x, q_y = self.boundary_conditions(h_n, q_x_n_next, 120 | q_y_n_next) 121 | # Continuity equation 122 | h_n = h_n + self.dt.expand_as(h_n) * delta_h_n 123 | h_n_next = h_n + self.dt.expand_as(h_n) * ( 124 | self._derivative(-q_x) + self._derivative(-q_y, transpose=True)) 125 | return h_n_next, q_x_n_next, q_y_n_next 126 | -------------------------------------------------------------------------------- /hydraulics/simulation_utils.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | G = 9.8 5 | 6 | 7 | def downsample(z: torch.Tensor, ds_factor: int) -> torch.Tensor: 8 | """downsample 2d tensor z by a factor of ds_factor. 9 | 10 | z should have 3 dimensions of (batch size, rows, cols). if z is provided 11 | with 2 dimensions, a third (batch size = 1) is deduced automatically. 12 | The returned downsampled tensor has 3 dimensions (batch size, rows, cols). 13 | """ 14 | if z.dim() == 2: 15 | z = z.expand(1, *z.shape) 16 | ds_operator = nn.AvgPool2d(kernel_size=ds_factor) 17 | return ds_operator(z) 18 | 19 | 20 | def cfl(dx: float, max_h: torch.Tensor, alpha: float) -> torch.Tensor: 21 | return (alpha * dx / (G + max_h)).reshape(-1, 1, 1, 1) 22 | 23 | 24 | class CFL(object): 25 | def __init__(self, dx, alpha): 26 | self.dx = dx 27 | self.alpha = alpha 28 | 29 | def __call__(self, max_h): 30 | return ( 31 | (self.alpha * self.dx / (G + max_h)).reshape(-1, 1, 1, 1)) 32 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import json 3 | from typing import Dict, NamedTuple 4 | 5 | import torch 6 | import torch.distributed as dist 7 | import torch.nn as nn 8 | from absl import app 9 | from absl import flags 10 | from absl import logging 11 | from torch.utils.data import distributed as dist_data 12 | 13 | import trainer 14 | import utils.tensorboard as tb 15 | from data import data 16 | from hydraulics import boundary 17 | from hydraulics import saint_venant 18 | from models import detour 19 | from models import swe_model 20 | from utils import optimization 21 | 22 | _get_dtype = {'float32': torch.float32, 23 | 'float16': torch.float16, 24 | 'float64': torch.float64} 25 | 26 | FLAGS = flags.FLAGS 27 | 28 | flags.DEFINE_string('comment', '', 29 | 'Comment for run. Ignored of log_dir is provided') 30 | flags.DEFINE_string('device', 'cuda', 'Device to use.') 31 | flags.DEFINE_string('dtype', 'float32', 32 | f'Data type to use. {_get_dtype.keys()}') 33 | flags.DEFINE_enum('model', 'detour', ['detour'], 'Down sample model') 34 | flags.DEFINE_string('model_init', '', 35 | 'Path to model weights to be used at initialization.') 36 | flags.DEFINE_boolean('group_norm', False, 'Use groupnorm instead of batchnorm.') 37 | flags.DEFINE_integer('batch_size', 32, 'Batch size.') 38 | flags.DEFINE_integer('epochs', 10, 'Number of epochs.') 39 | flags.DEFINE_float('lr', 0.001, 'Learning rate.') 40 | flags.DEFINE_string('lr_milestones', '[]', 41 | 'Decays the learning rate by gamma once the number of epoch' 42 | ' reaches one of the milestones.') 43 | flags.DEFINE_float('lr_gamma', 0.1, 44 | 'Multiplicative factor of learning rate decay. Used with' 45 | ' milestones.') 46 | flags.DEFINE_float('momentum', 0.9, 'Momentum.') 47 | flags.DEFINE_float('weight_decay', 0.0, 'Weight decay.') 48 | flags.DEFINE_float('regularization_lambda', 0.0, 'Regularization lambda.') 49 | flags.DEFINE_boolean('debug', False, 'Produces debugging output.') 50 | flags.DEFINE_enum('criterion', 'mse', ['mse', 'smooth_l1'], 'Loss function.') 51 | flags.DEFINE_enum('optimizer', 'adam', ['adam', 'sgd'], 'Optimizer.') 52 | flags.DEFINE_enum('regularization', 'smooth_l1', ['mse', 'smooth_l1'], 53 | 'Regularization loss function.') 54 | flags.DEFINE_enum('ground_truth_type', 'rain', ['flux', 'rain'], 55 | 'Type of ground truth.') 56 | flags.DEFINE_float('alpha', 0.7, 'CFL condition coefficient.') 57 | flags.DEFINE_float('theta', 0.7, 'q centered weighting. [0,1].') 58 | flags.DEFINE_integer('scale_factor', 16, 59 | 'Downsample factor from fine to coarse.') 60 | 61 | flags.DEFINE_integer('world_size', torch.cuda.device_count(), 62 | 'number of distributed processes') 63 | flags.DEFINE_integer('local_rank', -1, 'rank of distributed processes') 64 | flags.DEFINE_string('dist_init', 'env://', 65 | 'init used to set up distributed training') 66 | flags.DEFINE_string('dist_backend', 'nccl', 'distributed backend') 67 | 68 | _TRAIN_SEED = 214 69 | _TEST_SEED = 123 70 | # Batch size can be larger for test set. 71 | TEST_BATCH_SIZE = 16 72 | 73 | 74 | def _get_criterion(criterion: str): 75 | return {'mse': nn.MSELoss, 'smooth_l1': nn.SmoothL1Loss, 76 | 'inundation': optimization.InundationLoss}[criterion]() 77 | 78 | 79 | def _get_optimizer(optimizer: str, model: torch.nn.Module, **kwargs): 80 | return {'adam': torch.optim.Adam, 'sgd': torch.optim.SGD}[optimizer]( 81 | model.parameters(), **kwargs) 82 | 83 | 84 | def _flags_to_dict() -> Dict: 85 | names = [x.name for x in FLAGS.get_key_flags_for_module('main.py')] 86 | values = [x.value for x in FLAGS.get_key_flags_for_module('main.py')] 87 | return {name: value for name, value in zip(names, values)} 88 | 89 | 90 | def _namedtuple_to_json_file(args: NamedTuple, filename: str): 91 | """Converts namedtuple to readable dict format and saves it as json file.""" 92 | args_dict = [] 93 | for k, v in args._asdict().items(): 94 | if type(v) in {bool, str, int, float}: 95 | args_dict.append({'Name': k, 'Value': v}) 96 | elif k == 'optimizer': 97 | value = {'class': type(v).__name__} 98 | for key in sorted(v.param_groups[0].keys()): 99 | if key != 'params': 100 | value[key] = v.param_groups[0][key] 101 | args_dict.append({'Name': k, 'Value': value}) 102 | elif k == 'criterion' or k == 'regularization': 103 | args_dict.append({'Name': k, 'Value': type(v).__name__}) 104 | with open(filename, 'w') as f: 105 | json.dump(args_dict, f) 106 | 107 | 108 | def _hyper_parameters(model, coarse_grid_size, coarse_resolution, 109 | train_data) -> NamedTuple: 110 | params = _flags_to_dict() 111 | 112 | params['PyTorch'] = torch.__version__ 113 | params['dtype'] = _get_dtype[params['dtype']] 114 | params['coarse_dx'] = coarse_resolution 115 | params['coarse_n_x'] = coarse_grid_size 116 | params['fine_dx'] = train_data.resolution 117 | params['boundary_type'] = boundary.BoundaryType[ 118 | train_data.boundary_type.upper()] 119 | 120 | params['criterion'] = _get_criterion(FLAGS.criterion).to( 121 | FLAGS.device, dtype=_get_dtype[FLAGS.dtype]) 122 | params['regularization'] = _get_criterion(FLAGS.regularization).to( 123 | FLAGS.device, dtype=_get_dtype[FLAGS.dtype]) 124 | optimizer_params = {'lr': FLAGS.lr, 'weight_decay': FLAGS.weight_decay, 125 | 'momentum': FLAGS.momentum} 126 | if FLAGS.optimizer == 'adam': 127 | optimizer_params.pop('momentum') 128 | params['optimizer'] = _get_optimizer(FLAGS.optimizer, model, 129 | **optimizer_params) 130 | params['local_rank'] = FLAGS.local_rank 131 | params['world_size'] = FLAGS.world_size 132 | Args = collections.namedtuple('HyperParameters', sorted(params)) 133 | return Args(**params) 134 | 135 | 136 | def main(_): 137 | if FLAGS.debug: 138 | torch.set_printoptions(precision=5, linewidth=230, sci_mode=False) 139 | torch.manual_seed(_TRAIN_SEED) 140 | torch.cuda.manual_seed(_TRAIN_SEED) 141 | if FLAGS.local_rank >= 0: 142 | dist.init_process_group(backend=FLAGS.dist_backend, 143 | init_method=FLAGS.dist_init, 144 | world_size=FLAGS.world_size, 145 | rank=FLAGS.local_rank) 146 | torch.cuda.set_device(FLAGS.local_rank) 147 | if FLAGS.local_rank <= 0: 148 | FLAGS.alsologtostderr = True 149 | tb.init(FLAGS.log_dir, FLAGS.comment) 150 | logging.get_absl_handler().use_absl_log_file('Logger', tb.get_log_dir()) 151 | 152 | ground_truth_type = data.GroundTruthType[FLAGS.ground_truth_type.upper()] 153 | train_data = data.USGS(ground_truth_type=ground_truth_type, train_set=True) 154 | test_data = data.USGS(ground_truth_type=ground_truth_type, train_set=False) 155 | if FLAGS.local_rank <= 0: 156 | logging.info(f'USGS-1m loaded with {len(train_data)} train samples, ' 157 | f'{len(test_data)} test samples') 158 | if FLAGS.local_rank >= 0: 159 | train_sampler = dist_data.DistributedSampler(train_data, 160 | seed=_TRAIN_SEED) 161 | test_sampler = dist_data.DistributedSampler(test_data, seed=_TEST_SEED, 162 | shuffle=False) 163 | else: 164 | train_sampler = None 165 | test_sampler = None 166 | train_data_loader = torch.utils.data.DataLoader( 167 | train_data, shuffle=(train_sampler is None), sampler=train_sampler, 168 | batch_size=FLAGS.batch_size) 169 | test_data_loader = torch.utils.data.DataLoader( 170 | test_data, shuffle=False, sampler=test_sampler, 171 | batch_size=TEST_BATCH_SIZE) 172 | coarse_grid_size = int(train_data.grid_size // FLAGS.scale_factor) 173 | coarse_resolution = train_data.resolution * FLAGS.scale_factor 174 | solver = saint_venant.SaintVenantFlux(coarse_grid_size, coarse_resolution, 175 | FLAGS.theta) 176 | solver.to_gpu() 177 | if 'detour' in FLAGS.model: 178 | downsample_model = detour.resnet(FLAGS.group_norm) 179 | else: 180 | raise ValueError('Unsupported model type.') 181 | if FLAGS.local_rank <= 0: 182 | logging.info(downsample_model) 183 | model = swe_model.SweModel(downsample_model, solver, coarse_resolution, 184 | coarse_grid_size, FLAGS.alpha) 185 | 186 | model = model.cuda() 187 | if bool(FLAGS.model_init): 188 | device = FLAGS.local_rank if FLAGS.local_rank >= 0 else 0 189 | checkpoint = torch.load(FLAGS.model_init, 190 | map_location=torch.device(device)) 191 | model.downsample_model.load_state_dict(checkpoint['state_dict']) 192 | if FLAGS.local_rank <= 0: 193 | logging.info('Model initialized with state dict %s', 194 | FLAGS.model_init) 195 | if FLAGS.local_rank >= 0: 196 | device_ids = [FLAGS.local_rank] 197 | model = nn.parallel.DistributedDataParallel(model, 198 | device_ids=device_ids, 199 | output_device=device_ids[0]) 200 | FLAGS.lr_milestones = eval(FLAGS.lr_milestones) 201 | args = _hyper_parameters(model, coarse_grid_size, coarse_resolution, 202 | train_data) 203 | if FLAGS.local_rank <= 0: 204 | logging.info(args) 205 | logging.info('Number of model parameters: %s', 206 | sum([p.numel() for p in model.parameters()])) 207 | tb.log_hyper_parameters(args._asdict()) 208 | _namedtuple_to_json_file(args, tb.get_log_dir() + '/args.json') 209 | 210 | if FLAGS.lr_milestones: 211 | scheduler = torch.optim.lr_scheduler.MultiStepLR( 212 | args.optimizer, FLAGS.lr_milestones, gamma=FLAGS.lr_gamma, 213 | verbose=True if FLAGS.local_rank <= 0 else False) 214 | best_validation_loss = float('inf') 215 | for epoch in range(FLAGS.epochs): 216 | if FLAGS.local_rank >= 0: 217 | train_sampler.set_epoch(epoch) 218 | test_sampler.set_epoch(epoch) 219 | train_loss = trainer.train(epoch, model, train_data_loader, args) 220 | validation_loss = trainer.validate(epoch, model, test_data_loader, args) 221 | if FLAGS.lr_milestones: 222 | scheduler.step() 223 | 224 | if FLAGS.local_rank <= 0: 225 | if FLAGS.local_rank < 0: 226 | state_dict = model.downsample_model.state_dict() 227 | else: 228 | state_dict = model.module.downsample_model.state_dict() 229 | torch.save({'epoch': epoch, 'args': args._asdict(), 230 | 'state_dict': state_dict}, 231 | tb.get_log_dir() + f'/checkpoint.pth') 232 | if validation_loss < best_validation_loss: 233 | best_validation_loss = validation_loss 234 | torch.save({'epoch': epoch, 'args': args._asdict(), 235 | 'state_dict': state_dict}, 236 | tb.get_log_dir() + f'/best_checkpoint.pth') 237 | logging.info( 238 | f'\nResults - Epoch: {epoch}\tTraining Loss {train_loss:.4f}\t' 239 | f'Validation Loss {validation_loss:.4f}\n') 240 | tb.log_scalars(epoch, write_hparams=True, train_loss=train_loss, 241 | validation_loss=validation_loss) 242 | 243 | 244 | if __name__ == '__main__': 245 | # CUDA_VISIBLE_DEVICES=0,1,2,3 python -m torch.distributed.launch --nproc_per_node=4 --master_port 29499 main.py --batch_size 1 --debug --epochs 50 --regularization_lambda 0.5 246 | app.run(main) 247 | -------------------------------------------------------------------------------- /models/averagenet.py: -------------------------------------------------------------------------------- 1 | # Lint as: python3 2 | import torch 3 | import torch.nn as nn 4 | 5 | __all__ = ['average_net'] 6 | 7 | 8 | class AverageNet(nn.Module): 9 | 10 | def __init__(self, downsample_factor: int = 16): 11 | super(AverageNet, self).__init__() 12 | self.dummy_parameter = nn.Parameter(torch.zeros(1), True) 13 | self.avg = nn.AvgPool2d(kernel_size=downsample_factor) 14 | 15 | def forward(self, x): 16 | x = self.avg(x) 17 | return x 18 | 19 | 20 | def average_net(): 21 | return AverageNet() 22 | -------------------------------------------------------------------------------- /models/detour.py: -------------------------------------------------------------------------------- 1 | # Lint as: python3 2 | 3 | import torch 4 | import torch.nn as nn 5 | import torch.nn.functional 6 | from torch.utils import checkpoint 7 | 8 | batch_norm = nn.BatchNorm2d 9 | group_norm = nn.GroupNorm 10 | _use_group_norm = False 11 | 12 | 13 | def get_norm_layer(num_channels): 14 | if _use_group_norm: 15 | num_channels_per_group = 16 16 | return nn.GroupNorm(num_channels // num_channels_per_group, 17 | num_channels) 18 | else: 19 | return nn.BatchNorm2d(num_channels) 20 | 21 | 22 | def conv3x3(in_planes, out_planes, stride=1, groups=1, bias=False): 23 | """3x3 convolution with padding.""" 24 | return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, 25 | padding=1, padding_mode='replicate', groups=groups, 26 | bias=bias) 27 | 28 | 29 | class BasicBlock(nn.Module): 30 | 31 | def __init__(self, inplanes, planes, stride=1, expansion=1, downsample=None, 32 | groups=1, residual_block=None, 33 | tag=None): 34 | super(BasicBlock, self).__init__() 35 | self.bn1 = get_norm_layer(planes) 36 | self.relu = nn.ReLU(inplace=True) 37 | self.conv1 = conv3x3(inplanes, planes, stride, groups=groups) 38 | self.bn2 = get_norm_layer(expansion * planes) 39 | self.conv2 = conv3x3(planes, expansion * planes, groups=groups) 40 | self.downsample = downsample 41 | self.residual_block = residual_block 42 | self.stride = stride 43 | self.expansion = expansion 44 | self.tag = tag 45 | self.sub_layer1 = nn.Sequential(self.conv1, self.bn1, self.relu) 46 | self.sub_layer2 = nn.Sequential(self.conv2, self.bn2) 47 | 48 | def init_block(self): 49 | self.conv1.weight.data.div_(100) 50 | if self.downsample: 51 | self.downsample[0].weight.data.fill_( 52 | 1 / self.downsample[0].weight.shape[1]) 53 | 54 | def forward(self, x): 55 | residual = x 56 | out = checkpoint.checkpoint(self.sub_layer1, x) 57 | out = checkpoint.checkpoint(self.sub_layer2, out) 58 | 59 | if self.downsample is not None: 60 | residual = self.downsample(residual) 61 | 62 | if self.residual_block is not None: 63 | residual = self.residual_block(residual) 64 | 65 | out += residual 66 | out = self.relu(out) 67 | return out 68 | 69 | 70 | class ResNet(nn.Module): 71 | 72 | def __init__(self): 73 | super(ResNet, self).__init__() 74 | 75 | def _make_layer(self, block, planes, blocks, expansion=1, stride=1, 76 | groups=1, residual_block=None, tag=None): 77 | downsample = None 78 | out_planes = planes * expansion 79 | if stride != 1 or self.inplanes != out_planes: 80 | downsample = nn.Sequential( 81 | nn.Conv2d(self.inplanes, out_planes, kernel_size=1, 82 | stride=stride, bias=False), 83 | get_norm_layer(out_planes), 84 | ) 85 | if residual_block is not None: 86 | residual_block = residual_block(out_planes) 87 | 88 | layers = [] 89 | name = tag + '.0' if tag else None 90 | layers.append(block(self.inplanes, planes, stride, expansion=expansion, 91 | downsample=downsample, groups=groups, 92 | residual_block=residual_block, tag=name)) 93 | self.inplanes = out_planes 94 | for i in range(1, blocks): 95 | name = tag + '.{}'.format(i) if tag else None 96 | layers.append( 97 | block(self.inplanes, planes, expansion=expansion, groups=groups, 98 | residual_block=residual_block, tag=name)) 99 | 100 | return nn.Sequential(*layers) 101 | 102 | def features(self, x): 103 | x.requires_grad = True 104 | detour = self.detour(x) 105 | 106 | x = checkpoint.checkpoint(self.layer0, x) 107 | x = self.maxpool(x) 108 | x = self.layer1(x) 109 | x = self.layer2(x) 110 | x = self.layer3(x) 111 | x = self.layer4(x) 112 | 113 | x = self.conv2(x) 114 | x += detour 115 | return x 116 | 117 | def forward(self, x): 118 | return self.features(x) 119 | 120 | def regularization_pre_step(self, model): 121 | with torch.no_grad(): 122 | for m in model.modules(): 123 | if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear): 124 | m.weight.grad.add_(self.weight_decay * m.weight) 125 | return 0 126 | 127 | 128 | class ResNetDEM(ResNet): 129 | 130 | def __init__(self, inplanes=64, block=BasicBlock, residual_block=None, 131 | layers=(3, 4, 6, 3), width=(64, 128, 256, 512), expansion=4, 132 | groups=(1, 1, 1, 1), kernel_size=7): 133 | super(ResNetDEM, self).__init__() 134 | self.inplanes = inplanes 135 | self.conv1 = nn.Conv2d(1, self.inplanes, kernel_size=kernel_size, 136 | stride=2, padding=int((kernel_size - 1) / 2), 137 | padding_mode='replicate', bias=False) 138 | self.bn1 = get_norm_layer(self.inplanes) 139 | self.relu = nn.ReLU(inplace=True) 140 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 141 | self.detour = nn.AvgPool2d(kernel_size=16) 142 | 143 | for i in range(len(layers)): 144 | setattr(self, 'layer%s' % str(i + 1), 145 | self._make_layer(block=block, planes=width[i], 146 | blocks=layers[i], expansion=expansion, 147 | stride=1 if i in {0, 3} else 2, 148 | residual_block=residual_block, 149 | groups=groups[i])) 150 | 151 | self.avgpool = lambda x: x 152 | self.conv2 = nn.Conv2d(width[-1], 1, kernel_size=1, bias=False) 153 | self.layer0 = nn.Sequential(self.conv1, self.bn1, self.relu) 154 | 155 | def init_model(self): 156 | self.conv1.weight.data.fill_( 157 | 1 / (self.conv1.kernel_size[0] * self.conv1.kernel_size[1])) 158 | self.conv2.weight.data.fill_(1 / self.conv2.weight.shape[1]) 159 | 160 | 161 | def resnet(use_group_norm: bool = False) -> ResNetDEM: 162 | global _use_group_norm 163 | _use_group_norm = use_group_norm 164 | return ResNetDEM(inplanes=64, block=BasicBlock, layers=(2, 2, 2, 2), 165 | width=(64, 128, 256, 512), expansion=1, kernel_size=3) 166 | -------------------------------------------------------------------------------- /models/edge_preserving.py: -------------------------------------------------------------------------------- 1 | # Lint as: python3 2 | import torch 3 | import torch.nn as nn 4 | import cv2 5 | import numpy as np 6 | 7 | __all__ = ['edge_preserve'] 8 | 9 | 10 | class EdgePreserve(nn.Module): 11 | 12 | def __init__(self, downsample_factor: int = 16): 13 | super(EdgePreserve, self).__init__() 14 | self.kernel_size = 3 15 | self.sigma_space = 50 16 | self.sigma_color = 2 17 | self.dummy_parameter = nn.Parameter(torch.zeros(1), True) 18 | self.max_pool = nn.MaxPool2d(kernel_size=downsample_factor) 19 | self.avg_pool = nn.AvgPool2d(kernel_size=downsample_factor) 20 | 21 | def forward(self, x): 22 | filtered_samples = [] 23 | for xx in x: 24 | filtered_xx = cv2.bilateralFilter(np.float32(xx.cpu().squeeze()), 25 | d=self.kernel_size, 26 | sigmaColor=self.sigma_color, 27 | sigmaSpace=self.sigma_space) 28 | filtered_samples.append(torch.tensor(filtered_xx)) 29 | x = torch.stack(filtered_samples).to('cuda') 30 | x = x.unsqueeze(1) 31 | x = self.avg_pool(x) 32 | return x 33 | 34 | 35 | def edge_preserve(): 36 | return EdgePreserve() 37 | -------------------------------------------------------------------------------- /models/swe_model.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import torch 4 | import torch.nn as nn 5 | from torch.utils import checkpoint 6 | 7 | import hydraulics.simulation_utils as sim_utils 8 | 9 | __all__ = ['swe_model'] 10 | 11 | 12 | class SweModel(nn.Module): 13 | def __init__(self, downsample_model, numerical_solver, coarse_dx, 14 | coarse_n_x, alpha, simulation_mode=False): 15 | super(SweModel, self).__init__() 16 | self.downsample_model = downsample_model 17 | self.numerical_solver = numerical_solver 18 | self.coarse_dx = coarse_dx 19 | self.coarse_n_x = coarse_n_x 20 | self.alpha = alpha 21 | self.simulation_mode = simulation_mode 22 | self.simulation_current_time = 0 23 | self.simulation_h_n = [] 24 | self.simulation_t = [] 25 | 26 | def set_time_delta(self, dt): 27 | self.numerical_solver.dt = dt 28 | 29 | def set_boundary_conditions(self, boundary_conditions): 30 | self.numerical_solver.boundary_conditions = boundary_conditions 31 | 32 | def forward(self, fine_grid_z_n, hidden_h_n, hidden_q_x_n, hidden_q_y_n, 33 | fine_target_time: torch.Tensor, 34 | coarse_grid_z_n: Optional[torch.Tensor] = None): 35 | if coarse_grid_z_n is None: 36 | coarse_grid_z_n = self.downsample_model(fine_grid_z_n) 37 | self.simulation_current_time = torch.zeros_like(fine_target_time) 38 | # TODO(niv): magic numbers 36 & 100. 39 | delta_t = torch.ones_like(fine_target_time) * 100 40 | for _ in range(36): 41 | hidden_h_n, hidden_q_x_n, hidden_q_y_n = checkpoint.checkpoint( 42 | self.solver, coarse_grid_z_n, hidden_h_n, hidden_q_x_n, 43 | hidden_q_y_n, delta_t) 44 | return coarse_grid_z_n, hidden_h_n, hidden_q_x_n, hidden_q_y_n 45 | 46 | def to_gpu(self): 47 | self.downsample_model = self.downsample_model.cuda() 48 | self.numerical_solver.to_gpu() 49 | 50 | def solver(self, z_n, h_n, q_x_n, q_y_n, target_time): 51 | current_time = torch.zeros_like(target_time) 52 | min_h_n = 0.1 * torch.ones(h_n.shape[0]).cuda() 53 | i = 0 54 | while not torch.isclose(current_time, target_time, rtol=0, 55 | atol=0.01).all(): 56 | with torch.no_grad(): 57 | dt = sim_utils.cfl(self.coarse_dx, torch.max( 58 | h_n.view(h_n.shape[0], -1).max(dim=1).values, 59 | min_h_n), self.alpha) 60 | dt = torch.min(torch.abs(target_time - current_time), 61 | dt.squeeze()).reshape_as(dt) 62 | current_time += dt.squeeze() 63 | self.simulation_current_time += dt.squeeze() 64 | h_n, q_x_n, q_y_n = self.numerical_solver(z_n, h_n, q_x_n, q_y_n, 65 | dt) 66 | i += 1 67 | if self.simulation_mode and (i % 10) == 0: 68 | self.simulation_h_n.append( 69 | h_n.clone().detach().squeeze().cpu().numpy()) 70 | self.simulation_t.append(self.simulation_current_time.item()) 71 | return h_n, q_x_n, q_y_n 72 | 73 | 74 | def swe_model(*args, **kwargs): 75 | return SweModel(*args, **kwargs) 76 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pandas==1.1.3 2 | opencv_python==4.5.1.48 3 | torch==1.7.1 4 | matplotlib==3.3.2 5 | numpy==1.19.2 6 | Jinja2==2.11.2 7 | absl_py==0.11.0 8 | tqdm==4.50.2 9 | dataclasses==0.8 10 | scikit_image==0.16.2 11 | skimage==0.0 -------------------------------------------------------------------------------- /source/001/ned232_20200818_172734.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tech-submissions/physics-aware-downsampling/c16417712f0e081db34e783968ce54fb9ee44479/source/001/ned232_20200818_172734.png -------------------------------------------------------------------------------- /source/001/ned232_20200818_172734.txt: -------------------------------------------------------------------------------- 1 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x24y407_MO_AR_Miss_Stoddard_UTM16_2014.tif 2 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x24y406_MO_AR_NewMadrid_Pemiscot_2014.tif 3 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x24y406_MO_AR_Miss_Stoddard_UTM16_2014.tif 4 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x25y407_MO_AR_Miss_Stoddard_UTM16_2014.tif 5 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x24y405_MO_AR_NewMadrid_Pemiscot_2014.tif 6 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x25y406_MO_AR_Miss_Stoddard_UTM16_2014.tif 7 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x25y406_MO_AR_NewMadrid_Pemiscot_2014.tif 8 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x24y404_MO_AR_NewMadrid_Pemiscot_2014.tif 9 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x26y407_MO_AR_Miss_Stoddard_UTM16_2014.tif 10 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x25y405_MO_AR_NewMadrid_Pemiscot_2014.tif 11 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x24y403_MO_AR_NewMadrid_Pemiscot_2014.tif 12 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x26y406_MO_AR_NewMadrid_Pemiscot_2014.tif 13 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x26y406_MO_AR_Miss_Stoddard_UTM16_2014.tif 14 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x25y404_MO_AR_NewMadrid_Pemiscot_2014.tif 15 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x27y407_MO_AR_Miss_Stoddard_UTM16_2014.tif 16 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x24y402_MO_AR_NewMadrid_Pemiscot_2014.tif 17 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x26y405_MO_AR_NewMadrid_Pemiscot_2014.tif 18 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x25y403_MO_AR_NewMadrid_Pemiscot_2014.tif 19 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x27y406_MO_AR_NewMadrid_Pemiscot_2014.tif 20 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x27y406_MO_AR_Miss_Stoddard_UTM16_2014.tif 21 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x24y401_MO_AR_NewMadrid_Pemiscot_2014.tif 22 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x26y404_MO_AR_NewMadrid_Pemiscot_2014.tif 23 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x28y407_MO_AR_Miss_Stoddard_UTM16_2014.tif 24 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x25y402_MO_AR_NewMadrid_Pemiscot_2014.tif 25 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x27y405_MO_AR_NewMadrid_Pemiscot_2014.tif 26 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x24y400_MO_AR_Miss_Laud_UTM16_2014.tif 27 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x24y400_MO_AR_NewMadrid_Pemiscot_2014.tif 28 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x26y403_MO_AR_NewMadrid_Pemiscot_2014.tif 29 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x28y406_MO_AR_Miss_Stoddard_UTM16_2014.tif 30 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x28y406_MO_AR_NewMadrid_Pemiscot_2014.tif 31 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x25y401_MO_AR_NewMadrid_Pemiscot_2014.tif 32 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x27y404_MO_AR_NewMadrid_Pemiscot_2014.tif 33 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x29y407_MO_AR_Miss_Stoddard_UTM16_2014.tif 34 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x24y399_MO_AR_NewMadrid_Pemiscot_2014.tif 35 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x24y399_MO_AR_Miss_Laud_UTM16_2014.tif 36 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x26y402_MO_AR_NewMadrid_Pemiscot_2014.tif 37 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x28y405_MO_AR_Miss_Stoddard_UTM16_2014.tif 38 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x28y405_MO_AR_NewMadrid_Pemiscot_2014.tif 39 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x25y400_MO_AR_Miss_Laud_UTM16_2014.tif 40 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x25y400_MO_AR_NewMadrid_Pemiscot_2014.tif 41 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x27y403_MO_AR_NewMadrid_Pemiscot_2014.tif 42 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x29y406_MO_AR_Miss_Stoddard_UTM16_2014.tif 43 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x29y406_MO_AR_NewMadrid_Pemiscot_2014.tif 44 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x24y398_MO_AR_Miss_Laud_UTM16_2014.tif 45 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x26y401_MO_AR_NewMadrid_Pemiscot_2014.tif 46 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x28y404_MO_AR_NewMadrid_Pemiscot_2014.tif 47 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x25y399_MO_AR_NewMadrid_Pemiscot_2014.tif 48 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x25y399_MO_AR_Miss_Laud_UTM16_2014.tif 49 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x27y402_MO_AR_NewMadrid_Pemiscot_2014.tif 50 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x29y405_MO_AR_Miss_Stoddard_UTM16_2014.tif 51 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x29y405_MO_AR_NewMadrid_Pemiscot_2014.tif 52 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x24y397_MO_AR_Miss_Laud_UTM16_2014.tif 53 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x26y400_MO_AR_NewMadrid_Pemiscot_2014.tif 54 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x26y400_MO_AR_Miss_Laud_UTM16_2014.tif 55 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x25y398_MO_AR_Miss_Laud_UTM16_2014.tif 56 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x27y401_MO_AR_NewMadrid_Pemiscot_2014.tif 57 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x26y399_MO_AR_Miss_Laud_UTM16_2014.tif 58 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x26y399_MO_AR_NewMadrid_Pemiscot_2014.tif 59 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x25y397_MO_AR_Miss_Laud_UTM16_2014.tif 60 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x26y398_MO_AR_Miss_Laud_UTM16_2014.tif 61 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x26y397_MO_AR_Miss_Laud_UTM16_2014.tif 62 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x27y398_MO_AR_Miss_Laud_UTM16_2014.tif 63 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y406_TN_NRCS_2011.tif 64 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y406_TN_NRCS_L1_2011_12.tif 65 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y406_TN_NRCS_2011.tif 66 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y406_TN_NRCS_L1_2011_12.tif 67 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y405_TN_NRCS_2011.tif 68 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y405_TN_NRCS_L1_2011_12.tif 69 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y405_TN_NRCS_2011.tif 70 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y405_TN_NRCS_L1_2011_12.tif 71 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y405_TN_NRCS_2011.tif 72 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y405_TN_NRCS_L1_2011_12.tif 73 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y404_TN_NRCS_L1_2011_12.tif 74 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y404_TN_NRCS_2011.tif 75 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y404_TN_NRCS_2011.tif 76 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y404_TN_NRCS_L1_2011_12.tif 77 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y404_TN_NRCS_L1_2011_12.tif 78 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y404_TN_NRCS_2011.tif 79 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y403_TN_NRCS_2011.tif 80 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y403_TN_NRCS_L1_2011_12.tif 81 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y403_TN_NRCS_2011.tif 82 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y403_TN_NRCS_L1_2011_12.tif 83 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y403_TN_NRCS_L1_2011_12.tif 84 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y403_TN_NRCS_2011.tif 85 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x26y403_TN_NRCS_2011.tif 86 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x26y403_TN_NRCS_L1_2011_12.tif 87 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y402_TN_NRCS_2011.tif 88 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y402_TN_NRCS_L1_2011_12.tif 89 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y402_TN_NRCS_L1_2011_12.tif 90 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y402_TN_NRCS_2011.tif 91 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y402_TN_NRCS_L1_2011_12.tif 92 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y402_TN_NRCS_2011.tif 93 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x26y402_TN_NRCS_L1_2011_12.tif 94 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x26y402_TN_NRCS_2011.tif 95 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x25y402_TN_NRCS_L1_2011_12.tif 96 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x25y402_TN_NRCS_2011.tif 97 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y401_TN_NRCS_2011.tif 98 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y401_TN_NRCS_L1_2011_12.tif 99 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y401_TN_NRCS_2011.tif 100 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y401_TN_NRCS_L1_2011_12.tif 101 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y401_TN_NRCS_2011.tif 102 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y401_TN_NRCS_L1_2011_12.tif 103 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x26y401_TN_NRCS_2011.tif 104 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x26y401_TN_NRCS_L1_2011_12.tif 105 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y400_TN_NRCS_L1_2011_12.tif 106 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y400_TN_NRCS_2011.tif 107 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y400_TN_NRCS_2011.tif 108 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y400_TN_NRCS_L1_2011_12.tif 109 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y400_TN_NRCS_L1_2011_12.tif 110 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y400_TN_NRCS_2011.tif 111 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x26y400_TN_NRCS_L1_2011_12.tif 112 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x26y400_TN_NRCS_2011.tif 113 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x25y400_TN_NRCS_L1_2011_12.tif 114 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x25y400_TN_NRCS_2011.tif 115 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y399_TN_NRCS_L1_2011_12.tif 116 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y399_TN_NRCS_2011.tif 117 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y399_TN_NRCS_L1_2011_12.tif 118 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y399_TN_NRCS_2011.tif 119 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y399_TN_NRCS_L1_2011_12.tif 120 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y399_TN_NRCS_2011.tif 121 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x26y399_TN_NRCS_L1_2011_12.tif 122 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x26y399_TN_NRCS_2011.tif 123 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x25y399_TN_NRCS_2011.tif 124 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x25y399_TN_NRCS_L1_2011_12.tif 125 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y398_TN_NRCS_L1_2011_12.tif 126 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y398_TN_NRCS_2011.tif 127 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y398_TN_NRCS_2011.tif 128 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y398_TN_NRCS_L1_2011_12.tif 129 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y398_TN_NRCS_2011.tif 130 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y398_TN_NRCS_L1_2011_12.tif 131 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x26y398_TN_NRCS_L1_2011_12.tif 132 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x26y398_TN_NRCS_2011.tif 133 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x25y398_TN_NRCS_2011.tif 134 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x25y398_TN_NRCS_L1_2011_12.tif 135 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y397_TN_NRCS_2011.tif 136 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y397_TN_NRCS_L1_2011_12.tif 137 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y397_TN_NRCS_L1_2011_12.tif 138 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y397_TN_NRCS_2011.tif 139 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y397_TN_NRCS_L1_2011_12.tif 140 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y397_TN_NRCS_2011.tif 141 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x26y397_TN_NRCS_2011.tif 142 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x26y397_TN_NRCS_L1_2011_12.tif 143 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x25y397_TN_NRCS_L1_2011_12.tif 144 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x25y397_TN_NRCS_2011.tif 145 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x30y407_MO_AR_Miss_Stoddard_UTM16_2014.tif 146 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x30y406_MO_AR_Miss_Stoddard_UTM16_2014.tif 147 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y406_TN_NRCS_L1_2011_12.tif 148 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y406_TN_NRCS_2011.tif 149 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x30y405_MO_AR_Miss_Stoddard_UTM16_2014.tif 150 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y405_TN_NRCS_L1_2011_12.tif 151 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y405_TN_NRCS_2011.tif 152 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y404_TN_NRCS_2011.tif 153 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y404_TN_NRCS_L1_2011_12.tif 154 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y403_TN_NRCS_L1_2011_12.tif 155 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y403_TN_NRCS_2011.tif 156 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y402_TN_NRCS_L1_2011_12.tif 157 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y402_TN_NRCS_2011.tif 158 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y401_TN_NRCS_L1_2011_12.tif 159 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y401_TN_NRCS_2011.tif 160 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x29y396_TN_NRCS_L1_2011_12.tif 161 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x29y396_TN_NRCS_2011.tif 162 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x24y408_MO_AR_Miss_Stoddard_UTM16_2014.tif 163 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y400_TN_NRCS_L1_2011_12.tif 164 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y400_TN_NRCS_2011.tif 165 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x28y396_TN_NRCS_L1_2011_12.tif 166 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x28y396_TN_NRCS_2011.tif 167 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y399_TN_NRCS_2011.tif 168 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y399_TN_NRCS_L1_2011_12.tif 169 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x25y408_MO_AR_Miss_Stoddard_UTM16_2014.tif 170 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y398_TN_NRCS_L1_2011_12.tif 171 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y398_TN_NRCS_2011.tif 172 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x27y396_TN_NRCS_L1_2011_12.tif 173 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x27y396_TN_NRCS_2011.tif 174 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x26y408_MO_AR_Miss_Stoddard_UTM16_2014.tif 175 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y397_TN_NRCS_2011.tif 176 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y397_TN_NRCS_L1_2011_12.tif 177 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x26y396_TN_NRCS_2011.tif 178 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x26y396_TN_NRCS_L1_2011_12.tif 179 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x27y408_MO_AR_Miss_Stoddard_UTM16_2014.tif 180 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x25y396_MO_AR_Miss_Laud_UTM16_2014.tif 181 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x25y396_TN_NRCS_2011.tif 182 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x25y396_TN_NRCS_L1_2011_12.tif 183 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x28y408_MO_AR_Miss_Stoddard_UTM16_2014.tif 184 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM15_2014/TIFF/USGS_one_meter_x77y407_MO_AR_Miss_Stoddard_UTM15_2014.tif 185 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x77y407_MO_AR_Miss_Stoddard_UTM16_2014.tif 186 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x24y396_MO_AR_Miss_Laud_UTM16_2014.tif 187 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x24y396_TN_NRCS_L1_2011_12.tif 188 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x24y396_TN_NRCS_2011.tif 189 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x29y408_MO_AR_Miss_Stoddard_UTM16_2014.tif 190 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x77y406_MO_AR_Miss_Stoddard_UTM16_2014.tif 191 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM15_2014/TIFF/USGS_one_meter_x77y406_MO_AR_Miss_Stoddard_UTM15_2014.tif 192 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x77y406_MO_AR_NewMadrid_Pemiscot_2014.tif 193 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x77y405_MO_AR_NewMadrid_Pemiscot_2014.tif 194 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x23y397_MO_AR_Miss_Laud_UTM16_2014.tif 195 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x77y404_MO_AR_NewMadrid_Pemiscot_2014.tif 196 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x23y398_MO_AR_Miss_Laud_UTM16_2014.tif 197 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x77y403_MO_AR_NewMadrid_Pemiscot_2014.tif 198 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x30y408_MO_AR_Miss_Stoddard_UTM16_2014.tif 199 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x23y399_AR_Ouachita_B7_2016.tif 200 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x23y399_MO_AR_NewMadrid_Pemiscot_2014.tif 201 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x23y399_MO_AR_Miss_Laud_UTM16_2014.tif 202 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x77y408_MO_AR_Miss_Stoddard_UTM16_2014.tif 203 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_CapeGirardeau_Stoddard_2013/TIFF/USGS_one_meter_x77y408_MO_AR_CapeGirardeau_Stoddard_2013.tif 204 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM15_2014/TIFF/USGS_one_meter_x77y408_MO_AR_Miss_Stoddard_UTM15_2014.tif 205 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x77y402_MO_AR_NewMadrid_Pemiscot_2014.tif 206 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_2011/TIFF/USGS_one_meter_x30y396_TN_NRCS_2011.tif 207 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/TN_NRCS_L1_2011_12/TIFF/USGS_one_meter_x30y396_TN_NRCS_L1_2011_12.tif 208 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x23y400_MO_AR_Miss_Laud_UTM16_2014.tif 209 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x23y400_MO_AR_NewMadrid_Pemiscot_2014.tif 210 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x77y401_MO_AR_NewMadrid_Pemiscot_2014.tif 211 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x23y401_MO_AR_NewMadrid_Pemiscot_2014.tif 212 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x77y400_MO_AR_Miss_Laud_UTM16_2014.tif 213 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x77y400_MO_AR_NewMadrid_Pemiscot_2014.tif 214 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x23y402_MO_AR_NewMadrid_Pemiscot_2014.tif 215 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x77y399_MO_AR_Miss_Laud_UTM16_2014.tif 216 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x77y399_MO_AR_NewMadrid_Pemiscot_2014.tif 217 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x77y399_AR_Ouachita_B7_2016.tif 218 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x23y403_MO_AR_NewMadrid_Pemiscot_2014.tif 219 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x77y398_MO_AR_Miss_Laud_UTM16_2014.tif 220 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x23y396_MO_AR_Miss_Laud_UTM16_2014.tif 221 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x23y404_MO_AR_NewMadrid_Pemiscot_2014.tif 222 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x77y397_MO_AR_Miss_Laud_UTM16_2014.tif 223 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x23y405_MO_AR_NewMadrid_Pemiscot_2014.tif 224 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM15_2014/TIFF/USGS_one_meter_x23y406_MO_AR_Miss_Stoddard_UTM15_2014.tif 225 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x23y406_MO_AR_Miss_Stoddard_UTM16_2014.tif 226 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_NewMadrid_Pemiscot_2014/TIFF/USGS_one_meter_x23y406_MO_AR_NewMadrid_Pemiscot_2014.tif 227 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x23y407_MO_AR_Miss_Stoddard_UTM16_2014.tif 228 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM15_2014/TIFF/USGS_one_meter_x23y407_MO_AR_Miss_Stoddard_UTM15_2014.tif 229 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Laud_UTM16_2014/TIFF/USGS_one_meter_x77y396_MO_AR_Miss_Laud_UTM16_2014.tif 230 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_CapeGirardeau_Stoddard_2013/TIFF/USGS_one_meter_x23y408_MO_AR_CapeGirardeau_Stoddard_2013.tif 231 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM16_2014/TIFF/USGS_one_meter_x23y408_MO_AR_Miss_Stoddard_UTM16_2014.tif 232 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/MO_AR_Miss_Stoddard_UTM15_2014/TIFF/USGS_one_meter_x23y408_MO_AR_Miss_Stoddard_UTM15_2014.tif 233 | 234 | -------------------------------------------------------------------------------- /source/002/ned69_20200818_175155.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tech-submissions/physics-aware-downsampling/c16417712f0e081db34e783968ce54fb9ee44479/source/002/ned69_20200818_175155.png -------------------------------------------------------------------------------- /source/002/ned69_20200818_175155.txt: -------------------------------------------------------------------------------- 1 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x32y439_CO_Central_Western_2016.tif 2 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x31y439_CO_Central_Western_2016.tif 3 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x30y439_CO_Central_Western_2016.tif 4 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x29y439_CO_Central_Western_2016.tif 5 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x28y439_CO_Central_Western_2016.tif 6 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x32y438_CO_Central_Western_2016.tif 7 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x27y439_CO_Central_Western_2016.tif 8 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x31y438_CO_Central_Western_2016.tif 9 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x26y439_CO_Central_Western_2016.tif 10 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x30y438_CO_Central_Western_2016.tif 11 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x25y439_CO_Central_Western_2016.tif 12 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x29y438_CO_Central_Western_2016.tif 13 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x75y439_CO_Central_Western_2016.tif 14 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x24y439_CO_Central_Western_2016.tif 15 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x28y438_CO_Central_Western_2016.tif 16 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x76y439_CO_Central_Western_2016.tif 17 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x23y439_CO_Central_Western_2016.tif 18 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x27y438_CO_Central_Western_2016.tif 19 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x26y438_CO_Central_Western_2016.tif 20 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x25y438_CO_Central_Western_2016.tif 21 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x24y438_CO_Central_Western_2016.tif 22 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x75y438_CO_Central_Western_2016.tif 23 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x76y438_CO_Central_Western_2016.tif 24 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x23y438_CO_Central_Western_2016.tif 25 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x74y439_CO_Central_Western_2016.tif 26 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x74y438_CO_Central_Western_2016.tif 27 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x23y440_CO_Central_Western_2016.tif 28 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x76y440_CO_Central_Western_2016.tif 29 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x75y440_CO_Central_Western_2016.tif 30 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x24y440_CO_Central_Western_2016.tif 31 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x25y440_CO_Central_Western_2016.tif 32 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x26y440_CO_Central_Western_2016.tif 33 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x27y440_CO_Central_Western_2016.tif 34 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x28y440_CO_Central_Western_2016.tif 35 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x29y440_CO_Central_Western_2016.tif 36 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x32y437_CO_Central_Western_2016.tif 37 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x30y440_CO_Central_Western_2016.tif 38 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x74y440_CO_Central_Western_2016.tif 39 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x31y437_CO_Central_Western_2016.tif 40 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x31y440_CO_Central_Western_2016.tif 41 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x30y437_CO_Central_Western_2016.tif 42 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x32y440_CO_Central_Western_2016.tif 43 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x33y439_CO_Central_Western_2016.tif 44 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM13_2015/TIFF/USGS_one_meter_x29y437_CO_MesaCo_QL2_UTM13_2015.tif 45 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x29y437_CO_Central_Western_2016.tif 46 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x33y438_CO_Central_Western_2016.tif 47 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x28y437_CO_Central_Western_2016.tif 48 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM13_2015/TIFF/USGS_one_meter_x28y437_CO_MesaCo_QL2_UTM13_2015.tif 49 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x27y437_CO_Central_Western_2016.tif 50 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM13_2015/TIFF/USGS_one_meter_x27y437_CO_MesaCo_QL2_UTM13_2015.tif 51 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x26y437_CO_Central_Western_2016.tif 52 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM13_2015/TIFF/USGS_one_meter_x26y437_CO_MesaCo_QL2_UTM13_2015.tif 53 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM13_2015/TIFF/USGS_one_meter_x25y437_CO_MesaCo_QL2_UTM13_2015.tif 54 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x25y437_CO_Central_Western_2016.tif 55 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM13_2015/TIFF/USGS_one_meter_x75y437_CO_MesaCo_QL2_UTM13_2015.tif 56 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x75y437_CO_Central_Western_2016.tif 57 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM12_2016/TIFF/USGS_one_meter_x75y437_CO_MesaCo_QL2_UTM12_2016.tif 58 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM12_2016/TIFF/USGS_one_meter_x74y437_CO_MesaCo_QL2_UTM12_2016.tif 59 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x74y437_CO_Central_Western_2016.tif 60 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x33y437_CO_Central_Western_2016.tif 61 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x24y437_CO_Central_Western_2016.tif 62 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM13_2015/TIFF/USGS_one_meter_x24y437_CO_MesaCo_QL2_UTM13_2015.tif 63 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM12_2016/TIFF/USGS_one_meter_x24y437_CO_MesaCo_QL2_UTM12_2016.tif 64 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x76y437_CO_Central_Western_2016.tif 65 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM13_2015/TIFF/USGS_one_meter_x76y437_CO_MesaCo_QL2_UTM13_2015.tif 66 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x33y440_CO_Central_Western_2016.tif 67 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_Central_Western_2016/TIFF/USGS_one_meter_x23y437_CO_Central_Western_2016.tif 68 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM13_2015/TIFF/USGS_one_meter_x23y437_CO_MesaCo_QL2_UTM13_2015.tif 69 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/CO_MesaCo_QL2_UTM12_2016/TIFF/USGS_one_meter_x23y437_CO_MesaCo_QL2_UTM12_2016.tif 70 | 71 | -------------------------------------------------------------------------------- /source/003/ned173_20200818_174748.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tech-submissions/physics-aware-downsampling/c16417712f0e081db34e783968ce54fb9ee44479/source/003/ned173_20200818_174748.png -------------------------------------------------------------------------------- /source/003/ned173_20200818_174748.txt: -------------------------------------------------------------------------------- 1 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x54y393_AR_LakeConwayPointRE_2014.tif 2 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x54y392_AR_LakeConwayPointRE_2014.tif 3 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x53y393_AR_LakeConwayPointRE_2014.tif 4 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x53y392_AR_LakeConwayPointRE_2014.tif 5 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x45y390_AR_Ouachita_B7_2016.tif 6 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x54y390_AR_LakeConwayPointRE_2014.tif 7 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x52y393_AR_LakeConwayPointRE_2014.tif 8 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x53y391_AR_LakeConwayPointRE_2014.tif 9 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x54y389_AR_LakeConwayPointRE_2014.tif 10 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x45y389_AR_Ouachita_B7_2016.tif 11 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x52y392_AR_LakeConwayPointRE_2014.tif 12 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x53y390_AR_LakeConwayPointRE_2014.tif 13 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x46y390_AR_Ouachita_B7_2016.tif 14 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x54y388_AR_LakeConwayPointRE_2014.tif 15 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x45y388_AR_Ouachita_B7_2016.tif 16 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x51y393_AR_LakeConwayPointRE_2014.tif 17 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x52y391_AR_LakeConwayPointRE_2014.tif 18 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x53y389_AR_LakeConwayPointRE_2014.tif 19 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x46y389_AR_Ouachita_B7_2016.tif 20 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x54y387_AR_Ouachita_B6_2016.tif 21 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x45y387_AR_Ouachita_B7_2016.tif 22 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x54y387_AR_Ouachita_B7_2016.tif 23 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x54y387_AR_LakeConwayPointRE_2014.tif 24 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x45y387_AR_Ouachita_B6_2016.tif 25 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x51y392_AR_LakeConwayPointRE_2014.tif 26 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x47y390_AR_LakeConwayPointRE_2014.tif 27 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x47y390_AR_Ouachita_B7_2016.tif 28 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x52y390_AR_LakeConwayPointRE_2014.tif 29 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x46y388_AR_Ouachita_B7_2016.tif 30 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x53y388_AR_LakeConwayPointRE_2014.tif 31 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x51y391_AR_LakeConwayPointRE_2014.tif 32 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x48y391_AR_LakeConwayPointRE_2014.tif 33 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x50y393_AR_LakeConwayPointRE_2014.tif 34 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x47y389_AR_LakeConwayPointRE_2014.tif 35 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x52y389_AR_LakeConwayPointRE_2014.tif 36 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x47y389_AR_Ouachita_B7_2016.tif 37 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x53y387_AR_LakeConwayPointRE_2014.tif 38 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x53y387_AR_Ouachita_B7_2016.tif 39 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x46y387_AR_Ouachita_B7_2016.tif 40 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x53y387_AR_Ouachita_B6_2016.tif 41 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x46y387_AR_Ouachita_B6_2016.tif 42 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x50y393_AR_DardanelleReservoir_2015.tif 43 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x51y393_AR_DardanelleReservoir_2015.tif 44 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x48y393_AR_DardanelleReservoir_2015.tif 45 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x47y393_AR_DardanelleReservoir_2015.tif 46 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x46y393_AR_DardanelleReservoir_2015.tif 47 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x49y393_AR_DardanelleReservoir_2015.tif 48 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_North_Corridor_B2_2017/TIFF/USGS_one_meter_x53y393_AR_North_Corridor_B2_2017.tif 49 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x51y390_AR_Ouachita_B7_2016.tif 50 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x51y390_AR_LakeConwayPointRE_2014.tif 51 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x48y390_AR_LakeConwayPointRE_2014.tif 52 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x50y392_AR_LakeConwayPointRE_2014.tif 53 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x49y392_AR_LakeConwayPointRE_2014.tif 54 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x52y388_AR_LakeConwayPointRE_2014.tif 55 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x47y388_AR_Ouachita_B7_2016.tif 56 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x45y393_AR_DardanelleReservoir_2015.tif 57 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_North_Corridor_B2_2017/TIFF/USGS_one_meter_x54y393_AR_North_Corridor_B2_2017.tif 58 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x54y393_AR_NRCS_A4_2016.tif 59 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x48y392_AR_DardanelleReservoir_2015.tif 60 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x53y392_AR_NRCS_A4_2016.tif 61 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x49y392_AR_DardanelleReservoir_2015.tif 62 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x50y392_AR_DardanelleReservoir_2015.tif 63 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x54y392_AR_NRCS_A4_2016.tif 64 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x45y392_AR_DardanelleReservoir_2015.tif 65 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x47y392_AR_DardanelleReservoir_2015.tif 66 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x46y392_AR_DardanelleReservoir_2015.tif 67 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x48y389_AR_LakeConwayPointRE_2014.tif 68 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x51y389_AR_LakeConwayPointRE_2014.tif 69 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x51y389_AR_Ouachita_B7_2016.tif 70 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x48y389_AR_Ouachita_B7_2016.tif 71 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x50y391_AR_LakeConwayPointRE_2014.tif 72 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x49y391_AR_LakeConwayPointRE_2014.tif 73 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x52y387_AR_Ouachita_B6_2016.tif 74 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x47y387_AR_Ouachita_B6_2016.tif 75 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x47y387_AR_Ouachita_B7_2016.tif 76 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x52y387_AR_Ouachita_B7_2016.tif 77 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x48y391_AR_DardanelleReservoir_2015.tif 78 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x49y391_AR_DardanelleReservoir_2015.tif 79 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x47y391_AR_DardanelleReservoir_2015.tif 80 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x46y391_AR_DardanelleReservoir_2015.tif 81 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x53y391_AR_NRCS_A4_2016.tif 82 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x51y388_AR_LakeConwayPointRE_2014.tif 83 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x51y388_AR_Ouachita_B7_2016.tif 84 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x48y388_AR_Ouachita_B7_2016.tif 85 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x50y390_AR_LakeConwayPointRE_2014.tif 86 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x50y390_AR_Ouachita_B7_2016.tif 87 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x49y390_AR_LakeConwayPointRE_2014.tif 88 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x49y390_AR_Ouachita_B7_2016.tif 89 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x45y391_AR_DardanelleReservoir_2015.tif 90 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x54y391_AR_NRCS_A4_2016.tif 91 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x47y390_AR_DardanelleReservoir_2015.tif 92 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x53y390_AR_NRCS_A4_2016.tif 93 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x46y390_AR_DardanelleReservoir_2015.tif 94 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x54y390_AR_NRCS_A4_2016.tif 95 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x45y390_AR_DardanelleReservoir_2015.tif 96 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x48y390_AR_DardanelleReservoir_2015.tif 97 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x48y387_AR_Ouachita_B7_2016.tif 98 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x51y387_AR_Ouachita_B7_2016.tif 99 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x51y387_AR_Ouachita_B6_2016.tif 100 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x48y387_AR_Ouachita_B6_2016.tif 101 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x50y389_AR_LakeConwayPointRE_2014.tif 102 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x50y389_AR_Ouachita_B7_2016.tif 103 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x49y389_AR_LakeConwayPointRE_2014.tif 104 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x49y389_AR_Ouachita_B7_2016.tif 105 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x50y388_AR_LakeConwayPointRE_2014.tif 106 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x50y388_AR_Ouachita_B7_2016.tif 107 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x49y388_AR_Ouachita_B7_2016.tif 108 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x45y389_AR_DardanelleReservoir_2015.tif 109 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A1_2016/TIFF/USGS_one_meter_x50y388_AR_NRCS_A1_2016.tif 110 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A1_2016/TIFF/USGS_one_meter_x51y388_AR_NRCS_A1_2016.tif 111 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A1_2016/TIFF/USGS_one_meter_x53y388_AR_NRCS_A1_2016.tif 112 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A1_2016/TIFF/USGS_one_meter_x52y388_AR_NRCS_A1_2016.tif 113 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x50y387_AR_Ouachita_B6_2016.tif 114 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x50y387_AR_Ouachita_B7_2016.tif 115 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x49y387_AR_Ouachita_B6_2016.tif 116 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x49y387_AR_Ouachita_B7_2016.tif 117 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A1_2016/TIFF/USGS_one_meter_x51y387_AR_NRCS_A1_2016.tif 118 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A1_2016/TIFF/USGS_one_meter_x53y387_AR_NRCS_A1_2016.tif 119 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A1_2016/TIFF/USGS_one_meter_x52y387_AR_NRCS_A1_2016.tif 120 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x55y387_AR_Ouachita_B7_2016.tif 121 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x55y387_AR_Ouachita_B6_2016.tif 122 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x55y387_AR_LakeConwayPointRE_2014.tif 123 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x55y388_AR_LakeConwayPointRE_2014.tif 124 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x55y389_AR_LakeConwayPointRE_2014.tif 125 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x55y389_AR_NRCS_A4_2016.tif 126 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x55y390_AR_NRCS_A4_2016.tif 127 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x55y391_AR_NRCS_A4_2016.tif 128 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x55y392_AR_NRCS_A4_2016.tif 129 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_North_Corridor_B2_2017/TIFF/USGS_one_meter_x55y393_AR_North_Corridor_B2_2017.tif 130 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x55y393_AR_NRCS_A4_2016.tif 131 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x44y387_AR_Ouachita_B6_2016.tif 132 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x44y387_AR_Ouachita_B7_2016.tif 133 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x44y388_AR_Ouachita_B7_2016.tif 134 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B7_2016/TIFF/USGS_one_meter_x44y389_AR_Ouachita_B7_2016.tif 135 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x44y389_AR_DardanelleReservoir_2015.tif 136 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x44y390_AR_DardanelleReservoir_2015.tif 137 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x44y391_AR_DardanelleReservoir_2015.tif 138 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x44y392_AR_DardanelleReservoir_2015.tif 139 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x44y393_AR_DardanelleReservoir_2015.tif 140 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x50y386_AR_Ouachita_B6_2016.tif 141 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_UpperSaline_2014/TIFF/USGS_one_meter_x50y386_AR_UpperSaline_2014.tif 142 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x49y386_AR_Ouachita_B6_2016.tif 143 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_UpperSaline_2014/TIFF/USGS_one_meter_x49y386_AR_UpperSaline_2014.tif 144 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x51y386_AR_Ouachita_B6_2016.tif 145 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_UpperSaline_2014/TIFF/USGS_one_meter_x51y386_AR_UpperSaline_2014.tif 146 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x48y386_AR_Ouachita_B6_2016.tif 147 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_UpperSaline_2014/TIFF/USGS_one_meter_x52y386_AR_UpperSaline_2014.tif 148 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x47y386_AR_Ouachita_B6_2016.tif 149 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x52y386_AR_Ouachita_B6_2016.tif 150 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x46y386_AR_Ouachita_B6_2016.tif 151 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x53y386_AR_Ouachita_B6_2016.tif 152 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_UpperSaline_2014/TIFF/USGS_one_meter_x53y386_AR_UpperSaline_2014.tif 153 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x45y386_AR_Ouachita_B6_2016.tif 154 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x54y386_AR_Ouachita_B6_2016.tif 155 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x55y386_AR_Ouachita_B6_2016.tif 156 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_Ouachita_B6_2016/TIFF/USGS_one_meter_x44y386_AR_Ouachita_B6_2016.tif 157 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_North_Corridor_B2_2017/TIFF/USGS_one_meter_x54y394_AR_North_Corridor_B2_2017.tif 158 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x45y394_AR_DardanelleReservoir_2015.tif 159 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x53y394_AR_LakeConwayPointRE_2014.tif 160 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_North_Corridor_B2_2017/TIFF/USGS_one_meter_x53y394_AR_North_Corridor_B2_2017.tif 161 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x46y394_AR_DardanelleReservoir_2015.tif 162 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x52y394_AR_LakeConwayPointRE_2014.tif 163 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_North_Corridor_B2_2017/TIFF/USGS_one_meter_x52y394_AR_North_Corridor_B2_2017.tif 164 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x47y394_AR_DardanelleReservoir_2015.tif 165 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_LakeConwayPointRE_2014/TIFF/USGS_one_meter_x51y394_AR_LakeConwayPointRE_2014.tif 166 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_North_Corridor_B2_2017/TIFF/USGS_one_meter_x51y394_AR_North_Corridor_B2_2017.tif 167 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x51y394_AR_DardanelleReservoir_2015.tif 168 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x48y394_AR_DardanelleReservoir_2015.tif 169 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x50y394_AR_DardanelleReservoir_2015.tif 170 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x49y394_AR_DardanelleReservoir_2015.tif 171 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_NRCS_A4_2016/TIFF/USGS_one_meter_x55y394_AR_NRCS_A4_2016.tif 172 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_North_Corridor_B2_2017/TIFF/USGS_one_meter_x55y394_AR_North_Corridor_B2_2017.tif 173 | https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1m/Projects/AR_DardanelleReservoir_2015/TIFF/USGS_one_meter_x44y394_AR_DardanelleReservoir_2015.tif 174 | 175 | -------------------------------------------------------------------------------- /source/source.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import io 3 | import os 4 | from skimage.external import tifffile 5 | from typing import Sequence, Text, Optional 6 | import pandas as pd 7 | import utils 8 | import logging 9 | 10 | SOURCE_PATH = '/home/usgs_dem_data_source' 11 | PATH = '/home/usgs_dem_data/dem' 12 | TILE_SIZE = 2000 13 | ALLOWED_MASKED_PERCENTAGE = 0 14 | MAX_TOPOGRAPHY_DIFFERENCE = 100 15 | INFLUX_LENGTH = 400 16 | OUTFLUX_LENGTH = 400 17 | 18 | 19 | def read_source_files(root_dir: Text): 20 | if not os.path.exists(root_dir): 21 | raise ValueError(f'{root_dir} Does not exists') 22 | for root, dirs, files in os.walk(root_dir): 23 | for file in files: 24 | if file.endswith('.tif'): 25 | yield os.path.join(root, file) 26 | 27 | 28 | def process_dem(tif_file_path: Text): 29 | with open(tif_file_path, 'rb') as f: 30 | tiffbytes = f.read() 31 | np_map = tifffile.imread(io.BytesIO(tiffbytes)) 32 | np_ma_map = np.ma.masked_array(np_map, mask=(np_map < -2000)) 33 | np_ma_map = utils.fix_missing_values(np_ma_map) 34 | 35 | tiles = utils.divide_to_tiles(np_ma_map, (TILE_SIZE, TILE_SIZE)) 36 | tiles_filtered = [] 37 | for tile in tiles: 38 | if (utils.masked_values_percentage( 39 | tile) <= ALLOWED_MASKED_PERCENTAGE) and ( 40 | utils.topography_difference( 41 | tile) <= MAX_TOPOGRAPHY_DIFFERENCE): 42 | tiles_filtered.append(tile) 43 | 44 | dir_name = os.path.dirname(tif_file_path).split('/')[-1] 45 | file_name = tif_file_path.split('/')[-1].split('.')[0] 46 | samples = [] 47 | for index, tile in enumerate(tiles_filtered): 48 | min_location = utils.find_lowest_point(tile) 49 | x, y = min_location 50 | rows, cols = tile.shape 51 | outflux = (x, y, OUTFLUX_LENGTH) 52 | if x > 0: 53 | influx_axis = 0 if y < 0 else -1 54 | influx = (rows // 2, influx_axis, INFLUX_LENGTH) 55 | else: 56 | influx_axis = 0 if x < 0 else -1 57 | influx = (influx_axis, cols // 2, INFLUX_LENGTH) 58 | full_path = os.path.join(PATH, dir_name, f'{file_name}_{index}.npy') 59 | samples.append((full_path, influx, outflux)) 60 | np.save(full_path, np.asarray(tile)) 61 | 62 | df = pd.DataFrame(samples, columns=['dem', 'influx', 'outflux']) 63 | index_path = os.path.join(PATH, 'index.csv') 64 | with open(index_path, 'a') as f: 65 | df.to_csv(f, index=False, header=False) 66 | 67 | 68 | if __name__ == '__main__': 69 | logging.basicConfig() 70 | for tif_name in read_source_files(SOURCE_PATH): 71 | logging.info('Processing %s', tif_name) 72 | process_dem(tif_name) 73 | -------------------------------------------------------------------------------- /source/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from typing import Optional, Sequence 4 | from ast import literal_eval 5 | import torch 6 | 7 | 8 | def read_index_row(index: pd.DataFrame, row: int): 9 | dem = torch.tensor(np.load(index.iloc[row][1])) 10 | influx = literal_eval(index.iloc[row][2]) 11 | outflux = literal_eval(index.iloc[row][3]) 12 | discharge = index.iloc[row][4] 13 | time_stamps = literal_eval(index.iloc[row][5]) 14 | return dem, influx, outflux, discharge, time_stamps 15 | 16 | 17 | def topography_difference(tile: np.ma.masked_array): 18 | return np.max(tile) - np.min(tile) 19 | 20 | 21 | def masked_values_percentage(tile: np.ma.MaskedArray): 22 | return np.sum(tile.mask) / tile.size 23 | 24 | 25 | def fix_missing_values(tile: np.ma.MaskedArray, 26 | masked_value_offset: Optional[float] = 30): 27 | tile.data[tile.mask] = masked_value_offset + np.max(tile) 28 | return tile 29 | 30 | 31 | def divide_to_tiles(image, tile_shape): 32 | im_rows, im_cols = image.shape 33 | im_rows -= (im_rows % tile_shape[0]) 34 | im_cols -= (im_cols % tile_shape[1]) 35 | image = image[:im_rows, :im_cols] 36 | 37 | tile_rows, tile_cols = tile_shape 38 | tiles = image.reshape(im_rows // tile_rows, tile_rows, im_cols // tile_cols, 39 | tile_cols) 40 | return tiles.transpose(0, 2, 1, 3).reshape(-1, tile_rows, tile_cols) 41 | 42 | 43 | def find_lowest_point(tile: np.ma.MaskedArray): 44 | rows, cols = tile.shape 45 | min_index = np.argmin( 46 | np.ma.concatenate([tile[:, 0], tile[:, -1], tile[0, :], 47 | tile[-1, :]])) 48 | # left, right, up, down 49 | if min_index < rows: 50 | return min_index, 0 51 | if min_index < 2 * rows: 52 | return min_index - rows, -1 53 | if min_index < 2 * rows + cols: 54 | return 0, min_index - 2 * rows 55 | else: 56 | return -1, min_index - (2 * rows + cols) 57 | -------------------------------------------------------------------------------- /trainer.py: -------------------------------------------------------------------------------- 1 | import time 2 | from typing import Optional, Tuple 3 | 4 | import torch 5 | import torch.distributed as dist 6 | import torch.nn as nn 7 | from absl import logging 8 | 9 | from hydraulics import boundary 10 | from hydraulics import simulation_utils as sim_utils 11 | from utils import meters 12 | from utils import model_utils 13 | from utils import tensorboard as tb 14 | from utils import visualization 15 | from utils import evaluation_viewer 16 | from utils import optimization as optim 17 | 18 | 19 | def forward(model: nn.Module, 20 | data_loader: torch.utils.data.DataLoader, args, epoch: int, 21 | training: bool, simulate: bool 22 | ) -> Tuple[float, Optional[torch.Tensor]]: 23 | criterion = args.criterion 24 | optimizer = args.optimizer if training else None 25 | regularization_loss = args.regularization 26 | if args.local_rank >= 0: 27 | loss_meter = meters.DistributedAverageMeter(args.local_rank) 28 | else: 29 | loss_meter = meters.AverageMeter() 30 | gradient_norm = meters.AverageMeter() 31 | weight_norm = meters.AverageMeter() 32 | time_meter = meters.AverageMeter() 33 | 34 | for iteration, sample in enumerate(data_loader): 35 | model.zero_grad() 36 | if args.boundary_type == boundary.BoundaryType.FLUX: 37 | fine_grid_z_n, influx, outflux, discharge, target_time, \ 38 | fine_h_n = sample 39 | coarse_bc = boundary.FluxBoundaryConditions( 40 | args.coarse_dx, args.coarse_n_x, influx, outflux, discharge) 41 | else: 42 | fine_grid_z_n, rain_fall, target_time, fine_h_n = sample 43 | rain_fall = rain_fall.cuda() 44 | coarse_bc = boundary.RainBoundaryConditions(rain_fall) 45 | if not simulate and args.local_rank >= 0: 46 | model.module.set_boundary_conditions(coarse_bc) 47 | else: 48 | model.set_boundary_conditions(coarse_bc) 49 | 50 | fine_grid_z_n = fine_grid_z_n.cuda() 51 | target_time = target_time.cuda() 52 | coarse_h_n = torch.zeros(fine_h_n.shape[0], fine_h_n.shape[1], 53 | args.coarse_n_x, args.coarse_n_x).cuda() 54 | coarse_q_x_n = torch.zeros(fine_h_n.shape[0], fine_h_n.shape[1], 55 | args.coarse_n_x, args.coarse_n_x - 1).cuda() 56 | coarse_q_y_n = torch.zeros(fine_h_n.shape[0], fine_h_n.shape[1], 57 | args.coarse_n_x - 1, args.coarse_n_x).cuda() 58 | start = time.time() 59 | coarse_grid_z_n = None 60 | coarse_grid_z_n, coarse_h_n, coarse_q_x_n, coarse_q_y_n = model( 61 | fine_grid_z_n, coarse_h_n, coarse_q_x_n, coarse_q_y_n, 62 | target_time, coarse_grid_z_n) 63 | true_coarse_z_n = sim_utils.downsample(fine_grid_z_n, args.scale_factor) 64 | true_coarse_h_n = sim_utils.downsample(fine_h_n, args.scale_factor) 65 | true_water_level = true_coarse_h_n.detach() 66 | loss = criterion(coarse_h_n, true_water_level.to(coarse_h_n.device)) 67 | if args.local_rank != 0: 68 | loss_meter.update(loss.item(), n=len(fine_grid_z_n)) 69 | if args.regularization_lambda > 0: 70 | loss += args.regularization_lambda * optim.lpf_regularization( 71 | coarse_grid_z_n, true_coarse_z_n, regularization_loss) 72 | if simulate: 73 | html_report = evaluation_viewer.export_evaluation_html( 74 | args.model, 75 | args.sample, 76 | loss.item(), 77 | coarse_grid_z_n, 78 | true_coarse_z_n, 79 | coarse_h_n, 80 | true_water_level) 81 | with open(args.log_dir + '/evaluation.html', 'w') as f: 82 | f.write(html_report) 83 | html_movie = visualization.render_water_simulation_movie( 84 | model.simulation_h_n, 85 | coarse_grid_z_n.clone().detach().squeeze().cpu().numpy(), 86 | model.simulation_t) 87 | with open(args.log_dir + '/solver_solution.html', 'w') as f: 88 | f.write(html_movie) 89 | return loss_meter.average 90 | if training and loss.requires_grad: 91 | loss.backward() 92 | if args.local_rank <= 0: 93 | gradient_norm.update(model_utils.calc_gradient_norm(model)) 94 | weight_norm.update(model_utils.calc_weight_norm(model)) 95 | end = time.time() 96 | time_meter.update(end - start) 97 | if training and loss.requires_grad: 98 | optimizer.step() 99 | if args.local_rank >= 0: 100 | dist.reduce(loss, 0) 101 | if args.local_rank == 0: 102 | loss /= args.world_size 103 | loss_meter.update(loss.item(), n=len(fine_grid_z_n)) 104 | if args.local_rank <= 0 and iteration % 10 == 0: 105 | logging.info( 106 | '{phase} - Epoch: [{0}][{1}/{2}]\t' 107 | 'Time {time.val:.3f} ({time.average:.3f})\t' 108 | 'Loss {loss.val:.4f} ({loss.average:.4f})\t' 109 | 'Grad {grad.val:.4f} ({grad.average:.4f})\t'.format( 110 | epoch, iteration, len(data_loader), 111 | phase='TRAINING' if training else 'EVALUATING', 112 | time=time_meter, loss=loss_meter, grad=gradient_norm)) 113 | if args.local_rank <= 0: 114 | if training and loss.requires_grad: 115 | tb.log_scalars(epoch * len(data_loader) + iteration, 116 | gradient_norm=gradient_norm.average, 117 | weight_norm=weight_norm.average) 118 | if training: 119 | tb.log_scalars(epoch * len(data_loader) + iteration, 120 | train_loss_iteration=loss) 121 | return loss_meter.average 122 | 123 | 124 | def train(epoch: int, model: nn.Module, 125 | data_loader: torch.utils.data.DataLoader, args): 126 | # switch to train mode 127 | model.train() 128 | return forward(model, data_loader, args, epoch, True, False) 129 | 130 | 131 | def validate(epoch: int, model: nn.Module, 132 | data_loader: torch.utils.data.DataLoader, args): 133 | # switch to evaluate mode 134 | model.eval() 135 | with torch.no_grad(): 136 | return forward(model, data_loader, args, epoch, False, False) 137 | 138 | 139 | def simulate(model: nn.Module, data_loader: torch.utils.data.DataLoader, args): 140 | model.eval() 141 | with torch.no_grad(): 142 | return forward(model, data_loader, args, 0, False, True) 143 | -------------------------------------------------------------------------------- /utils/__pycache__/tensorboard.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tech-submissions/physics-aware-downsampling/c16417712f0e081db34e783968ce54fb9ee44479/utils/__pycache__/tensorboard.cpython-38.pyc -------------------------------------------------------------------------------- /utils/evaluation_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Evaluation Viewer 5 | 6 | 7 | 8 | 9 | 20 | 21 | 22 |
23 |

{{title}}

24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | {% for sample in samples %} 41 | 42 | 43 | 44 | 47 | 50 | 53 | 56 | 60 | 61 | {% endfor %} 62 | 63 |
Sample IDLossModel DEMBaseline DEMModel - Ground Truth Difference MapModel SolutionGround Truth Coarse 35 | Solution 36 |
{{ sample.sample_id }}{{ '%2.4f' % sample.loss }} 45 | Model DEM 46 | 48 | Baseline DEM 49 | 51 | Model-GT Diff 52 | 54 | Model Solution 55 | 57 | Ground Truth Coarse Solution 59 |
64 | 65 |
66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /utils/evaluation_viewer.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import sys 3 | from dataclasses import dataclass 4 | 5 | import cv2 6 | import jinja2 7 | import numpy as np 8 | import torch 9 | from matplotlib import figure as plt_fig 10 | from matplotlib.backends import backend_agg 11 | 12 | from utils import visualization as viz 13 | 14 | 15 | @dataclass 16 | class Sample: 17 | """Class for storing sample outputs.""" 18 | sample_id: int 19 | loss: float 20 | model_dem: str 21 | baseline_dem: str 22 | model_gt_difference: str 23 | model_solution: str 24 | baseline_solution: str 25 | 26 | 27 | def rgb_to_png_coded_string(rgb_image: np.ndarray) -> str: 28 | """Converts RGB numpy array to png decoded string.""" 29 | scaled_rgb_image = (np.clip(rgb_image, 0.0, 1.0) * 255).astype(np.uint8) 30 | success, png_image = cv2.imencode('.png', scaled_rgb_image[:, :, ::-1]) 31 | if not success: 32 | raise ValueError('Error encoding PNG image') 33 | return base64.b64encode(png_image.tostring()).decode('utf8') 34 | 35 | 36 | def plt_figure_to_rgb(figure: plt_fig.Figure) -> np.ndarray: 37 | canvas = backend_agg.FigureCanvasAgg(figure) 38 | width, height = figure.get_size_inches() * figure.get_dpi() 39 | canvas.draw() # draw the canvas, cache the renderer 40 | rgb_image = np.fromstring(canvas.tostring_rgb(), dtype='uint8').reshape( 41 | int(height), int(width), 3) 42 | return rgb_image / 255 43 | 44 | 45 | def export_evaluation_html(model: str, sample_id: int, loss: float, 46 | predicted_dem: torch.Tensor, 47 | baseline_dem: torch.Tensor, 48 | predicted_state: torch.Tensor, 49 | true_state: torch.Tensor) -> str: 50 | baseline_dem = baseline_dem.clone().detach().squeeze().cpu().numpy() 51 | predicted_dem = predicted_dem.clone().detach().squeeze().cpu().numpy() 52 | true_state = true_state.clone().detach().squeeze().cpu().numpy() 53 | predicted_state = predicted_state.clone().detach().squeeze().cpu().numpy() 54 | vmax = max(np.max(true_state), np.max(predicted_state)) 55 | vmin = min(np.min(true_state), np.min(predicted_state)) 56 | diff_figure = viz.plot_difference_map(predicted_state, true_state, 'model', 57 | 'true') 58 | true_state = viz.render_hillshade_water_image( 59 | baseline_dem, true_state, vmin, vmax) 60 | predicted_state = viz.render_hillshade_water_image( 61 | predicted_dem, predicted_state, vmin, vmax) 62 | vmax = max(np.max(baseline_dem), np.max(predicted_dem)) 63 | vmin = min(np.min(baseline_dem), np.min(predicted_dem)) 64 | baseline_dem_figure = viz.plot_dem(baseline_dem, colorbar=True, vmin=vmin, 65 | vmax=vmax) 66 | predicted_dem_figure = viz.plot_dem(predicted_dem, colorbar=True, vmin=vmin, 67 | vmax=vmax) 68 | baseline_dem_rgb = plt_figure_to_rgb(baseline_dem_figure) 69 | predicted_dem_rgb = plt_figure_to_rgb(predicted_dem_figure) 70 | predicted_true_diff = plt_figure_to_rgb(diff_figure) 71 | samples = [Sample(sample_id=sample_id, 72 | loss=loss, 73 | model_dem=rgb_to_png_coded_string(predicted_dem_rgb), 74 | baseline_dem=rgb_to_png_coded_string(baseline_dem_rgb), 75 | model_solution=rgb_to_png_coded_string(predicted_state), 76 | baseline_solution=rgb_to_png_coded_string(true_state), 77 | model_gt_difference=rgb_to_png_coded_string( 78 | predicted_true_diff))] 79 | resource_loader = jinja2.FileSystemLoader(searchpath="./") 80 | jinja_env = jinja2.Environment( 81 | loader=resource_loader, 82 | autoescape=jinja2.select_autoescape(['html', 'xml']) 83 | ) 84 | template = jinja_env.get_template('utils/evaluation_template.html') 85 | model_str = 'Model' if model else 'Baseline' 86 | 87 | return template.render(title=f'Sample Number {sample_id} - {model_str}', 88 | samples=samples, command=sys.argv) 89 | -------------------------------------------------------------------------------- /utils/meters.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | class AverageMeter(object): 5 | """Computes and stores the average and current value""" 6 | 7 | def __init__(self): 8 | self.reset() 9 | 10 | def reset(self): 11 | self.val = 0 12 | self.sum = 0 13 | self.count = 0 14 | 15 | def update(self, val, n=1): 16 | self.val = val 17 | self.sum += val * n 18 | self.count += n 19 | 20 | @property 21 | def average(self): 22 | return self.sum / self.count if self.count > 0 else 0 23 | 24 | 25 | class DistributedAverageMeter(object): 26 | """Computes and stores the average and current value""" 27 | 28 | def __init__(self, local_rank): 29 | self.device = local_rank 30 | self.reset() 31 | 32 | def reset(self): 33 | self.value = torch.zeros(1, device=self.device) 34 | self.sum = self.value 35 | self.count = 0 36 | self.average_value = self.value 37 | 38 | def update(self, val, n=1): 39 | self.value = torch.tensor(val, device=self.device) 40 | self.sum += self.value * n 41 | self.count += n 42 | self.average_value = self.sum / self.count 43 | 44 | @property 45 | def average(self): 46 | return self.average_value.item() 47 | 48 | @property 49 | def val(self): 50 | return self.value.item() 51 | -------------------------------------------------------------------------------- /utils/model_utils.py: -------------------------------------------------------------------------------- 1 | # Lint as: python3 2 | import logging 3 | from typing import Optional, Mapping, Text 4 | 5 | import torch 6 | import torch.nn as nn 7 | 8 | 9 | def get_model_gradients(model: nn.Module) -> Mapping[Text, torch.Tensor]: 10 | gradients = {} 11 | for name, weight in model.named_parameters(): 12 | gradients[name] = weight.grad.data.clone() 13 | return gradients 14 | 15 | 16 | def calc_gradient_norm(model: nn.Module, p: Optional[int] = 2) -> float: 17 | """Calculates the gradient p-norm of the provided model.""" 18 | total_norm = 0 19 | for name, param in model.named_parameters(): 20 | if param.grad is not None: 21 | param_norm = param.grad.norm(p) 22 | total_norm += param_norm.item() ** p 23 | else: 24 | logging.warning( 25 | 'parameter %s in model does not have gradient', name) 26 | return total_norm ** (1. / p) 27 | 28 | 29 | def calc_weight_norm(model: nn.Module, p: Optional[int] = 2) -> float: 30 | """Calculates the weights p-norm of the provided model.""" 31 | total_norm = 0 32 | for name, param in model.named_parameters(): 33 | if param.requires_grad: 34 | param_norm = param.norm(p) 35 | total_norm += param_norm.item() ** p 36 | else: 37 | logging.warning( 38 | 'parameter %s in model does require gradient', name) 39 | return total_norm ** (1. / p) 40 | -------------------------------------------------------------------------------- /utils/optimization.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | 6 | class InundationLoss(nn.Module): 7 | def __init__(self, threshold: float = 0.5, reduction: str = 'mean'): 8 | super(InundationLoss, self).__init__() 9 | self.reduction = reduction 10 | self.threshold = threshold 11 | 12 | def forward(self, input: torch.Tensor, 13 | target: torch.Tensor) -> torch.Tensor: 14 | difference = torch.abs(input - target) 15 | loss = torch.as_tensor((difference > self.threshold), dtype=torch.float) 16 | if self.reduction == 'mean': 17 | loss = torch.mean(loss) 18 | return loss 19 | 20 | 21 | def scale_regularization(output: torch.Tensor, target: torch.Tensor, criterion): 22 | """Max - Min regularization.""" 23 | output_max_value = torch.max(output) 24 | output_min_value = torch.min(output) 25 | target_max_value = torch.max(target) 26 | target_min_value = torch.min(target) 27 | return criterion(output_max_value - output_min_value, 28 | target_max_value - target_min_value) 29 | 30 | 31 | def lpf_regularization(output: torch.Tensor, target: torch.Tensor, criterion): 32 | """Low pass filter similarity regulrization.""" 33 | low_pass_filter = torch.ones((1, 1, 2, 2)) / 4 34 | low_pass_filter = low_pass_filter.to(output.device) 35 | filtered_output = F.conv2d(F.pad(output, (1, 0, 1, 0), mode='replicate'), 36 | low_pass_filter) 37 | return criterion(filtered_output, target.to(output.device)) 38 | -------------------------------------------------------------------------------- /utils/tensorboard.py: -------------------------------------------------------------------------------- 1 | # Lint as: python3 2 | import os 3 | from datetime import datetime 4 | from typing import Optional, Mapping, Any, Sequence 5 | 6 | import matplotlib.pyplot as plt 7 | import torch 8 | import torch.utils.tensorboard as tensorboard 9 | 10 | 11 | class TensorBoard(object): 12 | 13 | def __init__(self): 14 | self.log_dir = None 15 | self.writer = None 16 | self.step = 0 17 | self.hparams = {} 18 | 19 | @property 20 | def initialized(self): 21 | return bool(self.log_dir) 22 | 23 | 24 | _root = TensorBoard() 25 | 26 | 27 | def init(log_dir: Optional[str] = None, 28 | comment: Optional[str] = '') -> None: 29 | """Creates a TensorBoard logger that will write events to the event file. 30 | 31 | Args: 32 | log_dir: Save directory location. Default is 33 | runs/**CURRENT_DATETIME**. 34 | comment: Comment log_dir suffix appended to the default 35 | ``log_dir``. If ``log_dir`` is assigned, this argument has no effect. 36 | """ 37 | if not log_dir: 38 | current_time = datetime.now().strftime('%d-%m-%Y_%H-%M-%S') 39 | log_dir = os.path.join('runs', current_time + '_' + comment) 40 | if not _root.initialized: 41 | _root.log_dir = log_dir 42 | _root.writer = tensorboard.SummaryWriter(log_dir=log_dir) 43 | 44 | 45 | def get_log_dir(): 46 | if not _root.initialized: 47 | init() 48 | return _root.log_dir 49 | 50 | 51 | def close(): 52 | if _root.initialized: 53 | _root.writer.close() 54 | 55 | 56 | def update_step(step: int): 57 | if not _root.initialized: 58 | init() 59 | _root.step = step 60 | 61 | 62 | def log_scalars(step: Optional[int] = None, write_hparams: bool = False, 63 | **kwargs): 64 | if not _root.initialized: 65 | init() 66 | step = step if step else _root.step 67 | for k, v in kwargs.items(): 68 | _root.writer.add_scalar(k, v, step) 69 | if write_hparams: 70 | _root.writer.add_hparams(_root.hparams, kwargs, run_name='hparams') 71 | 72 | 73 | def log_historgrams(step: Optional[int] = None, **kwargs): 74 | if not _root.initialized: 75 | init() 76 | step = step if step else _root.step 77 | for k, v in kwargs.items(): 78 | _root.writer.add_histogram(k, v, step) 79 | 80 | 81 | def log_text(step: Optional[int] = None, **kwargs): 82 | if not _root.initialized: 83 | init() 84 | step = step if step else _root.step 85 | for tag, text in kwargs.items(): 86 | _root.writer.add_text(tag, text, step) 87 | 88 | 89 | def log_images(step: Optional[int], tag: str, images: torch.Tensor, **kwargs): 90 | if not _root.initialized: 91 | init() 92 | step = step if step else _root.step 93 | _root.writer.add_images(tag, images, step, **kwargs) 94 | 95 | 96 | def log_figure(step: Optional[int], **kwargs): 97 | if not _root.initialized: 98 | init() 99 | step = step if step else _root.step 100 | for tag, figure in kwargs.items(): 101 | _root.writer.add_figure(tag, figure, step) 102 | 103 | 104 | def register_hyper_parameter(key: str, value: Any): 105 | if not _root.initialized: 106 | init() 107 | _root.hparams[key] = value 108 | 109 | 110 | def log_hyper_parameters(hyper_param: Optional[Mapping[str, Any]] = None): 111 | def get_writeable_type(value: Any): 112 | valid_types = {bool, int, float, torch.Tensor, str} 113 | if type(value) in valid_types: 114 | return value 115 | elif issubclass(type(value), (torch.nn.modules.loss._Loss, 116 | torch.optim.Optimizer)): 117 | return type(value).__name__ 118 | else: 119 | return str(value) 120 | 121 | if not _root.initialized: 122 | init() 123 | if hyper_param is not None: 124 | hyper_param = {k: get_writeable_type(v) for k, v in hyper_param.items()} 125 | _root.hparams.update(hyper_param) 126 | 127 | 128 | def log_graph(step: Optional[int], tag: str, x_axis: torch.Tensor, 129 | data: Sequence[torch.Tensor], **kwargs): 130 | if not _root.initialized: 131 | init() 132 | step = step if step else _root.step 133 | figure = plt.figure() 134 | legend = kwargs.pop('legend') if 'legend' in kwargs else None 135 | axvline = kwargs.pop('axvline') if 'axvline' in kwargs else None 136 | for line in data: 137 | plt.plot(x_axis, line, **kwargs) 138 | if legend: 139 | plt.legend(legend) 140 | if axvline: 141 | plt.axvline(x_axis[axvline], color='red', linestyle='dashed') 142 | _root.writer.add_figure(tag, figure, step) 143 | 144 | 145 | def log_model(model: torch.nn.Module, input_to_model): 146 | """Add graph data to summary. 147 | 148 | Args: 149 | model (torch.nn.Module): Model to draw. 150 | input_to_model (torch.Tensor or list of torch.Tensor): A variable or a 151 | tuple of variables to be fed. 152 | """ 153 | if not _root.initialized: 154 | init() 155 | _root.writer.add_graph(model, input_to_model) 156 | -------------------------------------------------------------------------------- /utils/visualization.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import List, Optional 3 | 4 | import matplotlib 5 | import matplotlib.animation as animation 6 | import matplotlib.cm 7 | import matplotlib.pyplot as plt 8 | import numpy as np 9 | import torch 10 | from matplotlib.colors import LightSource 11 | 12 | 13 | def render_hillshade_water_image(z: np.ndarray, h: np.ndarray, 14 | vmin: Optional[float] = None, 15 | vmax: Optional[float] = None): 16 | norm = matplotlib.colors.Normalize(vmin, vmax) 17 | mappable = matplotlib.cm.ScalarMappable(norm, 'Blues') 18 | color_h = mappable.to_rgba(h) 19 | alpha = np.ones_like(h) * 0.85 20 | alpha = np.dstack([alpha] * 3) 21 | color_h = color_h[:, :, :3] 22 | 23 | # Shade from the northwest, with the sun 45 degrees from horizontal 24 | ls = LightSource(azdeg=315, altdeg=45) 25 | overlay = ls.hillshade(z, vert_exag=1, dx=1, dy=1) 26 | norm = matplotlib.colors.Normalize(np.min(overlay), np.max(overlay)) 27 | mappable = matplotlib.cm.ScalarMappable(norm, 'gray') 28 | overlay = mappable.to_rgba(overlay) 29 | overlay_image = overlay[:, :, :3] 30 | 31 | return (1 - alpha) * overlay_image + alpha * color_h 32 | 33 | 34 | def render_hillshade_image(z: np.ndarray, vmin: Optional[float] = None, 35 | vmax: Optional[float] = None): 36 | # Shade from the northwest, with the sun 45 degrees from horizontal 37 | ls = LightSource(azdeg=315, altdeg=45) 38 | rgb = ls.shade(z, cmap=plt.cm.gist_earth, blend_mode='overlay', 39 | vert_exag=1, dx=1, dy=1, vmin=vmin, vmax=vmax) 40 | return rgb[:, :, :3] 41 | 42 | 43 | def render_water_simulation_movie(state_list: List[np.ndarray], dem: np.ndarray, 44 | time_list: List[float]): 45 | matplotlib.rcParams['animation.embed_limit'] = 1000 46 | fig, ax = plt.subplots(1, 1) 47 | dem = np.squeeze(dem) 48 | max_height = -np.inf 49 | min_height = np.inf 50 | for value in state_list: 51 | max_height = max_height if max_height > np.max(value) else np.max(value) 52 | min_height = min_height if min_height < np.min(value) else np.min(value) 53 | vmin = 0 54 | logging.info(f'render water range - [{min_height:.3f},{max_height:.3f}]') 55 | image = plt.imshow( 56 | render_hillshade_water_image(dem, state_list[0], vmin=vmin, 57 | vmax=max_height)) 58 | plt.axis('off') 59 | 60 | def update_eta(num): 61 | ax.set_title(r'Water Surface Height $z+h$ at t = {:.2f} hours'.format( 62 | time_list[num] / 3600), fontname="serif", fontsize=16) 63 | image.set_data(render_hillshade_water_image(dem, state_list[num], 64 | vmin=vmin, vmax=max_height)) 65 | return image 66 | 67 | anim = animation.FuncAnimation(fig, update_eta, frames=len(state_list), 68 | interval=10, blit=False) 69 | html_movie = anim.to_jshtml(fps=16) 70 | plt.close() 71 | return html_movie 72 | 73 | 74 | def render_dem_evolution_movie(dem_list: List[np.ndarray]): 75 | fig, ax = plt.subplots(1, 1) 76 | image = plt.imshow(dem_list[0]) 77 | plt.colorbar() 78 | plt.axis('off') 79 | 80 | def update_eta(num): 81 | ax.set_title(f'DEM at step {num}', fontname="serif", fontsize=16) 82 | image.set_data(dem_list[num]) 83 | plt.clim(np.min(dem_list[num]), np.max(dem_list[num])) 84 | return image 85 | 86 | anim = animation.FuncAnimation(fig, update_eta, frames=len(dem_list), 87 | interval=10, blit=False) 88 | html_movie = anim.to_jshtml(fps=16) 89 | plt.close() 90 | return html_movie 91 | 92 | 93 | def plot_dem(dem: np.ndarray, colormap: str = plt.cm.gist_earth, 94 | colorbar: Optional[bool] = False, vmin: Optional[float] = None, 95 | vmax: Optional[float] = None): 96 | figure = plt.figure() 97 | if not vmax: 98 | vmax = np.max(dem) 99 | if not vmin: 100 | vmin = np.min(dem) 101 | image = plt.imshow(dem, cmap=colormap, vmax=vmax, vmin=vmin) 102 | if colorbar: 103 | plt.colorbar(image) 104 | plt.xticks([]) 105 | plt.yticks([]) 106 | plt.grid(False) 107 | plt.tight_layout(pad=0) 108 | return figure 109 | 110 | 111 | def plot_difference_map(state_1: np.ndarray, state_2: np.ndarray, 112 | label_1: str, label_2: str, 113 | vmin: Optional[float] = None, 114 | vmax: Optional[float] = None): 115 | state_1 = state_1.squeeze() 116 | state_2 = state_2.squeeze() 117 | if not vmax: 118 | vmax = np.max(np.abs(state_2 - state_1)) 119 | if not vmin: 120 | vmin = -vmax 121 | figure = plt.figure() 122 | image = plt.imshow(state_1 - state_2, cmap='coolwarm', vmin=vmin, vmax=vmax) 123 | plt.title(f'Water Difference Map - Red:{label_1}, Blue:{label_2}') 124 | plt.colorbar(image) 125 | plt.xticks([]) 126 | plt.yticks([]) 127 | plt.grid(False) 128 | plt.tight_layout(pad=0) 129 | plt.close() 130 | return figure 131 | 132 | 133 | def plot_loss_histogram(loss_vector: torch.Tensor, path: str, bins: int = 20, 134 | min: float = 0, max: float = 0): 135 | bars = torch.histc(loss_vector, bins=bins, min=min, max=max) 136 | bars /= torch.sum(bars) 137 | bin_edges = torch.linspace(min, max, steps=bins) 138 | plt.figure(figsize=(12, 8)) 139 | plt.bar(bin_edges, bars, width=0.0004) 140 | plt.ylim(0, 1) 141 | plt.tight_layout() 142 | plt.savefig(path + f'/loss_histogram.png', bbox_inches='tight') 143 | plt.close() 144 | --------------------------------------------------------------------------------