def test_c_s(self):
        c_ck = 75
        t_ck = 40
        p_ck = 10000
        s_ck = 36.616

        s_calc = Oc.c2s(c=c_ck, t=t_ck, p=p_ck)

        self.assertAlmostEqual(s_calc, s_ck, places=1)

        c_calc = Oc.s2c(s=s_calc, p=p_ck, t=t_ck)

        self.assertAlmostEqual(c_calc, c_ck, places=1)
    def test_theta_t0(self):
        theta_ck = 36.89073
        s_ck = 40
        t0_ck = 40
        p0_ck = 10000
        p_ref_ck = 0

        theta_calc = Oc.pot_temp(s=s_ck, t=t0_ck, p=p0_ck, pr=p_ref_ck)

        self.assertAlmostEqual(theta_calc, theta_ck, places=1)

        t0_calc = Oc.in_situ_temp(s=s_ck, t=theta_ck, p=p0_ck, pr=p_ref_ck)

        self.assertAlmostEqual(t0_calc, t0_ck, places=1)
Beispiel #3
0
 def _write_body(self):
     # logger.debug('generating body')
     vi = self.ssp.cur.proc_valid
     for idx in range(np.sum(vi)):
         self.fod.io.write(
             "%8.2f%10.2f%10.2f%10.2f%10.2f\n" %
             (self.ssp.cur.proc.depth[vi][idx],
              self.ssp.cur.proc.speed[vi][idx],
              self.ssp.cur.proc.temp[vi][idx],
              self.ssp.cur.proc.sal[vi][idx],
              Oc.s2c(s=self.ssp.cur.proc.sal[vi][idx],
                     p=Oc.d2p(d=self.ssp.cur.proc.depth[vi][idx],
                              lat=self.ssp.cur.meta.latitude),
                     t=self.ssp.cur.proc.temp[vi][idx])))
    def test_d2p_gsw(self):
        # check values from generate_gsw_trusted_values
        trusted_gsw_d = 9713.7  # m
        trusted_gsw_p = 10000  # dBar
        trusted_gsw_lat = 30.0

        calc_p = Oc.d2p_gsw(d=trusted_gsw_d, lat=trusted_gsw_lat, dyn_height=None)
        self.assertAlmostEqual(calc_p, trusted_gsw_p, places=1)
    def test_cr2s(self):
        cr_ck = 1.1
        t_ck = 40.0
        s_ck = 38.999

        s_calc = Oc.cr2s(cr=cr_ck, t=t_ck)

        self.assertAlmostEqual(s_calc, s_ck, places=1)
    def test_d2p_backup(self):
        # check values from Fofonoff and Millard(1983)
        trusted_fof_d = 9712.653  # m
        trusted_fof_p = 10000  # dBar
        trusted_fof_lat = 30.0

        calc_p = Oc.d2p_backup(d=trusted_fof_d, lat=trusted_fof_lat)
        self.assertAlmostEqual(calc_p, trusted_fof_p, places=1)
    def test_p2d_gsw(self):
        # check values from generate_gsw_trusted_values
        trusted_gsw_d = 9713.7  # m
        trusted_gsw_p = 10000  # dBar
        trusted_gsw_lat = 30.0

        calc_d = Oc.p2d_gsw(p=trusted_gsw_p, lat=trusted_gsw_lat, dyn_height=None)
        self.assertLess(abs(calc_d - trusted_gsw_d), 0.1)
    def test_atg(self):
        # check values from Fofonoff and Millard(1983)
        atg_ck = 3.255976e-4
        s_ck = 40.0
        t_ck = 40
        p_ck = 10000

        atg_calc = Oc.atg(s=s_ck, t=t_ck, p=p_ck)

        self.assertAlmostEqual(atg_calc, atg_ck, places=1)
    def test_d2p_gsw(self):
        # check values from generate_gsw_trusted_values
        trusted_gsw_d = 9713.7  # m
        trusted_gsw_p = 10000  # dBar
        trusted_gsw_lat = 30.0

        calc_p = Oc.d2p_gsw(d=trusted_gsw_d,
                            lat=trusted_gsw_lat,
                            dyn_height=None)
        self.assertLess(abs(calc_p - trusted_gsw_p), 0.1)
    def test_sal(self):
        # check values from Fofonoff and Millard(1983)
        trusted_fof_d = 9712.653  # m
        trusted_fof_lat = 30.0

        # check values dBar from Wong and Zhu(1995), Table III
        trusted_fof_s = 35  # ppt
        trusted_fof_t = 20  # deg C
        trusted_fof_vs = 1687.198  # m/sec

        calc_s = Oc.sal(d=trusted_fof_d, speed=trusted_fof_vs, t=trusted_fof_t, lat=trusted_fof_lat)

        self.assertAlmostEqual(calc_s, trusted_fof_s, places=1)
    def test_dyn_height_1000(self):
        # absolute salinity
        sa = np.array([34.7118, 34.8915, 35.0256, 34.8472, 34.7366, 34.7324])
        # conservative temperature
        ct = np.array([28.8099, 28.4392, 22.7862, 10.2262, 6.8272, 4.3236])
        # sea pressure
        p = np.array([10.0, 50.0, 125.0, 250.0, 600.0, 1000.0])
        p_ref = 1000.0
        # golden reference values
        gold_ref = np.array([17.0392, 14.6659, 10.9129, 7.5679, 3.3935, 0])

        calc_out = Oc.geo_strf_dyn_height(sa=sa, ct=ct, p=p, p_ref=p_ref)

        for i, val in enumerate(gold_ref):
            self.assertAlmostEqual(calc_out[i], val, places=0)
