Skip to content

Commit e326b29

Browse files
author
Matt Garthwaite
authored
Merge pull request #283 from GeoscienceAustralia/develop
Release 0.4.3
2 parents f914bf5 + 313483f commit e326b29

File tree

127 files changed

+2048
-1690
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+2048
-1690
lines changed

.travis.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,12 @@ install:
5858

5959

6060
script:
61-
- travis_wait 30 pytest --cov-config=.coveragerc --cov-report term-missing:skip-covered --cov=pyrate tests/
62-
61+
- pytest tests/ -m "slow"
62+
- pytest --cov-config=.coveragerc --cov-report term-missing:skip-covered --cov=pyrate tests/ -m "not slow"
6363

6464
after_success:
6565
- codecov
6666

67-
6867
before_deploy:
6968
- cd docs && make html
7069

docs/conf.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
source_suffix = ['.rst', '.md']
4040
# source_suffix = '.rst'
4141

42-
# The master toctree document.
43-
master_doc = 'index'
42+
# The main toctree document.
43+
main_doc = 'index'
4444

4545
# General information about the project.
4646
project = 'PyRate'
@@ -137,7 +137,7 @@
137137
# (source start file, target name, title,
138138
# author, documentclass [howto, manual, or own class]).
139139
latex_documents = [
140-
(master_doc, 'PyRate.tex', 'PyRate Documentation',
140+
(main_doc, 'PyRate.tex', 'PyRate Documentation',
141141
'Geoscience Australia InSAR team', 'manual'),
142142
]
143143

@@ -147,7 +147,7 @@
147147
# One entry per manual page. List of tuples
148148
# (source start file, name, description, authors, manual section).
149149
man_pages = [
150-
(master_doc, 'pyrate', 'PyRate Documentation',
150+
(main_doc, 'pyrate', 'PyRate Documentation',
151151
[author], 1)
152152
]
153153

@@ -158,7 +158,7 @@
158158
# (source start file, target name, title, author,
159159
# dir menu entry, description, category)
160160
texinfo_documents = [
161-
(master_doc, 'PyRate', 'PyRate Documentation',
161+
(main_doc, 'PyRate', 'PyRate Documentation',
162162
author, 'PyRate', 'One line description of project.',
163163
'Miscellaneous'),
164164
]

docs/contributing.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,17 @@ Ready to contribute? Here's how to set up `PyRate` for local development.
8080

8181
Now you can make your changes locally.
8282

83-
4. When you have finished making changes, check that your changes pass style and unit
83+
4. When you have finished making changes, check that your changes pass against unit
8484
tests. A suite of tests have been developed for use in testing `PyRate` functionality
8585
and for further code development. The tests use `pytest <http://doc.pytest.org/en/latest/>`__
86-
and can be found in the ``PyRate/tests/`` directory. A small test dataset used by the test suite is included in the repository in the ``PyRate/tests/test_data/small_test`` directory.
86+
and can be found in the ``PyRate/tests/`` directory. A small test dataset used by
87+
the test suite is included in the repository in the ``PyRate/tests/test_data/small_test`` directory.
8788

8889
::
8990

9091
cd ~/PyRate
91-
pytest tests/
92-
pip install tox
93-
tox
92+
# 'not slow' avoids running those tests marked as 'slow'
93+
pytest tests/ -m "not slow"
9494

9595
5. If the tests pass, commit your changes and push your branch to GitHub:
9696

docs/history.rst

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,33 @@
33
Release History
44
===============
55

6+
0.4.3 (2020-07-28)
7+
------------------
8+
Added
9+
+++++
10+
- Ability to define the order of steps in the ``process`` workflow
11+
(default order unchanged).
12+
13+
Fixed
14+
+++++
15+
16+
Changed
17+
+++++++
18+
- ``prepifg`` output interferograms are saved as read-only files.
19+
- ``process`` makes a writable copy of the ``prepifg`` output data
20+
at the beginning of each run.
21+
- The selected reference pixel is saved to disk and re-used on subsequent
22+
``process`` runs.
23+
- Saving of incremental time series (``tsincr``) products is optional,
24+
controlled by the ``savetsincr`` configuration parameter (default is on).
25+
26+
Removed
27+
+++++++
28+
- Removed obsolete InSAR terminology from code, docs and test data
29+
(changed to `first` and `second` images).
30+
- Stopped using ``unittest`` unit test framework in favour of exclusively
31+
using ``pytest``.
32+
633
0.4.2 (2020-06-26)
734
------------------
835
Added
@@ -16,12 +43,15 @@ Added
1643
lat/lon and x/y values; mean and standard deviation of reference window samples.
1744
- Quicklook PNG and KML files are generated for the ``Stack Rate`` error map by default.
1845

46+
Fixed
47+
+++++
48+
- Ensure ``prepifg`` treats input data files as `read only`.
49+
- Fix the way that the reference phase is subtracted from interferograms
50+
during ``process`` step.
51+
- Manual entry of ``refx/y`` converted to type ``int``.
52+
1953
Changed
2054
+++++++
21-
- Bugfix: ensure ``prepifg`` treats input data files as `read only`.
22-
- Bugfix: fix the way that the reference phase is subtracted from interferograms
23-
during ``process`` step.
24-
- Bugfix: manual entry of ``refx/y`` converted to type ``int``.
2555
- User supplies latitude and longitude values when specifying a reference pixel in
2656
the config file. Pixel x/y values are calculated and used internally.
2757
- Move ``Stack Rate`` masking to a standalone function ``pyrate.core.stack.mask_rate``,
@@ -55,15 +85,18 @@ Added
5585
- Improvements to the test suite, including systems-wide tests.
5686
- Improved logging.
5787

88+
Fixed
89+
+++++
90+
- Fixed bug in resampling/multi-looking when coherence masking is used.
91+
This bugfix will result in significantly fewer ``nan`` pixels in the outputs.
92+
- Fixed a bug in how NaNs are handled during coherence masking and multi-looking.
93+
Output rasters will contain ``nan`` as the nodata value.
94+
5895
Changed
5996
+++++++
6097
- ``Linear Rate`` algorithm has been renamed ``Stack Rate``.
6198
- User supplies full paths to input files in respective file lists.
6299
- All files generated by `PyRate` saved to user-defined ``outdir`` directory.
63-
- Fixed a bug in how NaNs are handled during coherence masking and multi-looking.
64-
Output rasters will contain ``nan`` as the nodata value.
65-
- Fixed bug in resampling/multi-looking when coherence masking is used.
66-
This bugfix will result in significantly fewer ``nan`` pixels in the outputs.
67100
- Renamed ``slcfilelist`` parameter to ``hdrfilelist``.
68101
- Log files are generated in the ``outdir`` and every `PyRate` step produces independent log files.
69102

@@ -129,7 +162,7 @@ Changed
129162
+++++++
130163
- Requirements now managed by ``requirements.txt`` file, parsed by ``setup.py``.
131164
- Requirements now split across base ``requirements.txt`` and separate files
132-
for dev (``requirements-dev.txt``) and testing ('requirements-test.txt').
165+
for dev (``requirements-dev.txt``) and testing (``requirements-test.txt``).
133166
- Moved default config files to top level source directory.
134167
- Pinned Python dependencies to specific versions.
135168
- Travis build now installs GDAL from apt.

input_parameters.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ tscal: 1
1818
# Optional save of numpy array files for output products (MERGE)
1919
savenpy: 0
2020

21+
# Optional save of incremental time series products (PROCESS/MERGE)
22+
savetsincr: 0
23+
2124
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2225
# Multi-threading parameters used by stacking/timeseries/prepifg
2326
# gamma prepifg runs in parallel on a single machine if parallel = 1

pyrate/configuration.py

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@
1919
"""
2020
from configparser import ConfigParser
2121
from pathlib import Path, PurePath
22+
from typing import Union
2223
from pyrate.constants import NO_OF_PARALLEL_PROCESSES
2324
from pyrate.default_parameters import PYRATE_DEFAULT_CONFIGURATION
2425
from pyrate.core.algorithm import factorise_integer
2526
from pyrate.core.shared import extract_epochs_from_filename, InputTypes
26-
from pyrate.core.config import parse_namelist, ConfigException
27+
from pyrate.core.config import parse_namelist, ConfigException, ORB_ERROR_DIR, TEMP_MLOOKED_DIR
2728

2829

2930
def set_parameter_value(data_type, input_value, default_value, required, input_name):
@@ -78,28 +79,38 @@ def validate_file_list_values(file_list, no_of_epochs):
7879

7980
class MultiplePaths:
8081
def __init__(self, out_dir: str, file_name: str, ifglksx: int = 1, ifgcropopt: int = 1,
81-
input_type: InputTypes = InputTypes.IFG):
82+
input_type: InputTypes = InputTypes.IFG, tempdir: Union[Path, str] = TEMP_MLOOKED_DIR):
8283
self.input_type = input_type
8384
b = Path(file_name)
8485
if b.suffix == ".tif":
8586
self.unwrapped_path = None
8687
converted_path = b # original file
8788
self.sampled_path = Path(out_dir).joinpath(
88-
b.stem + '_' + str(ifglksx) + "rlks_" + str(ifgcropopt) + "cr.tif").as_posix()
89+
b.stem + '_' + str(ifglksx) + "rlks_" + str(ifgcropopt) + "cr.tif")
8990
else:
9091
self.unwrapped_path = b.as_posix()
9192
converted_path = Path(out_dir).joinpath(
9293
b.stem.split('.')[0] + '_' + b.suffix[1:] + input_type.value).with_suffix('.tif')
9394
self.sampled_path = converted_path.with_name(
94-
converted_path.stem + '_' + str(ifglksx) + "rlks_" + str(ifgcropopt) + "cr.tif").as_posix()
95+
converted_path.stem + '_' + str(ifglksx) + "rlks_" + str(ifgcropopt) + "cr.tif")
96+
if not isinstance(tempdir, Path):
97+
tempdir = Path(out_dir).joinpath(tempdir)
98+
self.tmp_sampled_path = tempdir.joinpath(self.sampled_path.name).as_posix()
99+
self.sampled_path = self.sampled_path.as_posix()
95100
self.converted_path = converted_path.as_posix()
96101

97102
def __str__(self): # pragma: no cover
98-
return"""
99-
unwrapped_path = """ + self.unwrapped_path+"""
103+
st = ""
104+
if self.unwrapped_path is not None:
105+
st += """\nunwrapped_path = """ + self.unwrapped_path
106+
else:
107+
st += """\nunwrapped_path = None"""
108+
st += """
100109
converted_path = """ + self.converted_path+"""
101110
sampled_path = """ + self.sampled_path+"""
111+
tmp_sampled_path = """ + self.tmp_sampled_path+"""
102112
"""
113+
return st
103114

104115

105116
class Configuration:
@@ -112,12 +123,26 @@ def __init__(self, config_file_path):
112123
with open(config_file_path) as stream:
113124
parser.read_string("[root]\n" + stream.read())
114125

115-
for key, value in parser._sections["root"].items():
126+
for key, value in parser["root"].items():
116127
self.__dict__[key] = value
117128

118129
# make output path, if not provided will error
119130
Path(self.outdir).mkdir(exist_ok=True, parents=True)
120131

132+
# custom process sequence if 'process' section is provided in config
133+
if 'process' in parser and 'steps' in parser['process']:
134+
self.__dict__['process'] = list(filter(None, parser['process'].get('steps').splitlines()))
135+
else:
136+
self.__dict__['process'] = [
137+
'orbfit',
138+
'refphase',
139+
'mst',
140+
'apscorrect',
141+
'maxvar',
142+
'timeseries',
143+
'stack'
144+
]
145+
121146
# Validate required parameters exist.
122147

123148
required = {k for k, v in PYRATE_DEFAULT_CONFIGURATION.items() if v['Required']}
@@ -162,6 +187,14 @@ def __init__(self, config_file_path):
162187

163188
self.tmpdir.mkdir(parents=True, exist_ok=True)
164189

190+
# create orbfit error dir
191+
self.orb_error_dir = Path(self.outdir).joinpath(ORB_ERROR_DIR)
192+
self.orb_error_dir.mkdir(parents=True, exist_ok=True)
193+
194+
# create temp multilooked files dir
195+
self.temp_mlooked_dir = Path(self.outdir).joinpath(TEMP_MLOOKED_DIR)
196+
self.temp_mlooked_dir.mkdir(parents=True, exist_ok=True)
197+
165198
# var no longer used
166199
self.APS_ELEVATION_EXT = None
167200
self.APS_INCIDENCE_EXT = None
@@ -194,4 +227,13 @@ def __init__(self, config_file_path):
194227
def __get_files_from_attr(self, attr, input_type=InputTypes.IFG):
195228
val = self.__getattribute__(attr)
196229
files = parse_namelist(val)
197-
return [MultiplePaths(self.outdir, p, self.ifglksx, self.ifgcropopt, input_type=input_type) for p in files]
230+
return [
231+
MultiplePaths(self.outdir, p, self.ifglksx, self.ifgcropopt, input_type=input_type,
232+
tempdir=self.temp_mlooked_dir) for p in files
233+
]
234+
235+
236+
def write_config_parser_file(conf: ConfigParser, output_conf_file: Union[str, Path]):
237+
"""replacement function for write_config_file which uses dict instead of a ConfigParser instance"""
238+
with open(output_conf_file, 'w') as configfile:
239+
conf.write(configfile)

pyrate/core/algorithm.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def unit_vector(incidence, azimuth):
125125

126126
def ifg_date_lookup(ifgs, date_pair):
127127
"""
128-
Returns the Interferogram which has the master and slave dates given
128+
Returns the Interferogram which has the first and second dates given
129129
in 'date_pair'.
130130
131131
:param list ifgs: List of interferogram objects to search
@@ -136,10 +136,10 @@ def ifg_date_lookup(ifgs, date_pair):
136136
"""
137137

138138
if len(date_pair) != 2:
139-
msg = "Need (datetime.date, datetime.date) master/slave pair"
139+
msg = "Need (datetime.date, datetime.date) first/second image pair"
140140
raise IfgException(msg)
141141

142-
# check master/slave dates are in order
142+
# check first/second dates are in order
143143
try:
144144
# TODO: Clarify: Is the comparison here for a different date?
145145
# Then it should be written in a more pythonic way
@@ -151,17 +151,17 @@ def ifg_date_lookup(ifgs, date_pair):
151151
raise ValueError("Bad date_pair arg to ifg_date_lookup()")
152152

153153
for i in ifgs:
154-
if date_pair == (i.master, i.slave):
154+
if date_pair == (i.first, i.second):
155155
return i
156156

157-
raise ValueError("Cannot find Ifg with "
158-
"master/slave of %s" % str(date_pair))
157+
raise ValueError("Cannot find Ifg with first/second"
158+
"image dates of %s" % str(date_pair))
159159

160160

161161
def ifg_date_index_lookup(ifgs, date_pair):
162162
"""
163-
Returns the Interferogram index which has the master and slave dates
164-
given in 'date_pair'.
163+
Returns the Interferogram index which has the first and second image
164+
dates given in 'date_pair'.
165165
166166
:param list ifgs: List of interferogram objects to search
167167
:param tuple date_pair: A (datetime.date, datetime.date)
@@ -171,21 +171,21 @@ def ifg_date_index_lookup(ifgs, date_pair):
171171
"""
172172

173173
if len(date_pair) != 2:
174-
msg = "Need (datetime.date, datetime.date) master/slave pair"
174+
msg = "Need (datetime.date, datetime.date) first/second image date pair"
175175
raise IfgException(msg)
176176

177-
# check master/slave dates are in order
177+
# check first/second image dates are in order
178178
try:
179179
if date_pair[0] > date_pair[1]:
180180
date_pair = date_pair[1], date_pair[0]
181181
except:
182182
raise ValueError("Bad date_pair arg to ifg_date_lookup()")
183183

184184
for i, _ in enumerate(ifgs):
185-
if date_pair == (ifgs[i].master, ifgs[i].slave):
185+
if date_pair == (ifgs[i].first, ifgs[i].second):
186186
return i
187187

188-
raise ValueError("Cannot find Ifg with master/slave of %s" % str(date_pair))
188+
raise ValueError("Cannot find Ifg with first/second image dates of %s" % str(date_pair))
189189

190190

191191
def get_epochs(ifgs: Union[Iterable, Dict]) -> Tuple[EpochList, int]:
@@ -211,18 +211,18 @@ def get_epochs(ifgs: Union[Iterable, Dict]) -> Tuple[EpochList, int]:
211211

212212
def get_all_epochs(ifgs):
213213
"""
214-
Returns a sequence of all master and slave dates in given interferograms.
214+
Returns a sequence of all image dates used to form given interferograms.
215215
216216
:param list ifgs: List of interferogram objects
217217
218-
:return: master and slave dates
218+
:return: list of all image dates
219219
:rtype: list
220220
"""
221221

222-
return [ifg.master for ifg in ifgs] + [ifg.slave for ifg in ifgs]
222+
return [ifg.first for ifg in ifgs] + [ifg.second for ifg in ifgs]
223223

224224

225-
def master_slave_ids(dates):
225+
def first_second_ids(dates):
226226
"""
227227
Returns a dictionary of 'date:unique ID' for each date in 'dates'.
228228
IDs are ordered from oldest to newest, starting at 0.

0 commit comments

Comments
 (0)