Beispiel #1
0
def site():
    return Site(
        name='WRMC BSRN NASA Langley Research Center',
        latitude=37.1048,
        longitude=-76.3872,
        elevation=3.0,
        timezone='Etc/GMT+5',
        site_id='',
        provider='',
        extra_parameters=
        '{"network_api_id": "LRC", "attribution": "Driemel, A., Augustine, J., Behrens, K., Colle, S., Cox, C., Cuevas-Agull\\u00f3, E., Denn, F. M., Duprat, T., Fukuda, M., Grobe, H., Haeffelin, M., Hodges, G., Hyett, N., Ijima, O., Kallis, A., Knap, W., Kustov, V., Long, C. N., Longenecker, D., Lupi, A., Maturilli, M., Mimouni, M., Ntsangwane, L., Ogihara, H., Olano, X., Olefs, M., Omori, M., Passamani, L., Pereira, E. B., Schmith\\u00fcsen, H., Schumacher, S., Sieger, R., Tamlyn, J., Vogt, R., Vuilleumier, L., Xia, X., Ohmura, A., and K\\u00f6nig-Langlo, G.: Baseline Surface Radiation Network (BSRN): structure and data description (1992\\u20132017), Earth Syst. Sci. Data, 10, 1491-1501, doi:10.5194/essd-10-1491-2018, 2018.", "network": "WRMC BSRN", "network_api_abbreviation": "", "observation_interval_length": 1}',  # noqa: E501
    )
def restrict_forecast_upload_window(extra_parameters, get_forecast,
                                    first_time):
    """
    Check that the first_time falls within the window before the
    next initialization time of the forecast from the current time.
    Accounts for forecast lead_time_to_start and interval_label.
    Requires 'read' permission on the forecast in question.

    Parameters
    ----------
    extra_parameters : str
        The extra_parameters string for the forecast. If
        '"restrict_upload": true' is not found in the string, no restriction
        occurs and this function returns immediately.
    get_forecast : func
        Function to get the forecast from the database.
    first_time : datetime-like
        First timestamp in the posted forecast timeseries.

    Raises
    ------
    NotFoundException
        When the user does not have 'read' permission for the forecast or
        it doesn't exist.
    BadAPIRequest
        If the first_time of the timeseries is not consistent for the
        next initaliziation time of the forecast.
    """
    if not _restrict_in_extra(extra_parameters):
        return

    try:
        fx_dict = get_forecast().copy()
    except (StorageAuthError, NotFoundException):
        raise NotFoundException(
            errors={'404': 'Cannot read forecast or forecast does not exist'})
    # we don't care about the axis or constant values for probabilistic
    fx_dict['site'] = Site('name', 0, 0, 0, 'UTC')
    fx = Forecast.from_dict(fx_dict)
    next_issue_time = fx_utils.get_next_issue_time(fx,
                                                   _current_utc_timestamp())
    expected_start = next_issue_time + fx.lead_time_to_start
    if fx.interval_label == 'ending':
        expected_start += fx.interval_length
    if first_time != expected_start:
        raise BadAPIRequest(
            errors={
                'issue_time':
                (f'Currently only accepting forecasts issued for {next_issue_time}.'
                 f' Expecting forecast series to start at {expected_start}.')
            })
def create_site(api, site):
    """Post a new site to the API and create it's applicable reference
    observations.

    Parameters
    ----------
    api : io.APISession
        An APISession with a valid JWT for accessing the Reference Data user.
    site : dict
        Dictionary describing the site to post. This will be instantiated as
        a datamodel.Site object and the value of 'extra_parameters' will be
        serialized to json.

    Returns
    -------
    datamodel.Site
        The created site object.
    """
    # get a reference to network before we serialize extra_parameters
    network = site['extra_parameters']['network']
    network_handler = NETWORKHANDLER_MAP.get(network)
    if network_handler is None:
        logger.warning(f'Unrecognized network, {network} on Site '
                       f'{site["name"]} Observations cannot be '
                       'automatically generated.')
        return
    site.update({'extra_parameters': json.dumps(site['extra_parameters'])})
    site_name = f"{network} {common.clean_name(site['name'])}"
    existing = common.existing_sites(api)
    if site_name in existing:
        logger.info('Site, %s, already exists', site_name)
        created = existing[site_name]
    else:
        site['name'] = site_name
        site_to_create = Site.from_dict(site)
        try:
            created = api.create_site(site_to_create)
        except HTTPError as e:
            logger.error(f"Failed to create Site {site['name']}.")
            logger.debug(f'HTTP Error: {e.response.text}')
            return False
        else:
            logger.info(f'Created Site {created.name} successfully.')
    network_handler.initialize_site_observations(api, created)
    try:
        network_handler.initialize_site_forecasts(api, created)
    except ValueError as e:
        logger.error('Cannot create forecasts for %s: %s', site_name, e)
    return created
Beispiel #4
0
def test_initialize_site_forecasts(mocker, test_site):
    mock_create_fx = mocker.patch(
        'solarforecastarbiter.io.reference_observations.srml.common.'
        'create_forecasts')
    mock_api = mocker.MagicMock()
    srml.initialize_site_forecasts(mock_api, test_site)
    assert 'ac_power' in mock_create_fx.call_args[0][2]
    assert 'dc_power' in mock_create_fx.call_args[0][2]

    regular_site_dict = test_site_dict.copy()
    regular_site_dict.pop('modeling_parameters')
    reg_site = Site.from_dict(regular_site_dict)
    srml.initialize_site_forecasts(mock_api, reg_site)
    assert 'ac_power' not in mock_create_fx.call_args[0][2]
    assert 'dc_power' not in mock_create_fx.call_args[0][2]
