blob: 75e2adc8ac9bc52e1afd066eca6d57d43d499bbd [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.
import ocw.utils as utils
import numpy as np
from scipy.stats import percentileofscore, linregress
class Downscaling:
def __init__(self, ref_dataset, model_present, model_future):
'''
: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
ref = np.zeros(model_present.size) # For linear regression, the size of reference data must be same as model data.
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