Skip to content

Commit

Permalink
refactor (interface)!: improve command line handling
Browse files Browse the repository at this point in the history
Refactors main() to handle irregular arguments.
Refactors modules to handle passed kwargs. Kwargs should be expanded to
a function's arguments in its outer scope and are not allowed in
backend modules.
Futureproofs API by requesting an argument for a dataset's source
before parsing it.

Removes optional switch:
    -q, --specific-humidity

Refs: ST-3, ST-5, ST-6, ST-7, ST-26, ST-118
  • Loading branch information
gampnico committed May 11, 2023
1 parent e07e091 commit 26fa7bd
Show file tree
Hide file tree
Showing 10 changed files with 460 additions and 156 deletions.
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def setup(app):
project = "Scintillometry Tools"
copyright = f"2019-{date.today().year}, Scintillometry Tools Contributors"
author = "Scintillometry Tools Contributors"
release = "0.36.a0"
release = "0.37.a0"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 2 additions & 0 deletions docs/source/development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ committing:
make tests
Tests can take a couple of minutes to run.

After adding changes with ``git add``, run:

.. code-block:: bash
Expand Down
3 changes: 1 addition & 2 deletions docs/source/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,11 @@ Required arguments:

Optional switches:
-h, --help Show this help message and exit.
-q, --specific-humidity Derive fluxes from specific humidity.
-z, --dry-run Dry run of model.
-v, --verbose Verbose mode.