Beispiel #12
0
    def _write_body_abs(self, freq):
        # logger.debug('generating body for %d kHz' % freq)

        ti = self.ssp.cur.sis_thinned

        top_mean = 0
        bottom_mean = 0

        body = str()
        sample_sz = int(np.sum(ti))
        has_skipped_salinity = False
        for i in range(sample_sz):

            if self.ssp.cur.sis.sal[ti][i] <= 0:
                if not has_skipped_salinity:
                    logger.info("skipping invalid salinity values")
                    has_skipped_salinity = True
                continue

            abs = Oc.attenuation(f=freq, t=self.ssp.cur.sis.temp[ti][i], d=self.ssp.cur.sis.depth[ti][i],
                                 s=self.ssp.cur.sis.sal[ti][i], ph=8.1)

            if i == 0:  # first
                delta = (self.ssp.cur.sis.depth[ti][0] + self.ssp.cur.sis.depth[ti][1]) / 2.0

            elif i == sample_sz - 1:  # last
                delta = (self.ssp.cur.sis.depth[ti][sample_sz - 1] -
                         (self.ssp.cur.sis.depth[ti][sample_sz - 1] + self.ssp.cur.sis.depth[ti][sample_sz - 2]) / 2.0)

            else:
                delta = ((self.ssp.cur.sis.depth[ti][i + 1] + self.ssp.cur.sis.depth[ti][i]) / 2.0 -
                         (self.ssp.cur.sis.depth[ti][i] + self.ssp.cur.sis.depth[ti][i - 1]) / 2.0)

            top_mean += abs * delta
            bottom_mean += delta

            mean_abs = top_mean / bottom_mean

            body += "%.3f %.3f %.3f %s\n" \
                    % (self.ssp.cur.sis.depth[ti][i], abs, mean_abs, "999.000")

        self.fod.io.write(body)
        self.fod.io.close()
from hyo2.abc.lib.logging import set_logging

ns_list = [
    "hyo2.soundspeed", "hyo2.soundspeedmanager", "hyo2.soundspeedsettings"
]
set_logging(ns_list=ns_list)

logger = logging.getLogger(__name__)

# check values from Fofonoff and Millard(1983)
trusted_fof_d = 9712.653  # m
trusted_fof_p = 10000  # dBar
trusted_fof_lat = 30.0

# check values from generate_gsw_trusted_values
trusted_gsw_d = 9713.7  # m
trusted_gsw_p = 10000  # dBar
trusted_gsw_lat = 30.0

calc_d = Oc.p2d_backup(p=trusted_fof_p, lat=trusted_fof_lat)
logger.info("Backup: Depth: %.3f <> %.3f" % (calc_d, trusted_fof_d))

calc_d = Oc.p2d_gsw(p=trusted_gsw_p, lat=trusted_gsw_lat, dyn_height=None)
logger.info("GSW: Depth: %.3f <> %.3f" % (calc_d, trusted_gsw_d))

calc_p = Oc.d2p_backup(d=calc_d, lat=trusted_fof_lat)
logger.info("Backup: Pressure: %.3f <> %.3f" % (calc_p, trusted_fof_p))

