├── 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 |
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 |
--------------------------------------------------------------------------------