Beispiel #5
0
def template_fx(mock_api, mocker):
    mock_api.create_forecast = mocker.MagicMock(side_effect=lambda x: x)
    mock_api.create_probabilistic_forecast = mocker.MagicMock(
        side_effect=lambda x: x)
    site = site_objects[1].replace(latitude=32, longitude=-110)
    template = Forecast(name='Test Template',
                        issue_time_of_day=dt.time(0),
                        lead_time_to_start=pd.Timedelta('1d'),
                        interval_length=pd.Timedelta('1h'),
                        run_length=pd.Timedelta('24h'),
                        interval_label='ending',
                        interval_value_type='interval_mean',
                        variable='ghi',
                        site=Site('dummy', 0, 0, 0, 'MST'),
                        extra_parameters=json.dumps({
                            'is_reference_forecast':
                            True,
                            'model':
                            'gfs_quarter_deg_hourly_to_hourly_mean'
                        }))
    return mock_api, template, site
Beispiel #6
0
def test_decode_extra_parameters_error(site):
    with pytest.raises(ValueError):
        common.decode_extra_parameters(Site.from_dict(site))
Beispiel #7
0
def test_decode_extra_parameters():
    metadata = Site.from_dict(site_string_dicts[0])
    params = common.decode_extra_parameters(metadata)
    assert params['network'] == 'DOE ARM'
    assert params['observation_interval_length'] == 1
Beispiel #8
0
def test_check_network(networks, site, expected):
    metadata = Site.from_dict(site)
    assert common.check_network(networks, metadata) == expected
Beispiel #9
0
def test_create_observation_exists(mock_api, site_objects_param,
                                   observation_objects_param):
    variable = 'ghi'
    site = site_objects_param[0]
    common.create_observation(mock_api, site, variable)
    mock_api.create_observation.assert_not_called()


long_site_name = Site.from_dict({
    'name':
    'ARM site with just abouts sixty four characters in its name oops',
    'latitude':
    1,
    'longitude':
    1,
    'elevation':
    5,
    'timezone':
    'Etc/GMT+8',
    'extra_parameters': ('{"network": "DOE ARM", "network_api_abbreviation": '
                         '"site_abbrev", "network_api_id": "thing", '
                         '"observation_interval_length": 1}'),
})
observation_long_site_name = Observation.from_dict({
    'name':
    'site_abbrev air_temperature',
    'variable':
    'air_temperature',
    'interval_label':
    'ending',
    'interval_value_type':
                                 "network_api_id": 'BMS',
                                 "network_api_abbreviation": 'abbrv'},
        }
    ]]


def expected_site(site):
    new_site = site.copy()
    network = site['extra_parameters'].get('network', '')
    new_site['name'] = f"{network} {site['name']}"
    new_site.update({'extra_parameters': json.dumps(site['extra_parameters'])})
    return new_site


site_string_dicts = [expected_site(site) for site in site_dicts()]
site_objects = [Site.from_dict(site) for site in site_string_dicts]


@pytest.fixture
def site_dicts_param():
    return site_string_dicts


@pytest.fixture
def site_objects_param():
    return site_objects


def site_to_obs(site):
    ep = json.loads(site.extra_parameters)
    interval_length = ep['observation_interval_length']
from solarforecastarbiter.datamodel import (Forecast, Site,
                                            ProbabilisticForecast)
from solarforecastarbiter.io.fetch.nwp import DOMAIN


def is_in_nwp_domain(site):
    """
    Checks the location of the site and returns True if it is within the
    domain of the NWP forecasts.
    """
    return ((DOMAIN['leftlon'] <= site.longitude <= DOMAIN['rightlon'])
            and (DOMAIN['bottomlat'] <= site.latitude <= DOMAIN['toplat']))


_DUMMY_SITE = Site('dummy', 0, 0, 0, 'UTC')

# TODO: add poa globa, maybe relative humidity
CURRENT_NWP_VARIABLES = {
    'ac_power', 'ghi', 'dni', 'dhi', 'air_temperature', 'wind_speed'
}

# issue time of day is in local standard time and will be
# adjusted to the appropriate UTC hour
TEMPLATE_DETERMINISTIC_NWP_FORECASTS = [
    Forecast(name='Day Ahead GFS',
             issue_time_of_day=dt.time(0),
             lead_time_to_start=pd.Timedelta('1d'),
             interval_length=pd.Timedelta('1h'),
             run_length=pd.Timedelta('24h'),
             interval_label='ending',
Beispiel #12
0
        "ac_capacity": 0.02,
        "ac_loss_factor": 0.0,
        "dc_capacity": 0.02,
        "dc_loss_factor": 0.0,
        "surface_azimuth": 180.0,
        "surface_tilt": 15.0,
        "temperature_coefficient": 0.3,
        "tracking_type": "fixed"
    },
    "name": "Ashland OR PV",
    "timezone": "Etc/GMT+8",
    "provider": "",
    "site_id": "",
}

test_site_object = Site.from_dict(test_site_dict)


@pytest.fixture()
def test_site():
    return test_site_object


srml_df = pd.DataFrame({
    'ghi_1': {
        Timestamp('2020-03-01 00:00:00-0800', tz='Etc/GMT+8'): 0.0
    },
    'ghi_1_flag': {
        Timestamp('2020-03-01 00:00:00-0800', tz='Etc/GMT+8'): 11
    },
    'dni_1': {