calc_p = Oc.d2p_gsw(d=trusted_gsw_d, lat=trusted_gsw_lat, dyn_height=None)
logger.info("GSW: Pressure: %.3f <> %.3f" % (calc_p, trusted_gsw_p))
Beispiel #14
0
class ConstantGradientProfileDialog(AbstractDialog):

    def __init__(self, main_win, lib, parent=None):
        AbstractDialog.__init__(self, main_win=main_win, lib=lib, parent=parent)

        self.oc = Oceanography()

        self.setWindowTitle("Constant-gradient Profile")
        self.setMinimumWidth(480)

        # outline ui
        self.mainLayout = QtWidgets.QVBoxLayout()
        self.mainLayout.setContentsMargins(3, 3, 3, 3)
        self.setLayout(self.mainLayout)

        value_validator = QtGui.QDoubleValidator(0, 12000, 2, self)

        self.mainLayout.addStretch()

        # start point
        hbox = QtWidgets.QHBoxLayout()
        self.mainLayout.addLayout(hbox)
        hbox.addStretch()
        # depth label
        self.start_depth_label = QtWidgets.QLabel("Start [m]:")
        self.start_depth_label.setFixedWidth(50)
        self.start_depth_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.start_depth_label)
        # depth value
        self.start_depth_value = QtWidgets.QLineEdit()
        self.start_depth_value.setFixedWidth(50)
        self.start_depth_value.setValidator(value_validator)
        self.start_depth_value.setText("0.0")
        # noinspection PyUnresolvedReferences
        self.start_depth_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.start_depth_value)
        # temp label
        self.start_temp_label = QtWidgets.QLabel("temp [°C]:")
        self.start_temp_label.setFixedWidth(70)
        self.start_temp_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.start_temp_label)
        # temp value
        self.start_temp_value = QtWidgets.QLineEdit()
        self.start_temp_value.setFixedWidth(50)
        self.start_temp_value.setValidator(value_validator)
        self.start_temp_value.setText("12.94")
        # noinspection PyUnresolvedReferences
        self.start_temp_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.start_temp_value)
        # sal label
        self.start_sal_label = QtWidgets.QLabel("sal [PSU]:")
        self.start_sal_label.setFixedWidth(70)
        self.start_sal_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.start_sal_label)
        # sal value
        self.start_sal_value = QtWidgets.QLineEdit()
        self.start_sal_value.setFixedWidth(50)
        self.start_sal_value.setValidator(value_validator)
        self.start_sal_value.setText("35.0")
        # noinspection PyUnresolvedReferences
        self.start_sal_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.start_sal_value)
        # speed label
        self.start_speed_label = QtWidgets.QLabel("speed [m/s]:")
        self.start_speed_label.setFixedWidth(70)
        self.start_speed_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.start_speed_label)
        # speed value
        self.start_speed_value = QtWidgets.QLineEdit()
        self.start_speed_value.setFixedWidth(70)
        self.start_speed_value.setValidator(value_validator)
        self.start_speed_value.setText("1500.0")
        self.start_speed_value.setDisabled(True)
        # noinspection PyUnresolvedReferences
        self.start_speed_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.start_speed_value)
        hbox.addStretch()

        # end point
        hbox = QtWidgets.QHBoxLayout()
        self.mainLayout.addLayout(hbox)
        hbox.addStretch()
        # depth label
        self.end_depth_label = QtWidgets.QLabel("End [m]:")
        self.end_depth_label.setFixedWidth(50)
        self.end_depth_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.end_depth_label)
        # depth value
        self.end_depth_value = QtWidgets.QLineEdit()
        self.end_depth_value.setFixedWidth(50)
        self.end_depth_value.setValidator(value_validator)
        self.end_depth_value.setText("1000.0")
        # noinspection PyUnresolvedReferences
        self.end_depth_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.end_depth_value)
        # temp label
        self.end_temp_label = QtWidgets.QLabel("temp [°C]:")
        self.end_temp_label.setFixedWidth(70)
        self.end_temp_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.end_temp_label)
        # temp value
        self.end_temp_value = QtWidgets.QLineEdit()
        self.end_temp_value.setFixedWidth(50)
        self.end_temp_value.setValidator(value_validator)
        self.end_temp_value.setText("12.94")
        # noinspection PyUnresolvedReferences
        self.end_temp_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.end_temp_value)
        # sal label
        self.end_sal_label = QtWidgets.QLabel("sal [PSU]:")
        self.end_sal_label.setFixedWidth(70)
        self.end_sal_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.end_sal_label)
        # sal value
        self.end_sal_value = QtWidgets.QLineEdit()
        self.end_sal_value.setFixedWidth(50)
        self.end_sal_value.setValidator(value_validator)
        self.end_sal_value.setText("35.0")
        # noinspection PyUnresolvedReferences
        self.end_sal_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.end_sal_value)
        # speed label
        self.end_speed_label = QtWidgets.QLabel("speed [m/s]:")
        self.end_speed_label.setFixedWidth(70)
        self.end_speed_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.end_speed_label)
        # speed value
        self.end_speed_value = QtWidgets.QLineEdit()
        self.end_speed_value.setFixedWidth(70)
        self.end_speed_value.setValidator(value_validator)
        self.end_speed_value.setText("1500.0")
        self.end_speed_value.setDisabled(True)
        # noinspection PyUnresolvedReferences
        self.end_speed_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.end_speed_value)
        hbox.addStretch()

        self.mainLayout.addSpacing(12)

        # apply
        hbox = QtWidgets.QHBoxLayout()
        hbox.addStretch()
        self.apply = QtWidgets.QPushButton("Apply")
        # self.apply.setFixedHeight(30)
        # noinspection PyUnresolvedReferences
        self.apply.clicked.connect(self.on_apply)
        hbox.addWidget(self.apply)
        hbox.addStretch()
        self.mainLayout.addLayout(hbox)

        self.mainLayout.addStretch()

        self.on_values_changed()

    def on_values_changed(self):
        logger.debug("values changed")

        try:
            start_speed = self.oc.speed(d=float(self.start_depth_value.text()),
                                        t=float(self.start_temp_value.text()),
                                        s=float(self.start_sal_value.text()))
            self.start_speed_value.setText("%.2f" % start_speed)
        except Exception as e:
            logger.warning("Invalid start sound speed calculation: %s" % e)

        try:
            end_speed = self.oc.speed(d=float(self.end_depth_value.text()),
                                      t=float(self.end_temp_value.text()),
                                      s=float(self.end_sal_value.text()))
            self.end_speed_value.setText("%.2f" % end_speed)
        except Exception as e:
            logger.warning("Invalid end sound speed calculation: %s" % e)

    def on_apply(self):
        logger.debug("apply")

        try:
            start_depth = float(self.start_depth_value.text())
            end_depth = float(self.end_depth_value.text())
            if start_depth < 0:
                raise RuntimeError("Negative start depth: %s" % start_depth)
            if start_depth > end_depth:
                raise RuntimeError("Start depth > end depth: %s > %s" % (start_depth, end_depth))

        except Exception as e:
            msg = "Issue in depth fields!\n\n%s" % e
            # noinspection PyCallByClass,PyArgumentList
            QtWidgets.QMessageBox.warning(self, "Constant-gradient profile", msg, QtWidgets.QMessageBox.Ok)
            return

        try:
            start_temp = float(self.start_temp_value.text())
            end_temp = float(self.end_temp_value.text())
            if start_temp < -1.0:
                raise RuntimeError("Too negative start temp: %s" % start_temp)

        except Exception as e:
            msg = "Issue in temperature fields!\n\n%s" % e
            # noinspection PyCallByClass,PyArgumentList
            QtWidgets.QMessageBox.warning(self, "Constant-gradient profile", msg, QtWidgets.QMessageBox.Ok)
            return

        try:
            start_sal = float(self.start_sal_value.text())
            end_sal = float(self.end_sal_value.text())
            if start_sal < 0:
                raise RuntimeError("Negative start sal: %s" % start_sal)

        except Exception as e:
            msg = "Issue in salinity fields!\n\n%s" % e
            # noinspection PyCallByClass,PyArgumentList
            QtWidgets.QMessageBox.warning(self, "Constant-gradient profile", msg, QtWidgets.QMessageBox.Ok)
            return

        try:
            start_speed = float(self.start_speed_value.text())
            end_speed = float(self.end_speed_value.text())
            if start_speed < 0:
                raise RuntimeError("Negative start speed: %s" % start_speed)

        except Exception as e:
            msg = "Issue in speed fields!\n\n%s" % e
            # noinspection PyCallByClass,PyArgumentList
            QtWidgets.QMessageBox.warning(self, "Constant-gradient profile", msg, QtWidgets.QMessageBox.Ok)
            return

        try:
            self.lib.create_profile(start_depth=start_depth, start_temp=start_temp,
                                    start_sal=start_sal, start_speed=start_speed,
                                    end_depth=end_depth, end_temp=end_temp,
                                    end_sal=end_sal, end_speed=end_speed)

        except RuntimeError as e:
            traceback.print_exc()
            msg = "Issue in creating the profile:\n\n> %s" % e
            # noinspection PyCallByClass,PyArgumentList
            QtWidgets.QMessageBox.critical(self, "Creation error", msg, QtWidgets.QMessageBox.Ok)
            return

        self.accept()
