import datetime
from os import PathLike
from uuid import UUID
import numpy as np
from numpy import ma
from cloudnetpy import output
from cloudnetpy.constants import G_TO_KG, MM_H_TO_M_S
from cloudnetpy.exceptions import ValidTimeStampError
from cloudnetpy.instruments.instruments import FMCW94
from cloudnetpy.instruments.nc_radar import NcRadar
from cloudnetpy.instruments.rpg import RPG_ATTRIBUTES
from cloudnetpy.metadata import MetaData
from cloudnetpy.utils import bit_field_definition, get_uuid
[docs]
def bowtie2nc(
bowtie_file: str | PathLike,
output_file: str | PathLike,
site_meta: dict,
uuid: str | UUID | None = None,
date: str | datetime.date | None = None,
) -> UUID:
"""Converts 'BOW-TIE' RV-Meteor cloud radar data into Cloudnet Level 1b netCDF file.
Args:
bowtie_file: Input filename.
output_file: Output filename.
site_meta: Dictionary containing information about the site. Required key
value pair is `name`. Optional are `latitude`, `longitude`, `altitude`.
uuid: Set specific UUID for the file.
date: Expected date as YYYY-MM-DD of all profiles in the file.
Returns:
UUID of the generated file.
Raises:
ValidTimeStampError: No valid timestamps found.
"""
keymap = {
"Zh": "Zh",
"v": "v",
"width": "width",
"ldr": "ldr",
"kurt": "kurtosis",
"Skew": "skewness",
"SNR": "SNR",
"time": "time",
"range": "range",
"lwp": "lwp",
"SurfRelHum": "relative_humidity",
"rain": "rainfall_rate",
"Nyquist_velocity": "nyquist_velocity",
"range_offsets": "chirp_start_indices",
}
if isinstance(date, str):
date = datetime.date.fromisoformat(date)
uuid = get_uuid(uuid)
with Bowtie(bowtie_file, site_meta) as bowtie:
bowtie.init_data(keymap)
bowtie.add_time_and_range()
if date is not None:
bowtie.check_date(date)
bowtie.add_radar_specific_variables()
bowtie.add_site_geolocation()
bowtie.add_height()
bowtie.convert_units()
bowtie.fix_chirp_start_indices()
bowtie.test_if_all_masked()
bowtie.add_correction_bits()
attributes = output.add_time_attribute(ATTRIBUTES, bowtie.date)
output.update_attributes(bowtie.data, attributes)
output.save_level1b(bowtie, output_file, uuid)
return uuid
class Bowtie(NcRadar):
def __init__(self, full_path: str | PathLike, site_meta: dict) -> None:
super().__init__(full_path, site_meta)
self.instrument = FMCW94
self.date = self.get_date()
def convert_units(self) -> None:
self.data["lwp"].data *= G_TO_KG
self.data["rainfall_rate"].data *= MM_H_TO_M_S
self.data["relative_humidity"].data /= 100
def fix_chirp_start_indices(self) -> None:
array = self.data["chirp_start_indices"].data
self.data["chirp_start_indices"].data = np.array(array, dtype=np.int32)
self.data["chirp_start_indices"].data_type = "int32"
def add_correction_bits(self) -> None:
bits = ma.ones(self.data["v"].data.shape, dtype=np.uint32)
bits.mask = self.data["v"].data.mask
self.append_data(bits, "correction_bits")
def check_date(self, date: datetime.date) -> None:
if self.date != date:
raise ValidTimeStampError
ATTRIBUTES = RPG_ATTRIBUTES | {
"v": MetaData(
long_name="Doppler velocity",
units="m s-1",
comment=(
"This parameter is the radial component of the velocity, with positive\n"
"velocities are away from the radar. It was corrected for the heave\n"
"motion of the ship. A rolling average over 3 time steps has been\n"
"applied to it."
),
dimensions=("time", "range"),
),
"correction_bits": MetaData(
long_name="Correction bits",
units="1",
definition=bit_field_definition({0: """Doppler velocity is dealiased."""}),
comment=(
"This parameter is a bit field that indicates which corrections have\n"
"been applied to radar measurements."
),
dimensions=("time", "range"),
),
"nyquist_velocity": MetaData(
long_name="Nyquist velocity",
units="m s-1",
dimensions=("time", "chirp_sequence"),
),
}