# 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 | |