Beispiel #15
0
    def __init__(self, main_win, lib, parent=None):
        AbstractDialog.__init__(self, main_win=main_win, lib=lib, parent=parent)

        self.oc = Oceanography()

        self.setWindowTitle("Constant-gradient Profile")
        self.setMinimumWidth(480)

        # outline ui
        self.mainLayout = QtWidgets.QVBoxLayout()
        self.mainLayout.setContentsMargins(3, 3, 3, 3)
        self.setLayout(self.mainLayout)

        value_validator = QtGui.QDoubleValidator(0, 12000, 2, self)

        self.mainLayout.addStretch()

        # start point
        hbox = QtWidgets.QHBoxLayout()
        self.mainLayout.addLayout(hbox)
        hbox.addStretch()
        # depth label
        self.start_depth_label = QtWidgets.QLabel("Start [m]:")
        self.start_depth_label.setFixedWidth(50)
        self.start_depth_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.start_depth_label)
        # depth value
        self.start_depth_value = QtWidgets.QLineEdit()
        self.start_depth_value.setFixedWidth(50)
        self.start_depth_value.setValidator(value_validator)
        self.start_depth_value.setText("0.0")
        # noinspection PyUnresolvedReferences
        self.start_depth_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.start_depth_value)
        # temp label
        self.start_temp_label = QtWidgets.QLabel("temp [°C]:")
        self.start_temp_label.setFixedWidth(70)
        self.start_temp_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.start_temp_label)
        # temp value
        self.start_temp_value = QtWidgets.QLineEdit()
        self.start_temp_value.setFixedWidth(50)
        self.start_temp_value.setValidator(value_validator)
        self.start_temp_value.setText("12.94")
        # noinspection PyUnresolvedReferences
        self.start_temp_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.start_temp_value)
        # sal label
        self.start_sal_label = QtWidgets.QLabel("sal [PSU]:")
        self.start_sal_label.setFixedWidth(70)
        self.start_sal_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.start_sal_label)
        # sal value
        self.start_sal_value = QtWidgets.QLineEdit()
        self.start_sal_value.setFixedWidth(50)
        self.start_sal_value.setValidator(value_validator)
        self.start_sal_value.setText("35.0")
        # noinspection PyUnresolvedReferences
        self.start_sal_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.start_sal_value)
        # speed label
        self.start_speed_label = QtWidgets.QLabel("speed [m/s]:")
        self.start_speed_label.setFixedWidth(70)
        self.start_speed_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.start_speed_label)
        # speed value
        self.start_speed_value = QtWidgets.QLineEdit()
        self.start_speed_value.setFixedWidth(70)
        self.start_speed_value.setValidator(value_validator)
        self.start_speed_value.setText("1500.0")
        self.start_speed_value.setDisabled(True)
        # noinspection PyUnresolvedReferences
        self.start_speed_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.start_speed_value)
        hbox.addStretch()

        # end point
        hbox = QtWidgets.QHBoxLayout()
        self.mainLayout.addLayout(hbox)
        hbox.addStretch()
        # depth label
        self.end_depth_label = QtWidgets.QLabel("End [m]:")
        self.end_depth_label.setFixedWidth(50)
        self.end_depth_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.end_depth_label)
        # depth value
        self.end_depth_value = QtWidgets.QLineEdit()
        self.end_depth_value.setFixedWidth(50)
        self.end_depth_value.setValidator(value_validator)
        self.end_depth_value.setText("1000.0")
        # noinspection PyUnresolvedReferences
        self.end_depth_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.end_depth_value)
        # temp label
        self.end_temp_label = QtWidgets.QLabel("temp [°C]:")
        self.end_temp_label.setFixedWidth(70)
        self.end_temp_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.end_temp_label)
        # temp value
        self.end_temp_value = QtWidgets.QLineEdit()
        self.end_temp_value.setFixedWidth(50)
        self.end_temp_value.setValidator(value_validator)
        self.end_temp_value.setText("12.94")
        # noinspection PyUnresolvedReferences
        self.end_temp_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.end_temp_value)
        # sal label
        self.end_sal_label = QtWidgets.QLabel("sal [PSU]:")
        self.end_sal_label.setFixedWidth(70)
        self.end_sal_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.end_sal_label)
        # sal value
        self.end_sal_value = QtWidgets.QLineEdit()
        self.end_sal_value.setFixedWidth(50)
        self.end_sal_value.setValidator(value_validator)
        self.end_sal_value.setText("35.0")
        # noinspection PyUnresolvedReferences
        self.end_sal_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.end_sal_value)
        # speed label
        self.end_speed_label = QtWidgets.QLabel("speed [m/s]:")
        self.end_speed_label.setFixedWidth(70)
        self.end_speed_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        hbox.addWidget(self.end_speed_label)
        # speed value
        self.end_speed_value = QtWidgets.QLineEdit()
        self.end_speed_value.setFixedWidth(70)
        self.end_speed_value.setValidator(value_validator)
        self.end_speed_value.setText("1500.0")
        self.end_speed_value.setDisabled(True)
        # noinspection PyUnresolvedReferences
        self.end_speed_value.textEdited.connect(self.on_values_changed)
        hbox.addWidget(self.end_speed_value)
        hbox.addStretch()

        self.mainLayout.addSpacing(12)

        # apply
        hbox = QtWidgets.QHBoxLayout()
        hbox.addStretch()
        self.apply = QtWidgets.QPushButton("Apply")
        # self.apply.setFixedHeight(30)
        # noinspection PyUnresolvedReferences
        self.apply.clicked.connect(self.on_apply)
        hbox.addWidget(self.apply)
        hbox.addStretch()
        self.mainLayout.addLayout(hbox)

        self.mainLayout.addStretch()

        self.on_values_changed()
