blob: f3d701f20002679e2a8d65edc06e985f54bdece6 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""
Classes:
Downscaling - Container for applying statistical downscaling.
"""
import numpy as np
from scipy.stats import linregress, percentileofscore
class Downscaling(object):
"""
Statistical downscaling infers higher resolution information from lower resolution data.
For example, data collected at a more coarse regional level applied to a more refined
local level.
Statistical downscaling establishes a relationship between different variables in the large scale
and the local scale and applies that relationship to the local scale.
"""
def __init__(self, ref_dataset, model_present, model_future):
""" Default Downscaling constructor.
:param ref_dataset: The Dataset to use as the reference dataset (observation)
:type ref_dataset: Dataset
:param model_present: model simulation to be compared with observation
:type model_present: Dataset
:param model_future: model simulation to be calibrated for prediction
:type model_future: Dataset
"""
self.ref_dataset = ref_dataset[~ref_dataset.mask].ravel()
self.model_present = model_present.ravel()
self.model_future = model_future.ravel()
description = "statistical downscaling methods"
def Delta_addition(self):
"""Calculate the mean difference between future and present simulation,
then add the difference to the observed distribution
:returns: downscaled model_present and model_future
"""
ref = self.ref_dataset
model_present = self.model_present
model_future = self.model_future
return model_present, ref + np.mean(model_future - model_present)
def Delta_correction(self):
"""Calculate the mean difference between observation and present simulation,
then add the difference to the future distribution
:returns: downscaled model_present and model_future
"""
ref = self.ref_dataset
model_present = self.model_present
model_future = self.model_future
return model_present + np.mean(ref) - np.mean(model_present), model_future + \
np.mean(ref) - np.mean(model_present)
def Quantile_mapping(self):
"""Remove the biases for each quantile value
Wood et al (2004) HYDROLOGIC IMPLICATIONS OF DYNAMICAL
AND STATISTICAL APPROACHES TO DOWNSCALING CLIMATE MODEL OUTPUTS
:returns: downscaled model_present and model_future
"""
ref = self.ref_dataset
model_present = self.model_present
model_present_corrected = np.zeros(model_present.size)
model_future = self.model_future
model_future_corrected = np.zeros(model_future.size)
for ival, model_value in enumerate(model_present):
percentile = percentileofscore(model_present, model_value)
model_present_corrected[ival] = np.percentile(ref, percentile)
for ival, model_value in enumerate(model_future):
percentile = percentileofscore(model_future, model_value)
model_future_corrected[ival] = model_value + np.percentile(
ref, percentile) - np.percentile(model_present, percentile)
return model_present_corrected, model_future_corrected
def Asynchronous_regression(self):
"""Remove the biases by fitting a linear regression model with ordered observational and
model datasets
Stoner et al (2013) An asynchronous regional regression model for statistical downscaling of
daily climate variables
:returns: downscaled model_present and model_future
"""
ref_original = self.ref_dataset
model_present = self.model_present
model_present_sorted = np.sort(model_present)
model_future = self.model_future
# For linear regression, the size of reference data must be same as
# model data.
ref = np.zeros(model_present.size)
for ival, model_value in enumerate(model_present_sorted):
percentile = percentileofscore(model_present_sorted, model_value)
ref[ival] = np.percentile(ref_original, percentile)
slope, intercept = linregress(model_present_sorted, ref)[0:2]
return model_present * slope + intercept, model_future * slope + intercept