Optional arguments:
-e, --eddy <str> Path to eddy covariance data (InnFLUX).
-e, --eddy <str> Path to eddy covariance data (innFLUX).
-p, --profile <str> Path to temperature and humidity profiles
(HATPRO).
-t, --timezone <str> Convert to local timezone. Default "CET".
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "scintillometry"
version = "0.36.a0"
version = "0.37.a0"
authors = [
{ name="Scintillometry-Tools Contributors", email="" },
]
Expand Down
2 changes: 1 addition & 1 deletion src/scintillometry/backend/derivations.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def compute_fluxes(input_data, effective_height, beam_params=None):
effective_height (np.floating): Effective path height,
|z_eff| [m].
beam_params (tuple[int, int]): Wavelength and wavelength error
interval in nanometres. For BLS this is typically (850, 20).
interval in nanometres. For BLS this is typically (880, 20).
Returns:
pd.DataFrame: Updated dataframe containing derived values for
Expand Down
164 changes: 121 additions & 43 deletions src/scintillometry/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@
Optional switches:
-h, --help Show this help message and exit.
-q, --specific-humidity Derive fluxes from specific humidity.
-z, --dry-run Dry run of model.
-v, --verbose Verbose mode.
Optional arguments:
-e, --eddy <str> Path to eddy covariance data (InnFLUX).
-e, --eddy <str> Path to eddy covariance data (innFLUX).
-p, --profile <str> Path prefix to vertical temperature and
humidity measurements (HATPRO).
-l, --local-timezone <str> Convert to local timezone.
Expand Down Expand Up @@ -69,7 +68,6 @@ def user_argumentation():
Optional switches:
-h, --help Show this help message and exit.
-q, --specific-humidity Derive fluxes from specific humidity.
-z, --dry-run Dry run of model.
-v, --verbose Verbose mode.
Expand Down Expand Up @@ -124,14 +122,6 @@ def user_argumentation():
help="path to topographical path transect",
)
# Switches
parser.add_argument(
"-q",
"--specific-humidity",
action="store_true",
default=None,
dest="specific_humidity",
help="derive fluxes from specific humidity",
)
parser.add_argument(
"-z",
"--dry-run",
Expand Down Expand Up @@ -190,7 +180,7 @@ def user_argumentation():
type=str,
metavar="<path>",
required=False,
help="path to eddy covariance data (InnFLUX)",
help="path to eddy covariance data (innFLUX)",
)
parser.add_argument(
"-l",
Expand Down Expand Up @@ -278,48 +268,136 @@ def user_argumentation():
return arguments


def main():
args = user_argumentation()
print(args)
if args.specific_humidity:
raise NotImplementedError(
"Deriving fluxes from specific humidity is not yet implemented."
)
def perform_data_parsing(**kwargs):
"""Parses data from command line arguments.
Keyword Arguments:
bls_path (str): Path to a raw .mnd data file using FORMAT-1.
transect_path (str): Path to processed transect. The data must
be formatted as <path_height>, <normalised_path_position>.
The normalised path position maps to:
[0: receiver location, 1: transmitter location].
calibration (list): Contains the incorrect and correct path
lengths. Format as [incorrect, correct].
station_id (str): ZAMG weather station ID (Klima-ID).
Default 11803.
timezone (str): Local timezone during the scintillometer's
operation. Default "CET".
profile_prefix (str): Path to vertical measurements. For HATPRO
Retrieval data there should be two HATPRO files ending with
"humidity" and "temp". The path should be identical for both
files, e.g.::
./path/to/file_humidity.csv
./path/to/file_temp.csv
would require `file_path = "./path/to/file_"`. Default None.
# Import and parse BLS450, ZAMG, transect data
parsed_datasets = DataParser.wrangle_data(
bls_path=args.input,
transect_path=args.transect_path,
calibrate=args.calibration,
tzone=args.timezone,
station_id=args.station_id,
Returns:
dict: Parsed and labelled datasets for scintillometry
measurements, weather observations, and topography.
"""

# Parse BLS, weather, and topographical data
datasets = DataParser.wrangle_data(
bls_path=kwargs["input"],
transect_path=kwargs["transect_path"],
calibrate=kwargs["calibration"],
station_id=kwargs["station_id"],
tzone=kwargs["timezone"],
)

# Parse vertical measurements
if args.profile_prefix:
parsed_datasets["vertical"] = DataParser.parse_vertical(
file_path=args.profile_prefix,
device="hatpro",
if kwargs["profile_prefix"]:
datasets["vertical"] = DataParser.parse_vertical(
file_path=kwargs["profile_prefix"],
source="hatpro",
levels=None,
tzone=args.timezone,
tzone=kwargs["timezone"],
)

return datasets


def perform_analysis(datasets, **kwargs):
"""Analyses flux data.
Calculates and plots parsed data, and optionally compares it to
third-party data.
Defaults for keyword arguments only apply if the kwargs are passed
via command line arguments.
Arguments:
datasets (dict): Parsed and labelled datasets for scintillometry
measurements, weather observations, topography, and
optionally vertical measurements.
Keyword Args:
eddy_path (str): Path to eddy covariance measurements.
Default None.
regime (str): Target stability condition. Default None.
timezone (str): Local timezone of the measurement period.
Default "CET".
most_name (str): MOST coefficients for unstable and stable
conditions. Default "an1988".
method (str): Method to calculate switch time. Default "sun".
switch_time (Union[str, pd.Timestamp]): Local time of switch
between stability conditions. Overrides <method>.
Default None.
location (str): Location of data collection. Default empty
string.
beam_wavelength (int): Transmitter beam wavelength, nm.
Default 880 nm.
beam_error (int): Transmitter beam error, nm. Default 20 nm.
Returns:
dict: Passes input datasets. If a path to eddy covariance data
is provided, adds the key "eddy" containing the parsed eddy
covariance data.
"""

metrics_class = MetricsCalculations.MetricsWorkflow()
metrics_data = metrics_class.calculate_standard_metrics(
arguments=args, data=parsed_datasets
)
if args.eddy_path:
innflux_frame = DataParser.parse_innflux(
file_name=args.eddy_path,
tzone=args.timezone,
headers=None,
metrics_data = metrics_class.calculate_standard_metrics(data=datasets, **kwargs)
if kwargs["eddy_path"]:
eddy_frame = DataParser.parse_eddy_covariance(
file_path=kwargs["eddy_path"], tzone=kwargs["timezone"], source="innflux"
)
metrics_class.compare_innflux(
arguments=args,
innflux_data=innflux_frame,
comparison_data=metrics_data["iteration"],
metrics_data["eddy"] = eddy_frame
metrics_class.compare_eddy(
own_data=metrics_data["iteration"],
ext_data=eddy_frame,
source="innflux",
location=kwargs["location"],
)

return metrics_data


def main():
"""Parses command line arguments and executes analysis.
Converts command line arguments into kwargs. Imports and parses
scintillomter, weather, and transect data. If the appropriate
arguments are specified:
- Parses vertical measurements
- Calculates sensible heat fluxes
- Compares calculated fluxes to external data.
The majority of kwarg expansions should occur in this module. Do not
rely on kwargs for passing arguments between backend modules.
"""

arguments = user_argumentation()
kwarg_args = vars(arguments)

parsed_datasets = perform_data_parsing(**kwarg_args)
if not arguments.dry_run:
perform_analysis(datasets=parsed_datasets, **kwarg_args)
else:
print("Dry run - no analysis available.")


if __name__ == "__main__":
main()
Loading

0 comments on commit 26fa7bd

Please sign in to comment.