Beispiel #16
0
    def query(self,
              lat: Optional[float],
              lon: Optional[float],
              datestamp: Union[date, dt, None] = None,
              server_mode: bool = False):
        """Query RTOFS for passed location and timestamp"""
        if datestamp is None:
            datestamp = dt.utcnow()
        if isinstance(datestamp, dt):
            datestamp = datestamp.date()
        if not isinstance(datestamp, date):
            raise RuntimeError("invalid date passed: %s" % type(datestamp))
        logger.debug("query: %s @ (%.6f, %.6f)" % (datestamp, lon, lat))

        # check the inputs
        if (lat is None) or (lon is None) or (datestamp is None):
            logger.error("invalid query: %s @ (%s, %s)" %
                         (datestamp.strftime("%Y%m%d"), lon, lat))
            return None

        try:
            lat_idx, lon_idx = self.grid_coords(lat,
                                                lon,
                                                datestamp=datestamp,
                                                server_mode=server_mode)
            if lat_idx is None:
                logger.info("location outside of GoMOFS coverage")
                return None

        except TypeError as e:
            logger.critical("while converting location to grid coords, %s" % e)
            return None

        logger.debug("idx > lat: %s, lon: %s" % (lat_idx, lon_idx))
        lat_s_idx = lat_idx - self._search_half_window
        if lat_s_idx < 0:
            lat_s_idx = 0
        lat_n_idx = lat_idx + self._search_half_window
        if lat_n_idx >= self._lat.shape[0]:
            lat_n_idx = self._lat.shape[0] - 1
        lon_w_idx = lon_idx - self._search_half_window
        if lon_w_idx < 0:
            lon_w_idx = 0
        lon_e_idx = lon_idx + self._search_half_window
        if lon_e_idx >= self._lon.shape[1]:
            lon_e_idx = self._lon.shape[1] - 1
        # logger.info("indices -> %s %s %s %s" % (lat_s_idx, lat_n_idx, lon_w_idx, lon_e_idx))
        lat_search_window = lat_n_idx - lat_s_idx + 1
        lon_search_window = lon_e_idx - lon_w_idx + 1
        logger.info("updated search window: (%s, %s)" %
                    (lat_search_window, lon_search_window))

        # Need +1 on the north and east indices since it is the "stop" value in these slices
        t = self._file.variables['temp'][self._day_idx, :,
                                         lat_s_idx:lat_n_idx + 1,
                                         lon_w_idx:lon_e_idx + 1]
        s = self._file.variables['salt'][self._day_idx, :,
                                         lat_s_idx:lat_n_idx + 1,
                                         lon_w_idx:lon_e_idx + 1]
        # Set 'unfilled' elements to NANs (BUT when the entire array has valid data, it returns numpy.ndarray)
        if isinstance(t, np.ma.core.MaskedArray):
            t_mask = t.mask
            t._sharedmask = False
            t[t_mask] = np.nan
        if isinstance(s, np.ma.core.MaskedArray):
            s_mask = s.mask
            s._sharedmask = False
            s[s_mask] = np.nan

        # Calculate distances from requested position to each of the grid node locations
        distances = np.zeros(
            (self._d.size, lon_search_window, lat_search_window))
        longitudes = self._lon[lat_s_idx:lat_n_idx + 1,
                               lon_w_idx:lon_e_idx + 1]
        latitudes = self._lat[lat_s_idx:lat_n_idx + 1, lon_w_idx:lon_e_idx + 1]

        for i in range(lat_search_window):

            for j in range(lon_search_window):
                dist = self.g.distance(longitudes[i, j], latitudes[i, j], lon,
                                       lat)
                distances[:, i, j] = dist
                # logger.info("node (%s %s), pos: %3.2f, %3.2f, dist: %3.1f"
                #             % (i, j, latitudes[i, j], longitudes[i, j], distances[0, i, j]))

        # Get mask of "no data" elements and replace these with NaNs in distance array
        t_mask = np.isnan(t)
        distances[t_mask] = np.nan
        s_mask = np.isnan(s)
        distances[s_mask] = np.nan
        # logger.info("distance array:\n%s" % distances[0])

        # Spin through all the depth levels
        temp_pot = np.zeros(self._d.size)
        temp_in_situ = np.zeros(self._d.size)
        d = np.zeros(self._d.size)
        sal = np.zeros(self._d.size)
        num_values = 0
        for i in range(self._d.size):

            t_level = t[i]
            s_level = s[i]
            d_level = distances[i]

            try:
                ind = np.nanargmin(d_level)
            except ValueError:
                # logger.info("%s: all-NaN slices" % i)
                continue

            if np.isnan(ind):
                logger.info("%s: bottom of valid data" % i)
                break

            ind2 = np.unravel_index(ind, t_level.shape)

            t_closest = t_level[ind2]
            s_closest = s_level[ind2]
            # d_closest = d_level[ind2]

            temp_pot[i] = t_closest
            sal[i] = s_closest
            d[i] = self._d[i]

            # Calculate in-situ temperature
            p = Oc.d2p(d[i], lat)
            temp_in_situ[i] = Oc.in_situ_temp(s=sal[i],
                                              t=t_closest,
                                              p=p,
                                              pr=self._ref_p)
            # logger.info("%02d: %6.1f %6.1f > T/S/Dist: %3.1f %3.1f %3.1f [pot.temp. %3.1f]"
            #             % (i, d[i], p, temp_in_situ[i], s_closest, d_closest, t_closest))

            num_values += 1

        if num_values == 0:
            logger.info("no data from lookup!")
            return None

        # ind = np.nanargmin(distances[0])
        # ind2 = np.unravel_index(ind, distances[0].shape)
        # switching to the query location
        # lat_out = latitudes[ind2]
        # lon_out = longitudes[ind2]
        # while lon_out > 180.0:
        #     lon_out -= 360.0

        # Make a new SV object to return our query in
        ssp = Profile()
        ssp.meta.sensor_type = Dicts.sensor_types['Synthetic']
        ssp.meta.probe_type = Dicts.probe_types['GoMOFS']
        ssp.meta.latitude = lat
        if lon > 180.0:  # Go back to negative longitude
            lon -= 360.0
        ssp.meta.longitude = lon
        ssp.meta.utc_time = dt(year=datestamp.year,
                               month=datestamp.month,
                               day=datestamp.day)
        ssp.meta.original_path = "GoMOFS_%s" % datestamp.strftime("%Y%m%d")
        ssp.init_data(num_values)
        ssp.data.depth = d[0:num_values]
        ssp.data.temp = temp_in_situ[0:num_values]
        ssp.data.sal = sal[0:num_values]
        ssp.calc_data_speed()
        ssp.clone_data_to_proc()
        ssp.init_sis()

        profiles = ProfileList()
        profiles.append_profile(ssp)

        return profiles
