'''
/***************************************************************************
Name       :  geowrsi_worker.py
Description:  Worker for GeoWRSI Tool
copyright  :  (C) 2022-2023 by FEWS
email      :  dhackman@contractor.usgs.gov
Author     :  Derek Hackman
Modified   :  mm/dd/yyyy - descripton - Description

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
'''
import os

import numpy as np

from PyQt5 import QtCore

from qgis.core import Qgis, QgsMessageLog

from fews_tools import fews_tools_config as config
from fews_tools.utilities import geoclim_gdal_utilities as gdal_util
from fews_tools.utilities import geoclim_utilities as util
from fews_tools.utilities import geowrsi_utilities as geo_util


class GeoWRSIWorker(QtCore.QObject):
    '''
    GeoWRSI worker class
    '''

    def __init__(self, wrksp_setup, set_dic, reg_dic, crop_dic, output_dic):
        QtCore.QObject.__init__(self)
        self.wrksp_setup = wrksp_setup
        self.set_dic = set_dic
        self.reg_dic = reg_dic
        self.crop_dic = crop_dic
        self.output_dic = output_dic
        self.output_file_path =\
            self.wrksp_setup.get_output_path()
        self.killed = False

    def kill(self):
        """
        Set kill flag to true to stop processing.
        """
        self.killed = True

    def calc_avg_med_for_extended(self, stat_type, dict_key,
                                  ignore_vals=False, sos=False):
        """
        Calculate the average or median for extended years
        params(string) - stat_type - either 'Average' or 'Median' or '' if SOS
        params(string) - dict_type - string of which file name is having the
            calculations ran for
        params(bool) - ignore_vals - if we want to ignore the 253, 254, 255
            values for Yet to Start, No Start, No Data for the files that have
            these in them
        params(bool) - sos - if true we run the sos mode calc instead
        return(2-D cube) - final_ext_cube
        """
        files_list = []
        for year in self.set_dic['ext_years_list']:
            files_list.append(
                self.set_dic['ext_output_files_dict'][year][dict_key])
        # Set the PPT data cube and fill it with data
        ext_data_cube =\
            geo_util.fill_data_cube_from_files(self.reg_dic,
                                               files_list,
                                               self.output_file_path)
        if sos:
            # Call geo_util.calc_avg_med_1d_for_extended
            final_ext_cube =\
                np.apply_along_axis(geo_util.calc_sos_mode_1d_for_extended, 0,
                                    ext_data_cube,
                                    self.reg_dic['PeriodType'],
                                    self.set_dic['cross_year'])
        else:
            # Call geo_util.calc_avg_med_1d_for_extended
            final_ext_cube =\
                np.apply_along_axis(geo_util.calc_avg_med_1d_for_extended, 0,
                                    ext_data_cube,
                                    stat_type,
                                    ignore_vals)
        return final_ext_cube

    def calc_avg_med_for_list_extended(self, stat_type, dict_key,
                                       index, ignore_vals=False):
        """
        Calculate the average or median for extended years for a file list
        by passing in the index of the list
        params(string) - stat_type - either 'Average' or 'Median' or '' if SOS
        params(string) - dict_type - string of which file name is having the
            calculations ran for
        params(int) - index - index number to get the files to avg for in list
        params(bool) - ignore_vals - if we want to ignore the 253, 254, 255
            values for Yet to Start, No Start, No Data for the files that have
            these in them
        return(2-D cube) - final_ext_cube
        """
        files_list = []
        for year in self.set_dic['ext_years_list']:
            files_list.append(
                self.set_dic['ext_output_files_dict'][year][dict_key][index])
        # Set the PPT data cube and fill it with data
        ext_data_cube =\
            geo_util.fill_data_cube_from_files(self.reg_dic,
                                               files_list,
                                               self.output_file_path)
        # Call geo_util.calc_avg_med_1d_for_extended
        final_ext_cube =\
            np.apply_along_axis(geo_util.calc_avg_med_1d_for_extended, 0,
                                ext_data_cube,
                                stat_type,
                                ignore_vals)
        return final_ext_cube

    def run(self):
        '''
        Run the geowrsi function
        '''
        ret_tuple = None
        err = False
        try:
            prog_divisor = 1
            start_progress = 0
            if self.set_dic['forecast_run']:
                prog_divisor += 1
            if self.set_dic['ext_avg_run'] or self.set_dic['ext_med_run']:
                for _ in self.set_dic['ext_years_list']:
                    prog_divisor += 1
                prog_divisor += 1  # Add one more for the avg/med calcs
            if self.set_dic['wrsi_run_type'] == config.MULTI_HISTORICAL:
                for _ in self.set_dic['hist_years_list']:
                    prog_divisor += 1
            # Clear temp folder to makes sure all files
            # are resampled to region
            QgsMessageLog.logMessage(u"Clearing the temp folder",
                                     level=Qgis.Info)
            util.remove_temp_files(self.output_file_path)

            # Start resampling the needed files
            QgsMessageLog.logMessage(u"Resampling and gathering data",
                                     level=Qgis.Info)
            # Set the resampled mask
            resampled_mask, _ = \
                gdal_util.resample_input_files(self.output_file_path,
                                               self.set_dic['mask_file'],
                                               [], self.reg_dic)
            if self.killed is True:
                raise KeyboardInterrupt
            if not os.path.exists(resampled_mask):
                QgsMessageLog.logMessage(u'Mask File Error!! '
                                         'Error resampling the mask file',
                                         level=Qgis.Info)
                raise RuntimeError
            # Set resampled Clim WRSI
            clim_wrsi_cube =\
                geo_util.fill_data_cube_from_files(self.reg_dic,
                                                   [self.reg_dic["WRSI"]],
                                                   self.output_file_path)
            # Set resampled Clim SOS
            clim_sos_cube =\
                geo_util.fill_data_cube_from_files(self.reg_dic,
                                                   [self.reg_dic["SOS"]],
                                                   self.output_file_path)
            if self.killed is True:
                raise KeyboardInterrupt
            self.progress.emit(int(5/prog_divisor))
            # Create lgp data Cube
            lgp_data_cube = geo_util.fill_lgp(self.set_dic, self.reg_dic,
                                              resampled_mask,
                                              self.output_file_path)
            if self.killed is True:
                raise KeyboardInterrupt
            self.progress.emit(int(10/prog_divisor))
            # Create sos data cube
            sos_data_cube = geo_util.fill_sos(self.set_dic, self.reg_dic,
                                              resampled_mask,
                                              self.output_file_path)
            if self.killed is True:
                raise KeyboardInterrupt
            self.progress.emit(int(15/prog_divisor))
            # Create WHC data Cube
            whc_data_cube = geo_util.fill_whc(self.set_dic, self.reg_dic,
                                              resampled_mask,
                                              self.output_file_path)
            if self.killed is True:
                raise KeyboardInterrupt
            self.progress.emit(int(20/prog_divisor))
            # Create Mask data cube
            mask_data_cube = geo_util.fill_mask(resampled_mask)
            if self.killed is True:
                raise KeyboardInterrupt
            self.progress.emit(int(25/prog_divisor))
            # This extra_periods variable is used for calc_sos if needed and
            # for writing out to files later on so define it every time
            if self.reg_dic['PeriodType'] == 'Dekadal':
                extra_periods = config.DEKAD_SHIFT
            elif self.reg_dic['PeriodType'] == 'Pentadal':
                extra_periods = config.PENTAD_SHIFT
            else:
                QgsMessageLog.logMessage(u'Incorrect Region Period Type!! '
                                         'Must be "Dekadal" or "Pentadal"',
                                         level=Qgis.Info)
                raise RuntimeError
            # Setup the parameters for writing to files
            _, row_ct, col_ct, geoxform, _ = \
                gdal_util.get_geotiff_info(resampled_mask)
            gd_data_type = gdal_util.TYPE_DIC["Float32"]["GDAL"]

            if self.set_dic['wrsi_run_type'] == config.MULTI_HISTORICAL:
                for year in self.set_dic['hist_years_list']:
                    # Start by stacking all of the cubes for hist year
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 30/prog_divisor))
                    # Set the PPT data cube and fill it with historical data
                    # for the year
                    ppt_data_cube =\
                        geo_util.fill_data_cube_from_files(
                            self.reg_dic,
                            self.set_dic['hist_ppt_data_dict'][year],
                            self.output_file_path)
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 45/prog_divisor))
                    # Set the PET data cube and fill it with historical data
                    # for the year
                    pet_data_cube =\
                        geo_util.fill_data_cube_from_files(
                            self.reg_dic,
                            self.set_dic['hist_pet_data_dict'][year],
                            self.output_file_path)
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 60/prog_divisor))
                    # Stack the data cubes
                    cubes_arr = []
                    cubes_arr.append(ppt_data_cube)
                    cubes_arr.append(pet_data_cube)
                    cubes_arr.append(lgp_data_cube)
                    cubes_arr.append(whc_data_cube)
                    cubes_arr.append(sos_data_cube)
                    cubes_arr.append(mask_data_cube)
                    stacked_cube = geo_util.stack_cubes(cubes_arr)
                    periods, _, _ = ppt_data_cube.shape

                    if self.set_dic['sos_type'] == 'Calculated':
                        QgsMessageLog.logMessage(
                            u"Calculating historical SOS for " + year,
                            level=Qgis.Info)
                        stacked_cube = geo_util.calc_current_sos(
                            stacked_cube, self.reg_dic, self.set_dic,
                            extra_periods, periods)
                    QgsMessageLog.logMessage(
                        u"Begin calculating historical WRSI for " + year,
                        level=Qgis.Info)

                    # Call geo_util.run_geowrsi_historical function to run
                    # the wrsi for each historical year since we have full
                    # set of data
                    (wrsi_cube, swi_cube, lgp_phen_cube,
                        hist_output_cube, crop_stages_cube) =\
                        np.apply_along_axis(
                            geo_util.run_geowrsi_historical, 0,
                            stacked_cube,
                            self.crop_dic, periods,
                            self.set_dic['initial_period'],
                            self.set_dic['final_period'],
                            self.set_dic['cross_year'],
                            self.reg_dic['PeriodType'])
                    if self.killed is True:
                        raise KeyboardInterrupt
                    # Calculate WRSI Anomaly
                    mask = gdal_util.get_inverted_mask_array(
                        resampled_mask)
                    wrsi_arr = hist_output_cube[0]
                    wrsi_anom = geo_util.anomaly_calc(
                        wrsi_arr,
                        self.reg_dic,
                        mask,
                        clim_wrsi_cube[0],
                        "WRSI",
                        self.set_dic['cross_year'])
                    wrsi_anom[wrsi_anom == -9999] = config.NO_DATA

                    # Calculate SOS anomaly
                    sos_arr = stacked_cube[-2]
                    sos_anom = geo_util.anomaly_calc(
                        sos_arr,
                        self.reg_dic,
                        mask,
                        clim_sos_cube[0],
                        "SOS",
                        self.set_dic['cross_year'])

                    self.progress.emit(int(start_progress + 75/prog_divisor))
                    QgsMessageLog.logMessage(
                        u"Writing historical output files for "
                        + year,
                        level=Qgis.Info)
                    # Write the wrsi_cube out to a file for each needed
                    # output period this will allow first 6 dekads or 12
                    # pentads from data cube that represent the preseason
                    # to be skipped and the extra periods after the
                    # eos + 6 to be ignored
                    if self.output_dic['save_every_wrsi']:
                        for index, file in enumerate(self.set_dic[
                                'hist_output_files_dict'][year]
                                ['output_file_list_wrsi'],
                                extra_periods):
                            err = gdal_util.write_file(
                                file, wrsi_cube[index], col_ct,
                                row_ct, geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 80/prog_divisor))

                    # Write the swi_cube out to a file for each needed
                    # output period this will allow first 6 dekads or 12
                    # pentads from data cube that represent the preseason
                    # to be skipped and the extra periods after the
                    # eos + 6 to be ignored
                    if self.output_dic['save_every_soil_water_index']:
                        for index, file in enumerate(self.set_dic[
                                'hist_output_files_dict'][year]
                                ['output_file_list_swi'],
                                extra_periods):
                            err = gdal_util.write_file(
                                file, swi_cube[index], col_ct,
                                row_ct, geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 83/prog_divisor))

                    # Write the lgp_phen_cube out to file for each needed
                    # output period this will allow first 6 dekads or 12
                    # pentads from data cube that represent the preseason
                    # to be skipped and the extra periods after the
                    # eos + 6 to be ignored
                    if self.output_dic['save_every_lgp_phenology']:
                        for index, file in enumerate(self.set_dic[
                                'hist_output_files_dict'][year]
                                ['output_file_list_lgp_phen'],
                                extra_periods):
                            err = gdal_util.write_file(
                                file, lgp_phen_cube[index],
                                col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 86/prog_divisor))

                    # Write out the wrsi 2d array to the historical file
                    if self.output_dic['eos_wrsi']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_wrsi_eos'],
                            hist_output_cube[0], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the wrsi anom 2d array to the historical file
                    if self.output_dic['eos_wrsi_anomaly']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_wrsi_anom_eos'],
                            wrsi_anom, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the sos 2d array to the historical file
                    err = gdal_util.write_file(
                        self.set_dic['hist_output_files_dict'][year]
                        ['output_file_sos'],
                        sos_arr, col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the sos anom 2d array to the historical file
                    err = gdal_util.write_file(
                        self.set_dic['hist_output_files_dict'][year]
                        ['output_file_sos_anom'],
                        sos_anom, col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the lgp_phen 2d array to the historical file
                    if self.output_dic['eos_lgp_phenology']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_lgp_phen_eos'],
                            hist_output_cube[2], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the swi 2d array to the historical file
                    if self.output_dic['eos_soil_water_index']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_swi_eos'],
                            hist_output_cube[3], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the water_req_total 2d array
                    # to the historical file
                    if self.output_dic['eos_water_req_totals']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_water_req_tot_eos'],
                            hist_output_cube[4], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the max_water_deficit 2d array
                    # to the historical file
                    if self.output_dic['eos_max_water_deficits']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_max_water_def_eos'],
                            hist_output_cube[5], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the water_deficit_total 2d array
                    # to the historical file
                    if self.output_dic['eos_water_deficit_totals']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_water_def_tot_eos'],
                            hist_output_cube[6], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the max_water_surplus 2d array
                    # to the historical file
                    if self.output_dic['eos_max_water_surplus']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_max_water_surp_eos'],
                            hist_output_cube[7], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the water_surplus_total 2d array 
                    # to the historical file
                    if self.output_dic['eos_water_surplus_totals']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_water_surp_tot_eos'],
                            hist_output_cube[8], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the aet_total 2d array to the historical file
                    if self.output_dic['eos_aet_totals']:
                        err = gdal_util.write_file(self.set_dic[
                            'hist_output_files_dict'][year]
                            ['output_file_aet_tot_eos'],
                            hist_output_cube[9], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the crop stages cube to the historical files
                    if self.output_dic['save_crop_stage_totals_eos']:
                        for index, file in enumerate(self.set_dic[
                                'hist_output_files_dict'][year]
                                ['output_file_list_crop_stages']):
                            err = gdal_util.write_file(
                                file, crop_stages_cube[index],
                                col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                    self.progress.emit(int(start_progress + 90/prog_divisor))
                    start_progress = start_progress + 90/prog_divisor

            elif self.set_dic['wrsi_run_type'] == config.HISTORICAL:
                # Set the PPT data cube and fill it with data
                ppt_data_cube =\
                    geo_util.fill_data_cube_from_files(
                        self.reg_dic,
                        self.set_dic['available_files_list_ppt'],
                        self.output_file_path)
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(40/prog_divisor))
                # Set the PET data cube and fill it with data
                pet_data_cube =\
                    geo_util.fill_data_cube_from_files(
                        self.reg_dic,
                        self.set_dic['available_files_list_pet'],
                        self.output_file_path)
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(60/prog_divisor))
                # Stack the data cubes
                cubes_arr = []
                cubes_arr.append(ppt_data_cube)
                cubes_arr.append(pet_data_cube)
                cubes_arr.append(lgp_data_cube)
                cubes_arr.append(whc_data_cube)
                cubes_arr.append(sos_data_cube)
                cubes_arr.append(mask_data_cube)
                stacked_cube = geo_util.stack_cubes(cubes_arr)
                periods, _, _ = ppt_data_cube.shape
                if self.set_dic['sos_type'] == 'Calculated':
                    QgsMessageLog.logMessage(u"Calculating SOS",
                                             level=Qgis.Info)
                    stacked_cube = geo_util.calc_sos(
                        stacked_cube, self.reg_dic, self.set_dic, extra_periods,
                        periods)
                QgsMessageLog.logMessage(u"Begin calculating WRSI",
                                         level=Qgis.Info)
                # Call geo_util.run_geowrsi_historical function to get wrsi
                (wrsi_cube, swi_cube, lgp_phen_cube,
                 eos_output_cube, crop_stages_cube) =\
                    np.apply_along_axis(geo_util.run_geowrsi_historical, 0,
                                        stacked_cube,
                                        self.crop_dic, periods,
                                        self.set_dic['initial_period'],
                                        self.set_dic['final_period'],
                                        self.set_dic['cross_year'],
                                        self.reg_dic['PeriodType'])
                if self.killed is True:
                    raise KeyboardInterrupt

                # Calculate WRSI Anomaly
                mask = gdal_util.get_inverted_mask_array(resampled_mask)
                wrsi_arr = eos_output_cube[0]
                wrsi_anom = geo_util.anomaly_calc(wrsi_arr,
                                                  self.reg_dic,
                                                  mask,
                                                  clim_wrsi_cube[0],
                                                  "WRSI",
                                                  self.set_dic['cross_year'])
                wrsi_anom[wrsi_anom == -9999] = config.NO_DATA

                # Calculate SOS anomaly
                sos_arr = stacked_cube[-2]
                sos_anom = geo_util.anomaly_calc(sos_arr,
                                                 self.reg_dic,
                                                 mask,
                                                 clim_sos_cube[0],
                                                 "SOS",
                                                 self.set_dic['cross_year'])

                self.progress.emit(int(75/prog_divisor))
                QgsMessageLog.logMessage(u"Writing output files",
                                         level=Qgis.Info)

                # Write the wrsi_cube out to a file for each needed output
                # period this will allow first 6 dekads or 12 pentads from data
                # cube that represent the preseason to be skipped and the extra
                # periods after the eos + 6 to be ignored
                if self.output_dic['save_every_wrsi']:
                    for index, file in enumerate(self.set_dic[
                            'output_file_list_wrsi'],
                            extra_periods):
                        err = gdal_util.write_file(
                            file, wrsi_cube[index], col_ct,
                            row_ct, geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(80/prog_divisor))

                # Write the swi_cube out to a file for each needed output
                # period this will allow first 6 dekads or 12 pentads from data
                # cube that represent the preseason to be skipped and the extra
                # periods after the eos + 6 to be ignored
                if self.output_dic['save_every_soil_water_index']:
                    for index, file in enumerate(self.set_dic[
                            'output_file_list_swi'],
                            extra_periods):
                        err = gdal_util.write_file(
                            file, swi_cube[index], col_ct,
                            row_ct, geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(83/prog_divisor))

                # Write the lgp_phen_cube out to file for each needed output
                # period this will allow first 6 dekads or 12 pentads from data
                # cube that represent the preseason to be skipped and the extra
                # periods after the eos + 6 to be ignored
                if self.output_dic['save_every_lgp_phenology']:
                    for index, file in enumerate(self.set_dic[
                            'output_file_list_lgp_phen'],
                            extra_periods):
                        err = gdal_util.write_file(file, lgp_phen_cube[index],
                                                   col_ct, row_ct,
                                                   geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(86/prog_divisor))

                # Write out the wrsi_eos 2d array to the eos file
                if self.output_dic['eos_wrsi']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_wrsi_eos'],
                        eos_output_cube[0], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the wrsi_eos anom 2d array to the eos file
                if self.output_dic['eos_wrsi_anomaly']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_wrsi_anom_eos'],
                        wrsi_anom, col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                err = gdal_util.write_file(self.set_dic['output_file_sos'],
                                           sos_arr, col_ct, row_ct,
                                           geoxform, gd_data_type)
                if err is True:
                    raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                err = gdal_util.write_file(self.set_dic['output_file_sos_anom'],
                                           sos_anom, col_ct, row_ct,
                                           geoxform, gd_data_type)
                if err is True:
                    raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the lgp_phen_eos 2d array to the eos file
                if self.output_dic['eos_lgp_phenology']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_lgp_phen_eos'],
                        eos_output_cube[2], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the swi_eos 2d array to the eos file
                if self.output_dic['eos_soil_water_index']:
                    err = gdal_util.write_file(
                        self.set_dic['output_file_swi_eos'],
                        eos_output_cube[3], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the water_req_total 2d array to the eos file
                if self.output_dic['eos_water_req_totals']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_water_req_tot_eos'],
                        eos_output_cube[4], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the max_water_deficit 2d array to the eos file
                if self.output_dic['eos_max_water_deficits']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_max_water_def_eos'],
                        eos_output_cube[5], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the water_deficit_total 2d array to the eos file
                if self.output_dic['eos_water_deficit_totals']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_water_def_tot_eos'],
                        eos_output_cube[6], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the max_water_surplus 2d array to the eos file
                if self.output_dic['eos_max_water_surplus']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_max_water_surp_eos'],
                        eos_output_cube[7], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the water_surplus_total 2d array to the eos file
                if self.output_dic['eos_water_surplus_totals']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_water_surp_tot_eos'],
                        eos_output_cube[8], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the aet_total 2d array to the eos file
                if self.output_dic['eos_aet_totals']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_aet_tot_eos'],
                        eos_output_cube[9], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(90/prog_divisor))

                if self.output_dic['save_crop_stage_totals_eos']:
                    for index, file in enumerate(self.set_dic[
                            'output_file_list_crop_stages']):
                        err = gdal_util.write_file(
                            file, crop_stages_cube[index],
                            col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
            else:  # Running the WRSI to Current
                # Set the PPT data cube and fill it with data
                ppt_data_cube =\
                    geo_util.fill_data_cube_from_files(
                        self.reg_dic,
                        self.set_dic['available_files_list_ppt'],
                        self.output_file_path)
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(40/prog_divisor))
                # Set the PET data cube and fill it with data
                pet_data_cube =\
                    geo_util.fill_data_cube_from_files(
                        self.reg_dic,
                        self.set_dic['available_files_list_pet'],
                        self.output_file_path)
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(60/prog_divisor))
                # Stack the data cubes
                cubes_arr = []
                cubes_arr.append(ppt_data_cube)
                cubes_arr.append(pet_data_cube)
                cubes_arr.append(lgp_data_cube)
                cubes_arr.append(whc_data_cube)
                cubes_arr.append(sos_data_cube)
                cubes_arr.append(mask_data_cube)
                stacked_cube = geo_util.stack_cubes(cubes_arr)
                periods, _, _ = ppt_data_cube.shape
                if self.set_dic['sos_type'] == 'Calculated':
                    QgsMessageLog.logMessage(u"Calculating Current SOS",
                                             level=Qgis.Info)
                    stacked_cube = geo_util.calc_current_sos(
                        stacked_cube, self.reg_dic, self.set_dic, extra_periods,
                        periods)
                QgsMessageLog.logMessage(u"Begin calculating Current WRSI",
                                         level=Qgis.Info)
                # Call geo_util.run_geowrsi_current function to get wrsi
                (wrsi_cube, swi_cube, lgp_phen_cube,
                 cur_output_cube) =\
                    np.apply_along_axis(geo_util.run_geowrsi_current, 0,
                                        stacked_cube,
                                        self.crop_dic, periods,
                                        self.set_dic['initial_period'],
                                        self.set_dic['final_period'],
                                        self.set_dic['cross_year'],
                                        self.reg_dic['PeriodType'])
                if self.killed is True:
                    raise KeyboardInterrupt

                # Calculate WRSI Anomaly
                mask = gdal_util.get_inverted_mask_array(resampled_mask)
                wrsi_arr = cur_output_cube[0]
                wrsi_anom = geo_util.anomaly_calc(wrsi_arr,
                                                  self.reg_dic,
                                                  mask,
                                                  clim_wrsi_cube[0],
                                                  "WRSI",
                                                  self.set_dic['cross_year'])
                wrsi_anom[wrsi_anom == -9999] = config.NO_DATA

                # Calculate SOS anomaly
                sos_arr = stacked_cube[-2]
                sos_anom = geo_util.anomaly_calc(sos_arr,
                                                 self.reg_dic,
                                                 mask,
                                                 clim_sos_cube[0],
                                                 "SOS",
                                                 self.set_dic['cross_year'])

                self.progress.emit(int(75/prog_divisor))
                QgsMessageLog.logMessage(u"Writing Current output files",
                                         level=Qgis.Info)

                # Write the wrsi_cube out to a file for each needed output
                # period this will allow first 6 dekads or 12 pentads from data
                # cube that represent the preseason to be skipped and the extra
                # periods after the eos + 6 to be ignored
                if self.output_dic['save_every_wrsi']:
                    for index, file in enumerate(self.set_dic[
                            'output_file_list_wrsi_cur'],
                            extra_periods):
                        err = gdal_util.write_file(
                            file, wrsi_cube[index], col_ct,
                            row_ct, geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(80/prog_divisor))

                # Write the swi_cube out to a file for each needed output 
                # period this will allow first 6 dekads or 12 pentads from data
                # cube that represent the preseason to be skipped and the extra
                # periods after the eos + 6 to be ignored
                if self.output_dic['save_every_soil_water_index']:
                    for index, file in enumerate(self.set_dic[
                            'output_file_list_swi_cur'],
                            extra_periods):
                        err = gdal_util.write_file(
                            file, swi_cube[index], col_ct,
                            row_ct, geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(83/prog_divisor))

                # Write the lgp_phen_cube out to file for each needed output
                # period this will allow first 6 dekads or 12 pentads from data
                # cube that represent the preseason to be skipped and the extra
                # periods after the eos + 6 to be ignored
                if self.output_dic['save_every_lgp_phenology']:
                    for index, file in enumerate(self.set_dic[
                            'output_file_list_lgp_phen_cur'],
                            extra_periods):
                        err = gdal_util.write_file(file, lgp_phen_cube[index],
                                                   col_ct, row_ct,
                                                   geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(86/prog_divisor))

                # Write out the wrsi_cur 2d array to the cur file
                if self.output_dic['current_wrsi']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_wrsi_cur'],
                        cur_output_cube[0], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the wrsi_cur anom 2d array to the cur file
                if self.output_dic['current_wrsi_anomaly']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_wrsi_anom_cur'],
                        wrsi_anom, col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                err = gdal_util.write_file(self.set_dic['output_file_sos_cur'],
                                           sos_arr, col_ct, row_ct,
                                           geoxform, gd_data_type)
                if err is True:
                    raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                err = gdal_util.write_file(
                    self.set_dic['output_file_sos_anom_cur'],
                    sos_anom, col_ct, row_ct,
                    geoxform, gd_data_type)
                if err is True:
                    raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the lgp_phen_cur 2d array to the cur file
                if self.output_dic['current_lgp_phenology']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_lgp_phen_cur'],
                        cur_output_cube[2], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the swi_cur 2d array to the cur file
                if self.output_dic['current_soil_water_index']:
                    err = gdal_util.write_file(
                        self.set_dic['output_file_swi_cur'],
                        cur_output_cube[3], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the water_req_total 2d array to the cur file
                if self.output_dic['current_water_req_totals']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_water_req_tot_cur'],
                        cur_output_cube[4], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the max_water_deficit 2d array to the cur file
                if self.output_dic['current_max_water_deficits']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_max_water_def_cur'],
                        cur_output_cube[5], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the water_deficit_total 2d array to the cur file
                if self.output_dic['current_water_deficit_totals']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_water_def_tot_cur'],
                        cur_output_cube[6], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the max_water_surplus 2d array to the cur file
                if self.output_dic['current_max_water_surplus']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_max_water_surp_cur'],
                        cur_output_cube[7], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the water_surplus_total 2d array to the cur file
                if self.output_dic['current_water_surplus_totals']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_water_surp_tot_cur'],
                        cur_output_cube[8], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt

                # Write out the aet_total 2d array to the cur file
                if self.output_dic['current_aet_totals']:
                    err = gdal_util.write_file(self.set_dic[
                        'output_file_aet_tot_cur'],
                        cur_output_cube[9], col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                if self.killed is True:
                    raise KeyboardInterrupt
                self.progress.emit(int(90/prog_divisor))

                # if forecast run we will now go through the forecast setup
                # and calculations
                if self.set_dic['forecast_run']:
                    start_progress = 90/prog_divisor
                    # Start by restacking all of the cubes adding the forecast
                    # data to them
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 10/prog_divisor))
                    # add forecast ppt dekad to file list
                    forecast_ppt_file_list = \
                        self.set_dic['available_files_list_ppt']
                    forecast_ppt_file_list.append(
                        self.set_dic['forecast_ppt_file'])
                    # Set the PPT data cube and fill it with data
                    ppt_data_cube =\
                        geo_util.fill_data_cube_from_files(
                            self.reg_dic,
                            forecast_ppt_file_list,
                            self.output_file_path)
                    forecast_ppt_file_list.pop()
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 35/prog_divisor))
                    # add forecast ppt dekad to file list
                    forecast_pet_file_list = \
                        self.set_dic['available_files_list_pet']
                    forecast_pet_file_list.append(
                        self.set_dic['forecast_pet_avg_file'])
                    # Set the PET data cube and fill it with data
                    pet_data_cube =\
                        geo_util.fill_data_cube_from_files(
                            self.reg_dic,
                            forecast_pet_file_list,
                            self.output_file_path)
                    forecast_pet_file_list.pop()
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 60/prog_divisor))
                    # Stack the data cubes
                    cubes_arr = []
                    cubes_arr.append(ppt_data_cube)
                    cubes_arr.append(pet_data_cube)
                    cubes_arr.append(lgp_data_cube)
                    cubes_arr.append(whc_data_cube)
                    cubes_arr.append(sos_data_cube)
                    cubes_arr.append(mask_data_cube)
                    stacked_cube = geo_util.stack_cubes(cubes_arr)
                    periods, _, _ = ppt_data_cube.shape

                    if self.set_dic['sos_type'] == 'Calculated':
                        QgsMessageLog.logMessage(u"Calculating Forecast SOS",
                                                 level=Qgis.Info)
                        stacked_cube = geo_util.calc_current_sos(
                            stacked_cube, self.reg_dic, self.set_dic,
                            extra_periods, periods)
                    QgsMessageLog.logMessage(u"Begin calculating Forecast WRSI",
                                             level=Qgis.Info)
                    # Call geo_util.run_geowrsi_current function since it is
                    # the same logic for the forecast, just with an additional
                    # period of PPT and PET data
                    (wrsi_cube, swi_cube, lgp_phen_cube,
                     for_output_cube) =\
                        np.apply_along_axis(geo_util.run_geowrsi_current, 0,
                                            stacked_cube,
                                            self.crop_dic, periods,
                                            self.set_dic['initial_period'],
                                            self.set_dic['final_period'],
                                            self.set_dic['cross_year'],
                                            self.reg_dic['PeriodType'])
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Calculate WRSI Anomaly
                    mask = gdal_util.get_inverted_mask_array(resampled_mask)
                    wrsi_arr = for_output_cube[0]
                    wrsi_anom = geo_util.anomaly_calc(
                        wrsi_arr, self.reg_dic, mask, clim_wrsi_cube[0],
                        "WRSI", self.set_dic['cross_year'])
                    wrsi_anom[wrsi_anom == -9999] = config.NO_DATA

                    # Calculate SOS anomaly
                    sos_arr = stacked_cube[-2]
                    sos_anom = geo_util.anomaly_calc(sos_arr,
                                                     self.reg_dic,
                                                     mask,
                                                     clim_sos_cube[0],
                                                     "SOS",
                                                     self.set_dic['cross_year'])

                    self.progress.emit(int(start_progress + 75/prog_divisor))
                    QgsMessageLog.logMessage(u"Writing Forecast output files",
                                             level=Qgis.Info)
                    # Write the wrsi_cube out to a file for the needed forecast
                    # file
                    if self.output_dic['save_every_wrsi']:
                        for index, file in enumerate(self.set_dic[
                                'output_file_list_wrsi_for'],
                                extra_periods +
                                self.set_dic['num_current_periods']):
                            err = gdal_util.write_file(file, wrsi_cube[index],
                                                       col_ct, row_ct, geoxform,
                                                       gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    
                    # Write the swi_cube out to a file for the needed forecast
                    # file
                    if self.output_dic['save_every_soil_water_index']:
                        for index, file in enumerate(self.set_dic[
                                'output_file_list_swi_for'],
                                extra_periods +
                                self.set_dic['num_current_periods']):
                            err = gdal_util.write_file(file, swi_cube[index],
                                                       col_ct, row_ct, geoxform,
                                                       gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    
                    # Write the lgp_phen_cube out to file for the needed
                    # forecast file
                    if self.output_dic['save_every_lgp_phenology']:
                        for index, file in enumerate(self.set_dic[
                                'output_file_list_lgp_phen_for'],
                                extra_periods +
                                self.set_dic['num_current_periods']):
                            err = gdal_util.write_file(file, 
                                                       lgp_phen_cube[index],
                                                       col_ct, row_ct,
                                                       geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Write out the wrsi_for 2d array to the cur file
                    if self.output_dic['current_wrsi']:
                        err = gdal_util.write_file(self.set_dic[
                            'output_file_wrsi_for'],
                            for_output_cube[0], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 77/prog_divisor))

                    # Write out the wrsi_for anom 2d array to the cur file
                    if self.output_dic['current_wrsi_anomaly']:
                        err = gdal_util.write_file(self.set_dic[
                            'output_file_wrsi_anom_for'],
                            wrsi_anom, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 79/prog_divisor))

                    err = gdal_util.write_file(
                        self.set_dic['output_file_sos_for'],
                        sos_arr, col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 80/prog_divisor))

                    err = gdal_util.write_file(
                        self.set_dic['output_file_sos_anom_for'],
                        sos_anom, col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 81/prog_divisor))

                    # Write out the lgp_phen_for 2d array to the eos file
                    if self.output_dic['current_lgp_phenology']:
                        err = gdal_util.write_file(self.set_dic[
                            'output_file_lgp_phen_for'],
                            for_output_cube[2], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 82/prog_divisor))

                    # Write out the swi_for 2d array to the eos file
                    if self.output_dic['current_soil_water_index']:
                        err = gdal_util.write_file(
                            self.set_dic['output_file_swi_for'],
                            for_output_cube[3], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 83/prog_divisor))

                    # Write out the water_req_total 2d array to the eos file
                    if self.output_dic['current_water_req_totals']:
                        err = gdal_util.write_file(self.set_dic[
                            'output_file_water_req_tot_for'],
                            for_output_cube[4], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 84/prog_divisor))

                    # Write out the max_water_deficit 2d array to the eos file
                    if self.output_dic['current_max_water_deficits']:
                        err = gdal_util.write_file(self.set_dic[
                            'output_file_max_water_def_for'],
                            for_output_cube[5], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 85/prog_divisor))

                    # Write out the water_deficit_total 2d array to the eos
                    # file
                    if self.output_dic['current_water_deficit_totals']:
                        err = gdal_util.write_file(self.set_dic[
                            'output_file_water_def_tot_for'],
                            for_output_cube[6], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 86/prog_divisor))

                    # Write out the max_water_surplus 2d array to the eos file
                    if self.output_dic['current_max_water_surplus']:
                        err = gdal_util.write_file(self.set_dic[
                            'output_file_max_water_surp_for'],
                            for_output_cube[7], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 87/prog_divisor))

                    # Write out the water_surplus_total 2d array to the eos
                    # file
                    if self.output_dic['current_water_surplus_totals']:
                        err = gdal_util.write_file(self.set_dic[
                            'output_file_water_surp_tot_for'],
                            for_output_cube[8], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 88/prog_divisor))

                    # Write out the aet_total 2d array to the eos file
                    if self.output_dic['current_aet_totals']:
                        err = gdal_util.write_file(self.set_dic[
                            'output_file_aet_tot_for'],
                            for_output_cube[9], col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 90/prog_divisor))

                # if extended run we will now loop through the forecast setup
                # and calculations for each extended year
                if self.set_dic['ext_avg_run'] or self.set_dic['ext_med_run']:
                    for year in self.set_dic['ext_years_list']:
                        start_progress = start_progress + 90/prog_divisor
                        # Start by restacking all of the cubes adding the
                        # forecast data to them
                        if self.killed is True:
                            raise KeyboardInterrupt
                        self.progress.emit(int(start_progress + 10/prog_divisor))
                        # Set the PPT data cube and fill it with extended data
                        # for the year
                        ppt_data_cube =\
                            geo_util.fill_data_cube_from_files(
                                self.reg_dic,
                                self.set_dic['ext_ppt_data_dict'][year],
                                self.output_file_path)
                        if self.killed is True:
                            raise KeyboardInterrupt
                        self.progress.emit(int(start_progress + 35/prog_divisor))
                        # Set the PET data cube and fill it with extended data
                        # for the year
                        pet_data_cube =\
                            geo_util.fill_data_cube_from_files(
                                self.reg_dic,
                                self.set_dic['ext_pet_data_dict'][year],
                                self.output_file_path)
                        if self.killed is True:
                            raise KeyboardInterrupt
                        self.progress.emit(int(start_progress + 60/prog_divisor))
                        # Stack the data cubes
                        cubes_arr = []
                        cubes_arr.append(ppt_data_cube)
                        cubes_arr.append(pet_data_cube)
                        cubes_arr.append(lgp_data_cube)
                        cubes_arr.append(whc_data_cube)
                        cubes_arr.append(sos_data_cube)
                        cubes_arr.append(mask_data_cube)
                        stacked_cube = geo_util.stack_cubes(cubes_arr)
                        periods, _, _ = ppt_data_cube.shape

                        if self.set_dic['sos_type'] == 'Calculated':
                            QgsMessageLog.logMessage(
                                u"Calculating extended SOS for " + year,
                                level=Qgis.Info)
                            stacked_cube = geo_util.calc_current_sos(
                                stacked_cube, self.reg_dic, self.set_dic,
                                extra_periods, periods)
                        QgsMessageLog.logMessage(
                            u"Begin calculating extended WRSI for " + year,
                            level=Qgis.Info)
                        # Call geo_util.run_geowrsi_historical function to run
                        # the wrsi for each extended year since we have full
                        # set of data
                        (wrsi_cube, swi_cube, lgp_phen_cube,
                         ext_output_cube, crop_stages_cube) =\
                            np.apply_along_axis(
                                geo_util.run_geowrsi_historical, 0,
                                stacked_cube,
                                self.crop_dic, periods,
                                self.set_dic['initial_period'],
                                self.set_dic['final_period'],
                                self.set_dic['cross_year'],
                                self.reg_dic['PeriodType'])
                        if self.killed is True:
                            raise KeyboardInterrupt
                        # Calculate WRSI Anomaly
                        mask = gdal_util.get_inverted_mask_array(
                            resampled_mask)
                        wrsi_arr = ext_output_cube[0]
                        wrsi_anom = geo_util.anomaly_calc(
                            wrsi_arr,
                            self.reg_dic,
                            mask,
                            clim_wrsi_cube[0],
                            "WRSI",
                            self.set_dic['cross_year'])
                        wrsi_anom[wrsi_anom == -9999] = config.NO_DATA

                        # Calculate SOS anomaly
                        sos_arr = stacked_cube[-2]
                        sos_anom = geo_util.anomaly_calc(
                            sos_arr,
                            self.reg_dic,
                            mask,
                            clim_sos_cube[0],
                            "SOS",
                            self.set_dic['cross_year'])

                        self.progress.emit(int(start_progress + 75/prog_divisor))
                        QgsMessageLog.logMessage(
                            u"Writing extended intermediate output files for "
                            + year,
                            level=Qgis.Info)
                        # Write the wrsi_cube out to a file for each needed
                        # output period this will allow first 6 dekads or 12
                        # pentads from data cube that represent the preseason
                        # to be skipped and the extra periods after the
                        # eos + 6 to be ignored, also ignore the current
                        # periods
                        if self.output_dic['save_every_wrsi']:
                            for index, file in enumerate(self.set_dic[
                                    'ext_output_files_dict'][year]
                                    ['output_file_list_wrsi'],
                                    extra_periods +
                                    self.set_dic['num_current_periods']):
                                err = gdal_util.write_file(
                                    file, wrsi_cube[index], col_ct,
                                    row_ct, geoxform, gd_data_type)
                                if err is True:
                                    raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt
                        self.progress.emit(int(start_progress + 80/prog_divisor))

                        # Write the swi_cube out to a file for each needed
                        # output period this will allow first 6 dekads or 12
                        # pentads from data cube that represent the preseason
                        # to be skipped and the extra periods after the
                        # eos + 6 to be ignored, also ignore the current
                        # periods
                        if self.output_dic['save_every_soil_water_index']:
                            for index, file in enumerate(self.set_dic[
                                    'ext_output_files_dict'][year]
                                    ['output_file_list_swi'],
                                    extra_periods +
                                    self.set_dic['num_current_periods']):
                                err = gdal_util.write_file(
                                    file, swi_cube[index], col_ct,
                                    row_ct, geoxform, gd_data_type)
                                if err is True:
                                    raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt
                        self.progress.emit(int(start_progress + 83/prog_divisor))

                        # Write the lgp_phen_cube out to file for each needed
                        # output period this will allow first 6 dekads or 12
                        # pentads from data cube that represent the preseason
                        # to be skipped and the extra periods after the
                        # eos + 6 to be ignored, also ignore the current
                        # periods
                        if self.output_dic['save_every_lgp_phenology']:
                            for index, file in enumerate(self.set_dic[
                                    'ext_output_files_dict'][year]
                                    ['output_file_list_lgp_phen'],
                                    extra_periods +
                                    self.set_dic['num_current_periods']):
                                err = gdal_util.write_file(
                                    file, lgp_phen_cube[index],
                                    col_ct, row_ct,
                                    geoxform, gd_data_type)
                                if err is True:
                                    raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt
                        self.progress.emit(int(start_progress + 86/prog_divisor))

                        # Write out the wrsi 2d array to the ext file
                        if self.output_dic['eos_wrsi']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_wrsi_ext'],
                                ext_output_cube[0], col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the wrsi anom 2d array to the ext file
                        if self.output_dic['eos_wrsi_anomaly']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_wrsi_anom_ext'],
                                wrsi_anom, col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the sos 2d array to the ext file
                        err = gdal_util.write_file(
                            self.set_dic['ext_output_files_dict'][year]
                            ['output_file_sos_ext'],
                            sos_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the sos anom 2d array to the ext file
                        err = gdal_util.write_file(
                            self.set_dic['ext_output_files_dict'][year]
                            ['output_file_sos_anom_ext'],
                            sos_anom, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the lgp_phen 2d array to the ext file
                        if self.output_dic['eos_lgp_phenology']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_lgp_phen_ext'],
                                ext_output_cube[2], col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the swi 2d array to the ext file
                        if self.output_dic['eos_soil_water_index']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_swi_ext'],
                                ext_output_cube[3], col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the water_req_total 2d array
                        # to the ext file
                        if self.output_dic['eos_water_req_totals']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_water_req_tot_ext'],
                                ext_output_cube[4], col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the max_water_deficit 2d array
                        # to the ext file
                        if self.output_dic['eos_max_water_deficits']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_max_water_def_ext'],
                                ext_output_cube[5], col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the water_deficit_total 2d array
                        # to the ext file
                        if self.output_dic['eos_water_deficit_totals']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_water_def_tot_ext'],
                                ext_output_cube[6], col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the max_water_surplus 2d array
                        # to the ext file
                        if self.output_dic['eos_max_water_surplus']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_max_water_surp_ext'],
                                ext_output_cube[7], col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the water_surplus_total 2d array 
                        # to the ext file
                        if self.output_dic['eos_water_surplus_totals']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_water_surp_tot_ext'],
                                ext_output_cube[8], col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the aet_total 2d array to the ext file
                        if self.output_dic['eos_aet_totals']:
                            err = gdal_util.write_file(self.set_dic[
                                'ext_output_files_dict'][year]
                                ['output_file_aet_tot_ext'],
                                ext_output_cube[9], col_ct, row_ct,
                                geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                        if self.killed is True:
                            raise KeyboardInterrupt

                        # Write out the crop stages cube to the ext files
                        if self.output_dic['save_crop_stage_totals_eos']:
                            for index, file in enumerate(self.set_dic[
                                    'ext_output_files_dict'][year]
                                    ['output_file_list_crop_stages_ext']):
                                err = gdal_util.write_file(
                                    file, crop_stages_cube[index],
                                    col_ct, row_ct,
                                    geoxform, gd_data_type)
                                if err is True:
                                    raise RuntimeError
                        self.progress.emit(int(start_progress + 90/prog_divisor))

                    if self.set_dic['ext_avg_run']:
                        stat_type = 'Average'
                    else:
                        stat_type = 'Median'
                    # Calculate the averages for the final extended outputs
                    QgsMessageLog.logMessage(
                        u"Calculating the final " + stat_type +
                        " output files from the intermediate files",
                        level=Qgis.Info)
                    run_year = str(self.set_dic['start_year'])
                    start_progress = start_progress + 90/prog_divisor

                    # Calc avg/med and write out the 2d array to the ext file
                    if self.output_dic['eos_wrsi']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_wrsi_ext", True)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_wrsi_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 3/prog_divisor))

                    # Calc avg/med and write out the wrsi anom 2d array
                    # to the ext file
                    if self.output_dic['eos_wrsi_anomaly']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_wrsi_anom_ext", True)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_wrsi_anom_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 6/prog_divisor))

                    # Calc avg/med and write out the swi 2d array
                    # to the ext file
                    if self.output_dic['eos_soil_water_index']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_swi_ext", True)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_swi_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 9/prog_divisor))

                    # Calc avg/med and write out the lgp phen 2d array
                    # to the ext file
                    if self.output_dic['eos_lgp_phenology']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_lgp_phen_ext", True)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_lgp_phen_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 12/prog_divisor))

                    # Calc avg/med and write out the water req total 2d array
                    # to the ext file
                    if self.output_dic['eos_water_req_totals']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_water_req_tot_ext",
                            False)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_water_req_tot_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 15/prog_divisor))

                    # Calc avg/med and write out the max deficit 2d array
                    # to the ext file
                    if self.output_dic['eos_max_water_deficits']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_max_water_def_ext",
                            False)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_max_water_def_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 18/prog_divisor))

                    # Calc avg/med and write out the total deficit 2d array
                    # to the ext file
                    if self.output_dic['eos_water_deficit_totals']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_water_def_tot_ext",
                            False)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_water_def_tot_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 21/prog_divisor))

                    # Calc avg/med and write out the max surplus 2d array
                    # to the ext file
                    if self.output_dic['eos_max_water_surplus']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_max_water_surp_ext",
                            False)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_max_water_surp_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 24/prog_divisor))

                    # Calc avg/med and write out the total surplus 2d array
                    # to the ext file
                    if self.output_dic['eos_water_surplus_totals']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_water_surp_tot_ext",
                            False)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_water_surp_tot_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 27/prog_divisor))

                    # Calc avg/med and write out the aet total 2d array
                    # to the ext file
                    if self.output_dic['eos_aet_totals']:
                        ext_arr = self.calc_avg_med_for_extended(
                            stat_type, "output_file_aet_tot_ext", False)
                        err = gdal_util.write_file(self.set_dic[
                            'ext_output_files_dict'][run_year]
                            ['output_file_aet_tot_ext'],
                            ext_arr, col_ct, row_ct,
                            geoxform, gd_data_type)
                        if err is True:
                            raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 30/prog_divisor))

                    # Calc SOS Mode here and display
                    sos_ext_arr = self.calc_avg_med_for_extended(
                        stat_type, "output_file_sos_ext", False, True)
                    err = gdal_util.write_file(self.set_dic[
                        'ext_output_files_dict'][run_year]
                        ['output_file_sos_ext'],
                        sos_ext_arr, col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

                    # Calc sos anomaly from sos mode extended arr
                    sos_anom_ext = geo_util.anomaly_calc(
                        sos_ext_arr,
                        self.reg_dic,
                        mask,
                        clim_sos_cube[0],
                        "SOS",
                        self.set_dic['cross_year'])

                    # Write out the sos anom ext 2d array to the ext file
                    err = gdal_util.write_file(
                        self.set_dic['ext_output_files_dict'][run_year]
                        ['output_file_sos_anom_ext'],
                        sos_anom_ext, col_ct, row_ct,
                        geoxform, gd_data_type)
                    if err is True:
                        raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 36/prog_divisor))

                    # Calc the avg/median for each period by period wrsi
                    # output then write it out to the corresponding file
                    if self.output_dic['save_every_wrsi']:
                        for index, file in enumerate(self.set_dic[
                                'ext_output_files_dict'][run_year]
                                ['output_file_list_wrsi']):
                            ext_wrsi = self.calc_avg_med_for_list_extended(
                                stat_type, "output_file_list_wrsi",
                                index, True)
                            err = gdal_util.write_file(
                                file, ext_wrsi, col_ct,
                                row_ct, geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 54/prog_divisor))

                    # Calc the avg/median for each period by period swi
                    # output then write it out to the corresponding file
                    if self.output_dic['save_every_soil_water_index']:
                        for index, file in enumerate(self.set_dic[
                                'ext_output_files_dict'][run_year]
                                ['output_file_list_swi']):
                            ext_swi = self.calc_avg_med_for_list_extended(
                                stat_type, "output_file_list_swi",
                                index, True)
                            err = gdal_util.write_file(
                                file, ext_swi, col_ct,
                                row_ct, geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 72/prog_divisor))

                    # Calc the avg/median for each period by period lgp phen
                    # output then write it out to the corresponding file
                    if self.output_dic["save_every_lgp_phenology"]:
                        for index, file in enumerate(self.set_dic[
                                'ext_output_files_dict'][run_year]
                                ['output_file_list_lgp_phen']):
                            ext_lgp = self.calc_avg_med_for_list_extended(
                                stat_type, "output_file_list_lgp_phen",
                                index, True)
                            err = gdal_util.write_file(
                                file, ext_lgp, col_ct,
                                row_ct, geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt
                    self.progress.emit(int(start_progress + 90/prog_divisor))

                    # Crop Stages avg/med calcs
                    if self.output_dic['save_crop_stage_totals_eos']:
                        for index, file in enumerate(self.set_dic[
                                'ext_output_files_dict'][run_year]
                                ['output_file_list_crop_stages_ext']):
                            ext_crops = self.calc_avg_med_for_list_extended(
                                stat_type, "output_file_list_crop_stages_ext",
                                index, False)
                            err = gdal_util.write_file(
                                file, ext_crops, col_ct,
                                row_ct, geoxform, gd_data_type)
                            if err is True:
                                raise RuntimeError
                    if self.killed is True:
                        raise KeyboardInterrupt

            if err is True:
                raise RuntimeError
            if self.killed is True:
                raise KeyboardInterrupt
            if self.killed is False:
                self.progress.emit(95)
                ret_tuple = (0, u"WRSI completed")
            if err is True:
                raise RuntimeError
        # exit with appropriate message on killed (KeyboardInterrupt)
        except KeyboardInterrupt:
            self.progress.emit(0)
            ret_tuple = (0, u"WRSI aborted by user")
        # forward any execeptions upstream
        except BaseException as exc:
            self.error.emit(exc, u"Unspecified error in WRSI")
        self.finished.emit(ret_tuple)

    finished = QtCore.pyqtSignal(object)

    error = QtCore.pyqtSignal(Exception, str)

    progress = QtCore.pyqtSignal(int)