Beispiel #17
0
    def query(self, lat: Optional[float], lon: Optional[float], dtstamp: Optional[dt] = None,
              server_mode: bool = False):
        """Query RTOFS for passed location and timestamp"""
        if dtstamp is None:
            dtstamp = dt.utcnow()
        if not isinstance(dtstamp, dt):
            raise RuntimeError("invalid datetime passed: %s" % type(dtstamp))
        logger.debug("query: %s @ (%.6f, %.6f)" % (dtstamp, lon, lat))

        # check the inputs
        if (lat is None) or (lon is None):
            logger.error("invalid query: %s @ (%s, %s)" % (dtstamp.strftime("%Y/%m/%d %H:%M:%S"), lon, lat))
            return None

        try:
            lat_idx, lon_idx = self.grid_coords(lat, lon, dtstamp=dtstamp, server_mode=server_mode)
        except TypeError as e:
            logger.critical("while converting location to grid coords, %s" % e)
            return None
        # logger.debug("idx > lat: %s, lon: %s" % (lat_idx, lon_idx))

        lat_s_idx = lat_idx - self._search_half_window
        lat_n_idx = lat_idx + self._search_half_window
        lon_w_idx = lon_idx - self._search_half_window
        lon_e_idx = lon_idx + self._search_half_window
        # logger.info("indices -> %s %s %s %s" % (lat_s_idx, lat_n_idx, lon_w_idx, lon_e_idx))
        if lon < self._lon_0:  # Make all longitudes safe
            lon += 360.0

        longitudes = np.zeros((self._search_window, self._search_window))
        if (lon_e_idx < self._lon.size) and (lon_w_idx >= 0):
            # logger.info("safe case")

            # Need +1 on the north and east indices since it is the "stop" value in these slices
            t = self._file_temp.variables['temperature'][self._day_idx, :, lat_s_idx:lat_n_idx + 1,
                lon_w_idx:lon_e_idx + 1]
            s = self._file_sal.variables['salinity'][self._day_idx, :, lat_s_idx:lat_n_idx + 1, lon_w_idx:lon_e_idx + 1]
            # Set 'unfilled' elements to NANs (BUT when the entire array has valid data, it returns numpy.ndarray)
            if isinstance(t, np.ma.core.MaskedArray):
                t_mask = t.mask
                t._sharedmask = False
                t[t_mask] = np.nan
            if isinstance(s, np.ma.core.MaskedArray):
                s_mask = s.mask
                s._sharedmask = False
                s[s_mask] = np.nan

            lons = self._lon[lon_w_idx:lon_e_idx + 1]
            for i in range(self._search_window):
                longitudes[i, :] = lons
        else:
            logger.info("split case")

            # --- Do the left portion of the array first, this will run into the wrap longitude
            lon_e_idx = self._lon.size - 1
            # lon_west_index can be negative if lon_index is on the westernmost end of the array
            if lon_w_idx < 0:
                lon_w_idx = lon_w_idx + self._lon.size
            # logger.info("using lon west/east indices -> %s %s" % (lon_w_idx, lon_e_idx))

            # Need +1 on the north and east indices since it is the "stop" value in these slices
            t_left = self._file_temp.variables['temperature'][self._day_idx, :, lat_s_idx:lat_n_idx + 1,
                     lon_w_idx:lon_e_idx + 1]
            s_left = self._file_sal.variables['salinity'][self._day_idx, :, lat_s_idx:lat_n_idx + 1,
                     lon_w_idx:lon_e_idx + 1]
            # Set 'unfilled' elements to NANs (BUT when the entire array has valid data, it returns numpy.ndarray)
            if isinstance(t_left, np.ma.core.MaskedArray):
                t_mask = t_left.mask
                t_left[t_mask] = np.nan
            if isinstance(s_left, np.ma.core.MaskedArray):
                s_mask = s_left.mask
                s_left[s_mask] = np.nan

            lons_left = self._lon[lon_w_idx:lon_e_idx + 1]
            for i in range(self._search_window):
                longitudes[i, 0:lons_left.size] = lons_left
            # logger.info("longitudes are now: %s" % longitudes)

            # --- Do the right portion of the array first, this will run into the wrap
            # longitude so limit it accordingly
            lon_w_idx = 0
            lon_e_idx = self._search_window - lons_left.size - 1

            # Need +1 on the north and east indices since it is the "stop" value in these slices
            t_right = self._file_temp.variables['temperature'][self._day_idx, :, lat_s_idx:lat_n_idx + 1,
                      lon_w_idx:lon_e_idx + 1]
            s_right = self._file_sal.variables['salinity'][self._day_idx, :, lat_s_idx:lat_n_idx + 1,
                      lon_w_idx:lon_e_idx + 1]
            # Set 'unfilled' elements to NANs (BUT when the entire array has valid data, it returns numpy.ndarray)
            if isinstance(t_right, np.ma.core.MaskedArray):
                t_mask = t_right.mask
                t_right[t_mask] = np.nan
            if isinstance(s_right, np.ma.core.MaskedArray):
                s_mask = s_right.mask
                s_right[s_mask] = np.nan

            lons_right = self._lon[lon_w_idx:lon_e_idx + 1]
            for i in range(self._search_window):
                longitudes[i, lons_left.size:self._search_window] = lons_right

            # merge data
            t = np.zeros((self._file_temp.variables['lev'].size, self._search_window, self._search_window))
            t[:, :, 0:lons_left.size] = t_left
            t[:, :, lons_left.size:self._search_window] = t_right
            s = np.zeros((self._file_temp.variables['lev'].size, self._search_window, self._search_window))
            s[:, :, 0:lons_left.size] = s_left
            s[:, :, lons_left.size:self._search_window] = s_right

        # Calculate distances from requested position to each of the grid node locations
        distances = np.zeros((self._d.size, self._search_window, self._search_window))
        latitudes = np.zeros((self._search_window, self._search_window))
        lats = self._lat[lat_s_idx:lat_n_idx + 1]
        for i in range(self._search_window):
            latitudes[:, i] = lats

        for i in range(self._search_window):

            for j in range(self._search_window):
                dist = self.g.distance(longitudes[i, j], latitudes[i, j], lon, lat)
                distances[:, i, j] = dist
                # logger.info("node %s, pos: %3.1f, %3.1f, dist: %3.1f"
                #             % (i, latitudes[i, j], longitudes[i, j], distances[0, i, j]))
        # logger.info("distance array:\n%s" % distances[0])
        # Get mask of "no data" elements and replace these with NaNs in distance array
        t_mask = np.isnan(t)
        distances[t_mask] = np.nan
        s_mask = np.isnan(s)
        distances[s_mask] = np.nan

        # Spin through all the depth levels
        temp_pot = np.zeros(self._d.size)
        temp_in_situ = np.zeros(self._d.size)
        d = np.zeros(self._d.size)
        sal = np.zeros(self._d.size)
        num_values = 0
        for i in range(self._d.size):

            t_level = t[i]
            s_level = s[i]
            d_level = distances[i]

            try:
                ind = np.nanargmin(d_level)
            except ValueError:
                # logger.info("%s: all-NaN slices" % i)
                continue

            if np.isnan(ind):
                logger.info("%s: bottom of valid data" % i)
                break

            ind2 = np.unravel_index(ind, t_level.shape)

            t_closest = t_level[ind2]
            s_closest = s_level[ind2]
            # d_closest = d_level[ind2]

            temp_pot[i] = t_closest
            sal[i] = s_closest
            d[i] = self._d[i]

            # Calculate in-situ temperature
            p = Oc.d2p(d[i], lat)
            temp_in_situ[i] = Oc.in_situ_temp(s=sal[i], t=t_closest, p=p, pr=self._ref_p)
            # logger.info("%02d: %6.1f %6.1f > T/S/Dist: %3.1f %3.1f %3.1f [pot.temp. %3.1f]"
            #             % (i, d[i], p, temp_in_situ[i], s_closest, d_closest, t_closest))

            num_values += 1

        if num_values == 0:
            logger.info("no data from lookup!")
            return None

        # ind = np.nanargmin(distances[0])
        # ind2 = np.unravel_index(ind, distances[0].shape)
        # switching to the query location
        # lat_out = latitudes[ind2]
        # lon_out = longitudes[ind2]
        # while lon_out > 180.0:
        #     lon_out -= 360.0

        # Make a new SV object to return our query in
        ssp = Profile()
        ssp.meta.sensor_type = Dicts.sensor_types['Synthetic']
        ssp.meta.probe_type = Dicts.probe_types['RTOFS']
        ssp.meta.latitude = lat
        if lon > 180.0:  # Go back to negative longitude
            lon -= 360.0
        ssp.meta.longitude = lon
        ssp.meta.utc_time = dt(year=dtstamp.year, month=dtstamp.month, day=dtstamp.day,
                               hour=dtstamp.hour, minute=dtstamp.minute, second=dtstamp.second)
        ssp.meta.original_path = "RTOFS_%s" % dtstamp.strftime("%Y%m%d_%H%M%S")
        ssp.init_data(num_values)
        ssp.data.depth = d[0:num_values]
        ssp.data.temp = temp_in_situ[0:num_values]
        ssp.data.sal = sal[0:num_values]
        ssp.calc_data_speed()
        ssp.clone_data_to_proc()
        ssp.init_sis()

        profiles = ProfileList()
        profiles.append_profile(ssp)

        return profiles
import logging

from hyo2.soundspeed.profile.oceanography import Oceanography as Oc
from hyo2.abc.lib.logging import set_logging

ns_list = ["hyo2.soundspeed", "hyo2.soundspeedmanager", "hyo2.soundspeedsettings"]
set_logging(ns_list=ns_list)

logger = logging.getLogger(__name__)

# check values from Fofonoff and Millard(1983)
atg_ck = 3.255976e-4
s_ck = 40.0
t_ck = 40
p_ck = 10000
atg_calc = Oc.atg(s=s_ck, t=t_ck, p=p_ck)
logger.info("Adiabatic Temperature Gradient: %g <> %g" % (atg_calc, atg_ck))

theta_ck = 36.89073
s_ck = 40
t0_ck = 40
p0_ck = 10000
p_ref_ck = 0
theta_calc = Oc.pot_temp(s=s_ck, t=t0_ck, p=p0_ck, pr=p_ref_ck)
logger.info("Theta: %g <> %g" % (theta_calc, theta_ck))
t0_calc = Oc.in_situ_temp(s=s_ck, t=theta_ck, p=p0_ck, pr=p_ref_ck)
logger.info("Temp: %.3f <> %.3f" % (t0_calc, t0_ck))

cr_ck = 1.1
t_ck = 40.0
s_ck = 38.999
# gold ref using the matlab script: generate_gsw_trusted_values.m and GSW 3.05

# - @ 1000m

# absolute salinity
sa = np.array([34.7118, 34.8915, 35.0256, 34.8472, 34.7366, 34.7324])
# conservative temperature
ct = np.array([28.8099, 28.4392, 22.7862, 10.2262, 6.8272, 4.3236])
# sea pressure
p = np.array([10.0, 50.0, 125.0, 250.0, 600.0, 1000.0])
p_ref = 1000.0
# golden reference values
gold_ref = np.array([17.0392, 14.6659, 10.9129, 7.5679, 3.3935, 0])

calc_out = Oc.geo_strf_dyn_height(sa=sa, ct=ct, p=p, p_ref=p_ref)
print("@1000")
print("gold: %s" % gold_ref)
print("calc: %s" % calc_out)
print("diff: %s" % (calc_out - gold_ref))

# - @ 500m

# absolute salinity
sa = np.array([34.7118, 34.8915, 35.0256, 34.8472, 34.7366, 34.7324])
# conservative temperature
ct = np.array([28.8099, 28.4392, 22.7862, 10.2262, 6.8272, 4.3236])
# sea pressure
p = np.array([10.0, 50.0, 125.0, 250.0, 600.0, 1000.0])
p_ref = 500.0
# golden reference values
from hyo2.soundspeed.profile.oceanography import Oceanography as Oc
from hyo2.abc.lib.logging import set_logging

ns_list = [
    "hyo2.soundspeed", "hyo2.soundspeedmanager", "hyo2.soundspeedsettings"
]
set_logging(ns_list=ns_list)

logger = logging.getLogger(__name__)

# check values from Fofonoff and Millard(1983)
trusted_fof_d = 9712.653  # m
trusted_fof_lat = 30.0

# check values dBar from Wong and Zhu(1995), Table III
trusted_fof_s = 35  # ppt
trusted_fof_t = 20  # deg C
trusted_fof_vs = 1687.198  # m/sec

calc_vs = Oc.speed(d=trusted_fof_d,
                   t=trusted_fof_t,
                   s=trusted_fof_s,
                   lat=trusted_fof_lat)
logger.info("Speed: %.3f <> %.3f" % (calc_vs, trusted_fof_vs))

calc_s = Oc.sal(d=trusted_fof_d,
                speed=calc_vs,
                t=trusted_fof_t,
                lat=trusted_fof_lat)
logger.info("Salinity: %.3f <> %.3f" % (calc_s, trusted_fof_s))