Example #1
0
 def testMaskingFunctions(self):
     xouter = MV2.outerproduct(MV2.arange(5.), [1] * 10)
     masked = MV2.masked_greater(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[2:], True))
     self.assertTrue(MV2.allequal(masked.mask[:2], False))
     masked = MV2.masked_greater_equal(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[1:], True))
     self.assertTrue(MV2.allequal(masked.mask[:1], False))
     masked = MV2.masked_less(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[:1], True))
     self.assertTrue(MV2.allequal(masked.mask[1:], False))
     masked = MV2.masked_less_equal(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[:2], True))
     self.assertTrue(MV2.allequal(masked.mask[2:], False))
     masked = MV2.masked_not_equal(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[1], False))
     self.assertTrue(MV2.allequal(masked.mask[0], True))
     self.assertTrue(MV2.allequal(masked.mask[2:], True))
     masked = MV2.masked_equal(xouter, 1)
     self.assertTrue(MV2.allequal(masked.mask[1], True))
     self.assertTrue(MV2.allequal(masked.mask[0], False))
     self.assertTrue(MV2.allequal(masked.mask[2:], False))
     masked = MV2.masked_outside(xouter, 1, 3)
     self.assertTrue(MV2.allequal(masked.mask[0:1], True))
     self.assertTrue(MV2.allequal(masked.mask[1:4], False))
     self.assertTrue(MV2.allequal(masked.mask[4:], True))
     masked = MV2.masked_where(
         MV2.logical_or(MV2.greater(xouter, 3), MV2.less(xouter, 2)),
         xouter)
     self.assertTrue(MV2.allequal(masked.mask[0:2], True))
     self.assertTrue(MV2.allequal(masked.mask[2:4], False))
     self.assertTrue(MV2.allequal(masked.mask[4:], True))
Example #2
0
 def myMakeMask(array, range):
     """Returns the input array masked where the values are not between range[0] and range[1]"""
     m1 = MV2.less(array,
                   range[0])  # mask where it is less than the 1st value
     m2 = MV2.greater(
         array, range[1])  # mask where it is more than the 2nd value
     return MV2.logical_or(m1, m2)
Example #3
0
def loop(potential,potential_reg,c2,w3,region):
    nmax        = potential.shape[0]
    c3          = MV2.not_equal(w3,0.)
    c           = MV2.logical_and(c2,c3)
    thisturn    = MV2.ones(c.shape)
    for i in range(nmax):
        c1                  = MV2.logical_or(MV2.equal(potential_reg[i],region),MV2.equal(potential[i],-999))
        c2                  = MV2.logical_and(c,c1)
        c2                  = MV2.logical_and(c2,thisturn)
        potential_reg[i]    = MV2.where(c2,region,potential_reg[i])
        thisturn            = MV2.where(c2,0,thisturn)
        c1                  = MV2.logical_and(c2,MV2.equal(potential[i],-999))
        c2                  = MV2.logical_and(c2,MV2.not_equal(potential[i],-999))
        potential[i]        = MV2.where(c1,w3,potential[i])
        potential[i]        = MV2.where(c2,potential[i]+w3,potential[i])
    ## Ultimate test to see if more would be needed !
    if not MV2.allequal(MV2.logical_and(c,thisturn),0):
        raise 'OOOPS WE COULD USE MORE REGIONS BUDDY !'
    return
Example #4
0
def run_diag(parameter):
    parameter.reference_data_path
    parameter.test_data_path

    variables = parameter.variables
    seasons = parameter.seasons
    ref_name = parameter.ref_name
    regions = parameter.regions

    for season in seasons:
        try:
            filename1 = utils.get_test_filename(parameter, season)
            filename2 = utils.get_ref_filename(parameter, season)
        except IOError as e:
            print(e)
            # the file for the current parameters wasn't found, move to next
            # parameters
            continue

        print('test file: {}'.format(filename1))
        print('reference file: {}'.format(filename2))

        f_mod = cdms2.open(filename1)
        f_obs = cdms2.open(filename2)

        if parameter.short_test_name:
            parameter.test_name_yrs = parameter.short_test_name
        else:
            parameter.test_name_yrs = parameter.test_name

        try:
            yrs_averaged = f_mod.getglobal('yrs_averaged')
            parameter.test_name_yrs = parameter.test_name_yrs + ' (' + yrs_averaged + ')'

        except:
            print('No yrs_averaged exists in global attributes')
            parameter.test_name_yrs = parameter.test_name_yrs

        # save land/ocean fraction for masking
        try:
            land_frac = f_mod('LANDFRAC')
            ocean_frac = f_mod('OCNFRAC')
        except BaseException:
            mask_path = os.path.join(acme_diags.INSTALL_PATH,
                                     'acme_ne30_ocean_land_mask.nc')
            f0 = cdms2.open(mask_path)
            land_frac = f0('LANDFRAC')
            ocean_frac = f0('OCNFRAC')
            f0.close()

        for var in variables:
            print('Variable: {}'.format(var))
            parameter.var_id = var
            mv1 = acme.process_derived_var(var, acme.derived_variables, f_mod,
                                           parameter)
            mv2 = acme.process_derived_var(var, acme.derived_variables, f_obs,
                                           parameter)

            parameter.viewer_descr[var] = mv1.long_name if hasattr(
                mv1, 'long_name') else 'No long_name attr in test data.'

            # special case, cdms didn't properly convert mask with fill value
            # -999.0, filed issue with denise
            if ref_name == 'WARREN':
                # this is cdms2 for bad mask, denise's fix should fix
                mv2 = MV2.masked_where(mv2 == -0.9, mv2)
                # following should move to derived variable
            if ref_name == 'AIRS':
                # mv2=MV2.masked_where(mv2==mv2.fill_value,mv2)
                # this is cdms2 for bad mask, denise's fix should fix
                mv2 = MV2.masked_where(mv2 > 1e+20, mv2)
            if ref_name == 'WILLMOTT' or ref_name == 'CLOUDSAT':
                print(mv2.fill_value)
                # mv2=MV2.masked_where(mv2==mv2.fill_value,mv2)
                # this is cdms2 for bad mask, denise's fix should fix
                mv2 = MV2.masked_where(mv2 == -999., mv2)
                print(mv2.fill_value)

                # following should move to derived variable
                if var == 'PRECT_LAND':
                    days_season = {
                        'ANN': 365,
                        'DJF': 90,
                        'MAM': 92,
                        'JJA': 92,
                        'SON': 91
                    }
                    # mv1 = mv1 * days_season[season] * 0.1 #following AMWG
                    # approximate way to convert to seasonal cumulative
                    # precipitation, need to have solution in derived variable,
                    # unit convert from mm/day to cm
                    mv2 = mv2 / days_season[season] / \
                        0.1  # convert cm to mm/day instead
                    mv2.units = 'mm/day'

            if mv1.getLevel() and mv2.getLevel():  # for variables with z axis:
                plev = parameter.plevs
                print('Selected pressure level: {}'.format(plev))
                f_ins = [f_mod, f_obs]
                for f_ind, mv in enumerate([mv1, mv2]):
                    mv_plv = mv.getLevel()
                    # var(time,lev,lon,lat) convert from hybrid level to
                    # pressure
                    if mv_plv.long_name.lower().find('hybrid') != -1:
                        f_in = f_ins[f_ind]
                        hyam = f_in('hyam')
                        hybm = f_in('hybm')
                        ps = f_in('PS')  # Pa

                        mv_p = utils.hybrid_to_plevs(mv, hyam, hybm, ps, plev)

                    # levels are presure levels
                    elif mv_plv.long_name.lower().find(
                            'pressure') != -1 or mv_plv.long_name.lower().find(
                                'isobaric') != -1:
                        mv_p = utils.pressure_to_plevs(mv, plev)

                    else:
                        raise RuntimeError(
                            "Vertical level is neither hybrid nor pressure. Abort"
                        )
                    if f_ind == 0:
                        mv1_p = mv_p
                    if f_ind == 1:
                        mv2_p = mv_p
                # select plev
                for ilev in range(len(plev)):
                    mv1 = mv1_p[ilev, ]
                    mv2 = mv2_p[ilev, ]

                    # select region
                    if len(regions) == 0:
                        regions = ['global']

                    for region in regions:
                        print("Selected region: {}".format(region))

                        mv1_domain, mv2_domain = utils.select_region(
                            region, mv1, mv2, land_frac, ocean_frac, parameter)

                        parameter.output_file = '-'.join([
                            ref_name, var,
                            str(int(plev[ilev])), season, region
                        ])
                        parameter.main_title = str(' '.join(
                            [var,
                             str(int(plev[ilev])), 'mb', season, region]))

                        # Regrid towards lower resolution of two variables for
                        # calculating difference
                        mv1_reg, mv2_reg = utils.regrid_to_lower_res(
                            mv1_domain, mv2_domain, parameter.regrid_tool,
                            parameter.regrid_method)

                        # Plotting
                        diff = mv1_reg - mv2_reg
                        metrics_dict = create_metrics(mv2_domain, mv1_domain,
                                                      mv2_reg, mv1_reg, diff)

                        parameter.var_region = region
                        plot(parameter.current_set, mv2_domain, mv1_domain,
                             diff, metrics_dict, parameter)
                        utils.save_ncfiles(parameter.current_set, mv1_domain,
                                           mv2_domain, diff, parameter)

                f_in.close()

            # for variables without z axis:
            elif mv1.getLevel() is None and mv2.getLevel() is None:

                # select region
                if len(regions) == 0:
                    regions = ['global']

                for region in regions:
                    print("Selected region: {}".format(region))

                    mv1_domain, mv2_domain = utils.select_region(
                        region, mv1, mv2, land_frac, ocean_frac, parameter)

                    parameter.output_file = '-'.join(
                        [ref_name, var, season, region])
                    parameter.main_title = str(' '.join([var, season, region]))

                    # regrid towards lower resolution of two variables for
                    # calculating difference
                    mv1_reg, mv2_reg = utils.regrid_to_lower_res(
                        mv1_domain, mv2_domain, parameter.regrid_tool,
                        parameter.regrid_method)

                    # if var is 'SST' or var is 'TREFHT_LAND': #special case

                    if var == 'TREFHT_LAND' or var == 'SST':  # use "==" instead of "is"
                        if ref_name == 'WILLMOTT':
                            mv2_reg = MV2.masked_where(
                                mv2_reg == mv2_reg.fill_value, mv2_reg)
                            print(ref_name)

                            # if mv.mask is False:
                            #    mv = MV2.masked_less_equal(mv, mv._FillValue)
                            #    print("*************",mv.count())
                        land_mask = MV2.logical_or(mv1_reg.mask, mv2_reg.mask)
                        mv1_reg = MV2.masked_where(land_mask, mv1_reg)
                        mv2_reg = MV2.masked_where(land_mask, mv2_reg)

                    diff = mv1_reg - mv2_reg
                    metrics_dict = create_metrics(mv2_domain, mv1_domain,
                                                  mv2_reg, mv1_reg, diff)
                    parameter.var_region = region
                    plot(parameter.current_set, mv2_domain, mv1_domain, diff,
                         metrics_dict, parameter)
                    utils.save_ncfiles(parameter.current_set, mv1_domain,
                                       mv2_domain, diff, parameter)

            else:
                raise RuntimeError(
                    "Dimensions of two variables are difference. Abort")
        f_obs.close()
        f_mod.close()
    return parameter
Example #5
0
def run_diag(parameter):
    variables = parameter.variables
    seasons = parameter.seasons
    ref_name = getattr(parameter, 'ref_name', '')
    regions = parameter.regions

    test_data = utils.dataset.Dataset(parameter, test=True)
    ref_data = utils.dataset.Dataset(parameter, ref=True)

    for season in seasons:
        # Get the name of the data, appended with the years averaged.
        parameter.test_name_yrs = utils.general.get_name_and_yrs(
            parameter, test_data, season)
        parameter.ref_name_yrs = utils.general.get_name_and_yrs(
            parameter, ref_data, season)

        # Get land/ocean fraction for masking.
        try:
            land_frac = test_data.get_climo_variable('LANDFRAC', season)
            ocean_frac = test_data.get_climo_variable('OCNFRAC', season)
        except:
            mask_path = os.path.join(acme_diags.INSTALL_PATH,
                                     'acme_ne30_ocean_land_mask.nc')
            with cdms2.open(mask_path) as f:
                land_frac = f('LANDFRAC')
                ocean_frac = f('OCNFRAC')

        for var in variables:
            print('Variable: {}'.format(var))
            parameter.var_id = var

            mv1 = test_data.get_climo_variable(var, season)
            mv2 = ref_data.get_climo_variable(var, season)

            parameter.viewer_descr[var] = mv1.long_name if hasattr(
                mv1, 'long_name') else 'No long_name attr in test data.'

            # Special case, cdms didn't properly convert mask with fill value
            # -999.0, filed issue with Denis.
            if ref_name == 'WARREN':
                # This is cdms2 fix for bad mask, Denis' fix should fix this.
                mv2 = MV2.masked_where(mv2 == -0.9, mv2)
            # The following should be moved to a derived variable.
            if ref_name == 'AIRS':
                # This is cdms2 fix for bad mask, Denis' fix should fix this.
                mv2 = MV2.masked_where(mv2 > 1e+20, mv2)
            if ref_name == 'WILLMOTT' or ref_name == 'CLOUDSAT':
                # This is cdms2 fix for bad mask, Denis' fix should fix this.
                mv2 = MV2.masked_where(mv2 == -999., mv2)

                # The following should be moved to a derived variable.
                if var == 'PRECT_LAND':
                    days_season = {
                        'ANN': 365,
                        'DJF': 90,
                        'MAM': 92,
                        'JJA': 92,
                        'SON': 91
                    }
                    # mv1 = mv1 * days_season[season] * 0.1 # following AMWG
                    # Approximate way to convert to seasonal cumulative
                    # precipitation, need to have solution in derived variable,
                    # unit convert from mm/day to cm.
                    mv2 = mv2 / days_season[season] / \
                        0.1  # Convert cm to mm/day instead.
                    mv2.units = 'mm/day'

            # For variables with a z-axis.
            if mv1.getLevel() and mv2.getLevel():
                plev = parameter.plevs
                print('Selected pressure level: {}'.format(plev))

                mv1_p = utils.general.convert_to_pressure_levels(
                    mv1, plev, test_data, var, season)
                mv2_p = utils.general.convert_to_pressure_levels(
                    mv2, plev, ref_data, var, season)

                # Select plev.
                for ilev in range(len(plev)):
                    mv1 = mv1_p[ilev, ]
                    mv2 = mv2_p[ilev, ]

                    for region in regions:
                        print("Selected region: {}".format(region))

                        mv1_domain = utils.general.select_region(
                            region, mv1, land_frac, ocean_frac, parameter)
                        mv2_domain = utils.general.select_region(
                            region, mv2, land_frac, ocean_frac, parameter)

                        parameter.output_file = '-'.join([
                            ref_name, var,
                            str(int(plev[ilev])), season, region
                        ])
                        parameter.main_title = str(' '.join(
                            [var,
                             str(int(plev[ilev])), 'mb', season, region]))

                        # Regrid towards the lower resolution of the two
                        # variables for calculating the difference.
                        mv1_reg, mv2_reg = utils.general.regrid_to_lower_res(
                            mv1_domain, mv2_domain, parameter.regrid_tool,
                            parameter.regrid_method)

                        # Plotting
                        diff = mv1_reg - mv2_reg
                        metrics_dict = create_metrics(mv2_domain, mv1_domain,
                                                      mv2_reg, mv1_reg, diff)

                        parameter.var_region = region
                        plot(parameter.current_set, mv2_domain, mv1_domain,
                             diff, metrics_dict, parameter)
                        utils.general.save_ncfiles(parameter.current_set,
                                                   mv1_domain, mv2_domain,
                                                   diff, parameter)

            # For variables without a z-axis.
            elif mv1.getLevel() is None and mv2.getLevel() is None:
                for region in regions:
                    print("Selected region: {}".format(region))

                    mv1_domain = utils.general.select_region(
                        region, mv1, land_frac, ocean_frac, parameter)
                    mv2_domain = utils.general.select_region(
                        region, mv2, land_frac, ocean_frac, parameter)

                    parameter.output_file = '-'.join(
                        [ref_name, var, season, region])
                    parameter.main_title = str(' '.join([var, season, region]))

                    # Regrid towards the lower resolution of the two
                    # variables for calculating the difference.
                    mv1_reg, mv2_reg = utils.general.regrid_to_lower_res(
                        mv1_domain, mv2_domain, parameter.regrid_tool,
                        parameter.regrid_method)

                    # Special case.
                    if var == 'TREFHT_LAND' or var == 'SST':
                        if ref_name == 'WILLMOTT':
                            mv2_reg = MV2.masked_where(
                                mv2_reg == mv2_reg.fill_value, mv2_reg)

                        land_mask = MV2.logical_or(mv1_reg.mask, mv2_reg.mask)
                        mv1_reg = MV2.masked_where(land_mask, mv1_reg)
                        mv2_reg = MV2.masked_where(land_mask, mv2_reg)

                    diff = mv1_reg - mv2_reg
                    metrics_dict = create_metrics(mv2_domain, mv1_domain,
                                                  mv2_reg, mv1_reg, diff)
                    parameter.var_region = region

                    plot(parameter.current_set, mv2_domain, mv1_domain, diff,
                         metrics_dict, parameter)
                    utils.general.save_ncfiles(parameter.current_set,
                                               mv1_domain, mv2_domain, diff,
                                               parameter)

            else:
                raise RuntimeError(
                    "Dimensions of the two variables are different. Aborting.")

    return parameter
def myMakeMask(array, range):
    """Returns the input array masked where the values are not between range[0] and range[1]"""
    m1=MV.less (array, range[0]) # mask where it is less than the 1st value
    m2=MV.greater(array, range[1]) # mask where it is more than the 2nd value
    return MV.logical_or(m1,m2)
Example #7
0
def run_diag(parameter):
    reference_data_path = parameter.reference_data_path
    test_data_path = parameter.test_data_path

    variables = parameter.variables
    seasons = parameter.seasons
    ref_name = parameter.ref_name
    regions = parameter.regions

    for season in seasons:
        try:
            filename1 = utils.get_test_filename(parameter, season)
            filename2 = utils.get_ref_filename(parameter, season)
        except IOError as e:
            print(e)
            # the file for the current parameters wasn't found, move to next parameters
            continue

        print('test file: {}'.format(filename1))
        print('reference file: {}'.format(filename2))

        f_mod = cdms2.open(filename1)
        f_obs = cdms2.open(filename2)

        #save land/ocean fraction for masking
        try:
            land_frac = f_mod('LANDFRAC')
            ocean_frac = f_mod('OCNFRAC')
        except:
            mask_path = os.path.join(sys.prefix, 'share', 'acme_diags',
                                     'acme_ne30_ocean_land_mask.nc')
            f0 = cdms2.open(mask_path)
            land_frac = f0('LANDFRAC')
            ocean_frac = f0('OCNFRAC')
            f0.close()

        for var in variables:
            print('Variable: {}'.format(var))
            parameter.var_id = var
            mv1 = acme.process_derived_var(var, acme.derived_variables, f_mod,
                                           parameter)
            mv2 = acme.process_derived_var(var, acme.derived_variables, f_obs,
                                           parameter)

            parameter.viewer_descr[var] = mv1.long_name if hasattr(
                mv1, 'long_name') else 'No long_name attr in test data.'

            # special case, cdms didn't properly convert mask with fill value
            # -999.0, filed issue with denise
            if ref_name == 'WARREN':
                # this is cdms2 for bad mask, denise's fix should fix
                mv2 = MV2.masked_where(mv2 == -0.9, mv2)
                # following should move to derived variable
            if ref_name == 'AIRS':
                # mv2=MV2.masked_where(mv2==mv2.fill_value,mv2)
                print(mv2.fill_value)
                # this is cdms2 for bad mask, denise's fix should fix
                mv2 = MV2.masked_where(mv2 > 1e+20, mv2)
            if ref_name == 'WILLMOTT' or ref_name == 'CLOUDSAT':
                print(mv2.fill_value)
                # mv2=MV2.masked_where(mv2==mv2.fill_value,mv2)
                # this is cdms2 for bad mask, denise's fix should fix
                mv2 = MV2.masked_where(mv2 == -999., mv2)
                print(mv2.fill_value)

                # following should move to derived variable
                if var == 'PRECT_LAND':
                    days_season = {
                        'ANN': 365,
                        'DJF': 90,
                        'MAM': 92,
                        'JJA': 92,
                        'SON': 91
                    }
                    # mv1 = mv1 * days_season[season] * 0.1 #following AMWG
                    # approximate way to convert to seasonal cumulative
                    # precipitation, need to have solution in derived variable,
                    # unit convert from mm/day to cm
                    mv2 = mv2 / days_season[season] / \
                        0.1  # convert cm to mm/day instead
                    mv2.units = 'mm/day'

            if mv1.getLevel() and mv2.getLevel():  # for variables with z axis:
                #plev = parameter.plevs
                plev = numpy.logspace(2.0, 3.0, num=17)
                #plev = [30.,50.,70.,100.,150.,200.,250.,300.,400.,500.,600.,700.,775.,850.,925.,1000.]
                print('Selected pressure level: {}'.format(plev))
                f_ins = [f_mod, f_obs]
                for f_ind, mv in enumerate([mv1, mv2]):
                    mv_plv = mv.getLevel()
                    # var(time,lev,lon,lat) convert from hybrid level to pressure
                    if mv_plv.long_name.lower().find('hybrid') != -1:
                        f_in = f_ins[f_ind]
                        hyam = f_in('hyam')
                        hybm = f_in('hybm')
                        ps = f_in('PS')  #Pa

                        mv_p = utils.hybrid_to_plevs(mv, hyam, hybm, ps, plev)

                    elif mv_plv.long_name.lower().find(
                            'pressure') != -1 or mv_plv.long_name.lower().find(
                                'isobaric') != -1:  # levels are presure levels
                        mv_p = utils.pressure_to_plevs(mv, plev)

                    else:
                        raise RuntimeError(
                            "Vertical level is neither hybrid nor pressure. Abort"
                        )

                    #calculate zonal mean
                    mv_p = cdutil.averager(mv_p, axis='x')
                    if f_ind == 0:
                        mv1_p = mv_p
                    elif f_ind == 1:
                        mv2_p = mv_p
                parameter.output_file = '-'.join(
                    [ref_name, var, season, parameter.regions[0]])
                parameter.main_title = str(' '.join([var, season]))

                # Regrid towards lower resolution of two variables for
                # calculating difference
                if len(mv1_p.getLatitude()) <= len(mv2_p.getLatitude()):
                    mv1_reg = mv1_p
                    lev_out = mv1_p.getLevel()
                    lat_out = mv1_p.getLatitude()
                    mv2_reg = mv2_p.crossSectionRegrid(lev_out, lat_out)
                    #apply mask back, since crossSectionRegrid doesn't preserve mask
                    mv2_reg = MV2.masked_where(mv2_reg == mv2_reg.fill_value,
                                               mv2_reg)
                    print(mv2_reg.fill_value)
                else:
                    mv2_reg = mv2_p
                    lev_out = mv2_p.getLevel()
                    lat_out = mv2_p.getLatitude()
                    mv1_reg = mv1_p.crossSectionRegrid(lev_out, lat_out)
                    #apply mask back, since crossSectionRegrid doesn't preserve mask
                    mv1_reg = MV2.masked_where(mv1_reg == mv1_reg.fill_value,
                                               mv1_reg)

                #print(mv1_p.shape, mv2_p.shape)
                #mv1_reg, mv2_reg = utils.sregrid_to_lower_res(
                #    mv1_p, mv2_p, parameter.regrid_tool, parameter.regrid_method)
                #reg_mask = MV2.logical_and(mv1_reg.mask, mv2_reg.mask)
                #print('reg_mask', reg_mask[:,-1])
                #mv1_reg = MV2.masked_where(reg_mask,mv1_reg)
                #mv2_reg = MV2.masked_where(reg_mask,mv2_reg)
                #print(mv1_reg.shape)
                #print(mv2_reg.shape)
                #print(mv1_p[:,-1].mask)
                #print(mv2_p[:,-1].mask)

                #print(mv1_reg[:,-1].mask)
                #print(mv2_reg[:,-1].mask)
                # Plotting
                diff = mv1_reg - mv2_reg
                metrics_dict = create_metrics(mv2_p, mv1_p, mv2_reg, mv1_reg,
                                              diff)

                parameter.var_region = 'global'

                plot(parameter.current_set, mv2_p, mv1_p, diff, metrics_dict,
                     parameter)
                utils.save_ncfiles(parameter.current_set, mv1_p, mv2_p, diff,
                                   parameter)

            # for variables without z axis:
            elif mv1.getLevel() == None and mv2.getLevel() == None:

                #select region
                if len(regions) == 0:
                    regions = ['global']

                for region in regions:
                    print("Selected region: {}".format(region))

                    mv1_domain, mv2_domain = utils.select_region(
                        region, mv1, mv2, land_frac, ocean_frac, parameter)

                    parameter.output_file = '-'.join(
                        [ref_name, var, season, region])
                    parameter.main_title = str(' '.join([var, season, region]))

                    # regrid towards lower resolution of two variables for
                    # calculating difference
                    mv1_reg, mv2_reg = utils.regrid_to_lower_res(
                        mv1_domain, mv2_domain, parameter.regrid_tool,
                        parameter.regrid_method)

                    # if var is 'SST' or var is 'TREFHT_LAND': #special case

                    if var == 'TREFHT_LAND' or var == 'SST':  # use "==" instead of "is"
                        if ref_name == 'WILLMOTT':
                            mv2_reg = MV2.masked_where(
                                mv2_reg == mv2_reg.fill_value, mv2_reg)
                            print(ref_name)

                            # if mv.mask is False:
                            #    mv = MV2.masked_less_equal(mv, mv._FillValue)
                            #    print("*************",mv.count())
                        land_mask = MV2.logical_or(mv1_reg.mask, mv2_reg.mask)
                        mv1_reg = MV2.masked_where(land_mask, mv1_reg)
                        mv2_reg = MV2.masked_where(land_mask, mv2_reg)

                    diff = mv1_reg - mv2_reg
                    metrics_dict = create_metrics(mv2_domain, mv1_domain,
                                                  mv2_reg, mv1_reg, diff)
                    parameter.var_region = region

                    plot(parameter.current_set, mv2_domain, mv1_domain, diff,
                         metrics_dict, parameter)
                    utils.save_ncfiles(parameter.current_set, mv1_domain,
                                       mv2_domain, diff, parameter)

            else:
                raise RuntimeError(
                    "Dimensions of two variables are difference. Abort")
        f_obs.close()
        f_mod.close()
    return parameter
Example #8
0
def run_diag(parameter):
    variables = parameter.variables
    seasons = parameter.seasons
    ref_name = getattr(parameter, "ref_name", "")
    regions = parameter.regions

    test_data = utils.dataset.Dataset(parameter, test=True)
    ref_data = utils.dataset.Dataset(parameter, ref=True)

    for season in seasons:
        # Get the name of the data, appended with the years averaged.
        parameter.test_name_yrs = utils.general.get_name_and_yrs(
            parameter, test_data, season)
        parameter.ref_name_yrs = utils.general.get_name_and_yrs(
            parameter, ref_data, season)

        # Get land/ocean fraction for masking.
        try:
            land_frac = test_data.get_climo_variable("LANDFRAC", season)
            ocean_frac = test_data.get_climo_variable("OCNFRAC", season)
        except Exception:
            mask_path = os.path.join(acme_diags.INSTALL_PATH,
                                     "acme_ne30_ocean_land_mask.nc")
            with cdms2.open(mask_path) as f:
                land_frac = f("LANDFRAC")
                ocean_frac = f("OCNFRAC")

        for var in variables:
            print("Variable: {}".format(var))
            parameter.var_id = var

            mv1 = test_data.get_climo_variable(var, season)
            mv2 = ref_data.get_climo_variable(var, season)

            parameter.viewer_descr[var] = (mv1.long_name if hasattr(
                mv1, "long_name") else "No long_name attr in test data.")

            # Special case, cdms didn't properly convert mask with fill value
            # -999.0, filed issue with Denis.
            if ref_name == "WARREN":
                # This is cdms2 fix for bad mask, Denis' fix should fix this.
                mv2 = MV2.masked_where(mv2 == -0.9, mv2)
            # The following should be moved to a derived variable.
            if ref_name == "AIRS":
                # This is cdms2 fix for bad mask, Denis' fix should fix this.
                mv2 = MV2.masked_where(mv2 > 1e20, mv2)
            if ref_name == "WILLMOTT" or ref_name == "CLOUDSAT":
                # This is cdms2 fix for bad mask, Denis' fix should fix this.
                mv2 = MV2.masked_where(mv2 == -999.0, mv2)

                # The following should be moved to a derived variable.
                if var == "PRECT_LAND":
                    days_season = {
                        "ANN": 365,
                        "DJF": 90,
                        "MAM": 92,
                        "JJA": 92,
                        "SON": 91,
                    }
                    # mv1 = mv1 * days_season[season] * 0.1 # following AMWG
                    # Approximate way to convert to seasonal cumulative
                    # precipitation, need to have solution in derived variable,
                    # unit convert from mm/day to cm.
                    mv2 = (mv2 / days_season[season] / 0.1
                           )  # Convert cm to mm/day instead.
                    mv2.units = "mm/day"

            # For variables with a z-axis.
            if mv1.getLevel() and mv2.getLevel():
                plev = parameter.plevs
                print("Selected pressure level: {}".format(plev))

                mv1_p = utils.general.convert_to_pressure_levels(
                    mv1, plev, test_data, var, season)
                mv2_p = utils.general.convert_to_pressure_levels(
                    mv2, plev, ref_data, var, season)

                # Select plev.
                for ilev in range(len(plev)):
                    mv1 = mv1_p[ilev, ]
                    mv2 = mv2_p[ilev, ]

                    for region in regions:
                        # print("Selected region: {}".format(region))

                        mv1_domain = utils.general.select_region(
                            region, mv1, land_frac, ocean_frac, parameter)
                        mv2_domain = utils.general.select_region(
                            region, mv2, land_frac, ocean_frac, parameter)

                        parameter.output_file = "-".join([
                            ref_name,
                            var,
                            str(int(plev[ilev])),
                            season,
                            region,
                        ])
                        parameter.main_title = str(" ".join([
                            var,
                            str(int(plev[ilev])),
                            "mb",
                            season,
                            region,
                        ]))

                        # Regrid towards the lower resolution of the two
                        # variables for calculating the difference.
                        mv1_reg, mv2_reg = utils.general.regrid_to_lower_res(
                            mv1_domain,
                            mv2_domain,
                            parameter.regrid_tool,
                            parameter.regrid_method,
                        )

                        diff = mv1_reg - mv2_reg
                        metrics_dict = create_metrics(mv2_domain, mv1_domain,
                                                      mv2_reg, mv1_reg, diff)

                        # Saving the metrics as a json.
                        metrics_dict["unit"] = mv1_reg.units
                        fnm = os.path.join(
                            utils.general.get_output_dir(
                                parameter.current_set, parameter),
                            parameter.output_file + ".json",
                        )
                        with open(fnm, "w") as outfile:
                            json.dump(metrics_dict, outfile)
                        # Get the filename that the user has passed in and display that.
                        # When running in a container, the paths are modified.
                        fnm = os.path.join(
                            utils.general.get_output_dir(
                                parameter.current_set,
                                parameter,
                                ignore_container=True,
                            ),
                            parameter.output_file + ".json",
                        )
                        # print('Metrics saved in: ' + fnm)

                        parameter.var_region = region
                        plot(
                            parameter.current_set,
                            mv2_domain,
                            mv1_domain,
                            diff,
                            metrics_dict,
                            parameter,
                        )
                        utils.general.save_ncfiles(
                            parameter.current_set,
                            mv1_domain,
                            mv2_domain,
                            diff,
                            parameter,
                        )

            # For variables without a z-axis.
            elif mv1.getLevel() is None and mv2.getLevel() is None:
                for region in regions:
                    # print("Selected region: {}".format(region))

                    mv1_domain = utils.general.select_region(
                        region, mv1, land_frac, ocean_frac, parameter)
                    mv2_domain = utils.general.select_region(
                        region, mv2, land_frac, ocean_frac, parameter)

                    parameter.output_file = "-".join(
                        [ref_name, var, season, region])
                    parameter.main_title = str(" ".join([var, season, region]))

                    # Regrid towards the lower resolution of the two
                    # variables for calculating the difference.
                    mv1_reg, mv2_reg = utils.general.regrid_to_lower_res(
                        mv1_domain,
                        mv2_domain,
                        parameter.regrid_tool,
                        parameter.regrid_method,
                    )

                    # Special case.
                    if var == "TREFHT_LAND" or var == "SST":
                        if ref_name == "WILLMOTT":
                            mv2_reg = MV2.masked_where(
                                mv2_reg == mv2_reg.fill_value, mv2_reg)

                        land_mask = MV2.logical_or(mv1_reg.mask, mv2_reg.mask)
                        mv1_reg = MV2.masked_where(land_mask, mv1_reg)
                        mv2_reg = MV2.masked_where(land_mask, mv2_reg)

                    diff = mv1_reg - mv2_reg
                    metrics_dict = create_metrics(mv2_domain, mv1_domain,
                                                  mv2_reg, mv1_reg, diff)

                    # Saving the metrics as a json.
                    metrics_dict["unit"] = mv1_reg.units
                    fnm = os.path.join(
                        utils.general.get_output_dir(parameter.current_set,
                                                     parameter),
                        parameter.output_file + ".json",
                    )
                    with open(fnm, "w") as outfile:
                        json.dump(metrics_dict, outfile)
                    # Get the filename that the user has passed in and display that.
                    # When running in a container, the paths are modified.
                    fnm = os.path.join(
                        utils.general.get_output_dir(
                            parameter.current_set,
                            parameter,
                            ignore_container=True,
                        ),
                        parameter.output_file + ".json",
                    )
                    # print('Metrics saved in: ' + fnm)

                    parameter.var_region = region
                    plot(
                        parameter.current_set,
                        mv2_domain,
                        mv1_domain,
                        diff,
                        metrics_dict,
                        parameter,
                    )
                    utils.general.save_ncfiles(
                        parameter.current_set,
                        mv1_domain,
                        mv2_domain,
                        diff,
                        parameter,
                    )

            else:
                raise RuntimeError(
                    "Dimensions of the two variables are different. Aborting.")

    return parameter
Example #9
0
def harmonic(data, k=3):
    
    data = data.reorder('t...')
    cdutil.setAxisTimeBoundsDaily(data.getTime())
    axislist = data.getAxisList()
    dataid = data.id 
    
    daily = True 
    monthly = False
    
    timeAxis = axislist[0]
    N = 365. #len(timeAxis)
#    P = 10. # 10 year, yearly harmonic oscilation
#    P = 10*12 # 10 year, monthly harmonic oscilation
#    P = 10*365 # 10 year, daily harmonic oscilation 
#    if P > N:
#        raise ValueError("P('%d') value should not exceed N(%d)" % (P,N))
        
    if k > N/2:
        raise ValueError("k value should not exceed (%d) i.e. N/2 value" % (N/2))
    
    if len(timeAxis) > 366:
        print 'found more than 1 year data.'
#        y_t = dailyClimatology(data, action='sum')
    else:
        y_t = data 
    # end of if len(timeAxis) > 366:
    
    Y_0 = cdutil.averager(data, axis='t', action='average', weights='equal')

    # make memory free
    del data 
        
    t = numpy.arange(1, N+1, dtype='float')
    
    otheraxis = list(Y_0.shape)
    ax_product = 1
    for ax in otheraxis:
        ax_product *= ax
    otheraxis.insert(0,N)
    t = t.repeat(ax_product).reshape(otheraxis)    
    angle = 2 * math.pi * t/N
    Y_k = 0.
    
    for i in range(1,k+1):
    
        kangle = angle*i
       
        A_k = (2./N) * cdutil.averager(y_t * numpy.cos(kangle), axis='t', action='sum')
        B_k = (2./N) * cdutil.averager(y_t * numpy.sin(kangle), axis='t', action='sum')   
        C_k = MV2.sqrt((A_k*A_k) + (B_k*B_k))
        
        # if A_k is positiv, then retain this phase_angle as it is.
        # phase_angle should be in degrees
        phase_angle = phase_arc_angle = MV2.arctan(B_k/A_k) 
        
        # if A_k is zero, then replace phase_angle with pi/2 else retain same
        phase_angle = MV2.where(MV2.equal(A_k, 0.), math.pi/2.0, phase_arc_angle)
               
        # if A_k is negative, then add pi with phase_angle (if it is <= pi ) 
        condition1 = MV2.logical_and(MV2.less(A_k, 0.), MV2.less_equal(phase_arc_angle, math.pi))
        phase_angle = MV2.where(condition1, phase_arc_angle+math.pi, phase_arc_angle)
        # if A_k is negative, then subtract pi from phase_angle (if it is > pi ) 
        condition2 = MV2.logical_and(MV2.less(A_k, 0.), MV2.greater(phase_arc_angle, math.pi)) 
        condition3 = MV2.logical_or(condition1, condition2)
        phase_angle = MV2.where(condition3, phase_arc_angle-math.pi, phase_arc_angle)
    
        # make memory free 
        del phase_arc_angle
        
        if daily and not monthly:
            # subtract 15 days lag to adjust phase_angle w.r.t daily
            print "Daily Subtraction"
            phase_angle -= (15.*2*math.pi)/N
        # end of if daily and not monthly:

        phase_angle = numpy.array(phase_angle)
#        phase_angle = numpy.tile(phase_angle, N).reshape(kangle.shape)         
        kangle = numpy.array(kangle)
        Y_k += C_k * MV2.cos(kangle - phase_angle)
    # end of for i in range(1,k+1):
    
    # add mean to the sum of first k-th harmonic of data 
    Y_k += Y_0
    
    # make memory free
    del y_t, Y_0
    
    sumOfMean_and_first_k_harmonic = cdms2.createVariable(Y_k, id=dataid)
    sumOfMean_and_first_k_harmonic.setAxisList(axislist)
    sumOfMean_and_first_k_harmonic.comments = 'sumOfMean_and_first_%d_harmonic' % k
    
    # make memory free
    del Y_k
    
    # return result
    return sumOfMean_and_first_k_harmonic
Example #10
0
def run_diag(parameter):
    variables = parameter.variables
    seasons = parameter.seasons
    ref_name = getattr(parameter, "ref_name", "")
    regions = parameter.regions

    test_data = utils.dataset.Dataset(parameter, test=True)
    ref_data = utils.dataset.Dataset(parameter, ref=True)

    for season in seasons:
        # Get the name of the data, appended with the years averaged.
        parameter.test_name_yrs = utils.general.get_name_and_yrs(
            parameter, test_data, season)
        parameter.ref_name_yrs = utils.general.get_name_and_yrs(
            parameter, ref_data, season)

        # Get land/ocean fraction for masking.
        try:
            land_frac = test_data.get_climo_variable("LANDFRAC", season)
            ocean_frac = test_data.get_climo_variable("OCNFRAC", season)
        except Exception:
            mask_path = os.path.join(acme_diags.INSTALL_PATH,
                                     "acme_ne30_ocean_land_mask.nc")
            with cdms2.open(mask_path) as f:
                land_frac = f("LANDFRAC")
                ocean_frac = f("OCNFRAC")

        for var in variables:
            print("Variable: {}".format(var))
            parameter.var_id = var

            mv1 = test_data.get_climo_variable(var, season)
            mv2 = ref_data.get_climo_variable(var, season)

            parameter.viewer_descr[var] = (mv1.long_name if hasattr(
                mv1, "long_name") else "No long_name attr in test data.")

            # Special case, cdms didn't properly convert mask with fill value
            # -999.0, filed issue with Denis.
            if ref_name == "WARREN":
                # This is cdms2 fix for bad mask, Denis' fix should fix this.
                mv2 = MV2.masked_where(mv2 == -0.9, mv2)
            # The following should be moved to a derived variable.
            if ref_name == "AIRS":
                # This is cdms2 fix for bad mask, Denis' fix should fix this.
                mv2 = MV2.masked_where(mv2 > 1e20, mv2)
            if ref_name == "WILLMOTT" or ref_name == "CLOUDSAT":
                # This is cdms2 fix for bad mask, Denis' fix should fix this.
                mv2 = MV2.masked_where(mv2 == -999.0, mv2)

                # The following should be moved to a derived variable.
                if var == "PRECT_LAND":
                    days_season = {
                        "ANN": 365,
                        "DJF": 90,
                        "MAM": 92,
                        "JJA": 92,
                        "SON": 91,
                    }
                    # mv1 = mv1 * days_season[season] * 0.1 # following AMWG
                    # Approximate way to convert to seasonal cumulative
                    # precipitation, need to have solution in derived variable,
                    # unit convert from mm/day to cm.
                    mv2 = (mv2 / days_season[season] / 0.1
                           )  # Convert cm to mm/day instead.
                    mv2.units = "mm/day"

            # For variables with a z-axis.
            if mv1.getLevel() and mv2.getLevel():
                # Since the default is now stored in ZonalMean2dParameter,
                # we must get it from there if the plevs param is blank.
                plevs = parameter.plevs
                if (isinstance(plevs, numpy.ndarray) and not plevs.all()) or (
                        not isinstance(plevs, numpy.ndarray) and not plevs):
                    plevs = ZonalMean2dParameter().plevs

                # print('Selected pressure level: {}'.format(plevs))

                mv1_p = utils.general.convert_to_pressure_levels(
                    mv1, plevs, test_data, var, season)
                mv2_p = utils.general.convert_to_pressure_levels(
                    mv2, plevs, ref_data, var, season)

                mv1_p = cdutil.averager(mv1_p, axis="x")
                mv2_p = cdutil.averager(mv2_p, axis="x")

                parameter.output_file = "-".join(
                    [ref_name, var, season, parameter.regions[0]])
                parameter.main_title = str(" ".join([var, season]))

                # Regrid towards the lower resolution of the two
                # variables for calculating the difference.
                if len(mv1_p.getLatitude()) < len(mv2_p.getLatitude()):
                    mv1_reg = mv1_p
                    lev_out = mv1_p.getLevel()
                    lat_out = mv1_p.getLatitude()
                    mv2_reg = mv2_p.crossSectionRegrid(lev_out, lat_out)
                    # Apply the mask back, since crossSectionRegrid
                    # doesn't preserve the mask.
                    mv2_reg = MV2.masked_where(mv2_reg == mv2_reg.fill_value,
                                               mv2_reg)
                elif len(mv1_p.getLatitude()) > len(mv2_p.getLatitude()):
                    mv2_reg = mv2_p
                    lev_out = mv2_p.getLevel()
                    lat_out = mv2_p.getLatitude()
                    mv1_reg = mv1_p.crossSectionRegrid(lev_out, lat_out)
                    # Apply the mask back, since crossSectionRegrid
                    # doesn't preserve the mask.
                    mv1_reg = MV2.masked_where(mv1_reg == mv1_reg.fill_value,
                                               mv1_reg)
                else:
                    mv1_reg = mv1_p
                    mv2_reg = mv2_p

                diff = mv1_reg - mv2_reg
                metrics_dict = create_metrics(mv2_p, mv1_p, mv2_reg, mv1_reg,
                                              diff)

                parameter.var_region = "global"

                plot(
                    parameter.current_set,
                    mv2_p,
                    mv1_p,
                    diff,
                    metrics_dict,
                    parameter,
                )
                utils.general.save_ncfiles(parameter.current_set, mv1_p, mv2_p,
                                           diff, parameter)

            # For variables without a z-axis.
            elif mv1.getLevel() is None and mv2.getLevel() is None:
                for region in regions:
                    # print("Selected region: {}".format(region))

                    mv1_domain = utils.general.select_region(
                        region, mv1, land_frac, ocean_frac, parameter)
                    mv2_domain = utils.general.select_region(
                        region, mv2, land_frac, ocean_frac, parameter)

                    parameter.output_file = "-".join(
                        [ref_name, var, season, region])
                    parameter.main_title = str(" ".join([var, season, region]))

                    # Regrid towards the lower resolution of the two
                    # variables for calculating the difference.
                    mv1_reg, mv2_reg = utils.general.regrid_to_lower_res(
                        mv1_domain,
                        mv2_domain,
                        parameter.regrid_tool,
                        parameter.regrid_method,
                    )

                    # Special case.
                    if var == "TREFHT_LAND" or var == "SST":
                        if ref_name == "WILLMOTT":
                            mv2_reg = MV2.masked_where(
                                mv2_reg == mv2_reg.fill_value, mv2_reg)
                        land_mask = MV2.logical_or(mv1_reg.mask, mv2_reg.mask)
                        mv1_reg = MV2.masked_where(land_mask, mv1_reg)
                        mv2_reg = MV2.masked_where(land_mask, mv2_reg)

                    diff = mv1_reg - mv2_reg
                    metrics_dict = create_metrics(mv2_domain, mv1_domain,
                                                  mv2_reg, mv1_reg, diff)
                    parameter.var_region = region

                    plot(
                        parameter.current_set,
                        mv2_domain,
                        mv1_domain,
                        diff,
                        metrics_dict,
                        parameter,
                    )
                    utils.general.save_ncfiles(
                        parameter.current_set,
                        mv1_domain,
                        mv2_domain,
                        diff,
                        parameter,
                    )

            else:
                raise RuntimeError(
                    "Dimensions of the two variables are different. Aborting.")

    return parameter
Example #11
0
def harmonic(data, k=3, time_type='daily', phase_shift=15):
    """     
    Inputs : 
        data : climatology data 
        k : Integer no to compute K th harmonic. By default it takes 3.
        time_type : daily | monthly | full (time type of input climatology)
                    'daily' -> it returns 365 days harmonic,
                    'monthly' -> it returns 12 month harmonic,
                    'full' -> it retuns harmonic for full length of 
                    input data. 
                    
        phase_shift : Used to subtract 'phase_shift' days lag to adjust
                      phase_angle w.r.t daily or monthly. By default it takes
                      15 days lag to adjust phase_angle w.r.t daily data.
                      User can pass None disable this option.
    
    Returns :
        Returns "sum mean of mean and first K th harmonic" of input 
        climatology data. 
    
    Concept :
    
    Earth science data consists of a strong seasonality component as 
    indicated by the cycles of repeated patterns in climate variables such 
    as air pressure, temperature and precipitation. The seasonality forms 
    the strongest signals in this data and in order to find other patterns,
    the seasonality is removed by subtracting the monthly mean values of the
    raw data for each month. However since the raw data like air temperature,
    pressure, etc. are constantly being generated with the help of satellite
    observations, the climate scientists usually use a moving reference base 
    interval of some years of raw data to calculate the mean in order to 
    generate the anomaly time series and study the changes with respect to
    that. 
    
    Fourier series analysis decomposes a signal into an infinite series of 
    harmonic components. Each of these components is comprised initially of 
    a sine wave and a cosine wave of equal integer frequency. These two waves
    are then combined into a single cosine wave, which has characteristic 
    amplitude (size of the wave) and phase angle (offset of the wave). 
    Convergence has been established for bounded piecewise continuous 
    functions on a closed interval, with special conditions at points of
    discontinuity. Its convergence has been established for other conditions
    as well, but these are not relevant to the analysis at hand.
    
    Reference: Daniel S Wilks, 'Statistical Methods in the Atmospheric 
               Sciences' second Edition, page no(372-378).
               
    Written By : Arulalan.T
    
    Date : 16.05.2014
    
    """
    
    data = data.reorder('t...')
    cdutil.setAxisTimeBoundsDaily(data.getTime())
    axislist = data.getAxisList()
    timeAxis = axislist[0]
    dataid = data.id     
    
    if time_type in ['daily']:
        N = 365.0   # must be float 
    elif time_type[:3] in ['mon']:
        N = 12.0    # must be float 
    elif time_type in ['full']:
        N = float(len(timeAxis))
        
    if k > N/2:
        raise ValueError("k value should not exceed (%d) i.e. N/2 value" % (N/2))
    
    if len(timeAxis) > 366:
        print 'found more than 1 year data.'
        raise ValueError("Kindly pass only climatology data")
    else:
        y_t = data 
    # end of if len(timeAxis) > 366:
    
    Y_0 = cdutil.averager(data, axis='t', action='average', weights='equal')

    # make memory free
    del data 
        
    t = numpy.arange(1, N+1, dtype='float')
    
    otheraxis = list(Y_0.shape)
    ax_product = 1
    for ax in otheraxis:
        ax_product *= ax
    otheraxis.insert(0,N)
    t = t.repeat(ax_product).reshape(otheraxis)    
    angle = 2 * math.pi * t/N
    Y_k = 0.
    
    for i in range(1,k+1):
    
        kangle = angle*i
       
        A_k = (2./N) * cdutil.averager(y_t * numpy.cos(kangle), axis='t', action='sum')
        B_k = (2./N) * cdutil.averager(y_t * numpy.sin(kangle), axis='t', action='sum')   
        C_k = MV2.sqrt((A_k*A_k) + (B_k*B_k))
        
        # if A_k is positiv, then retain this phase_angle as it is.
        # phase_angle should be in degrees
        phase_angle = phase_arc_angle = MV2.arctan(B_k/A_k) 
        
        # if A_k is zero, then replace phase_angle with pi/2 else retain same
        phase_angle = MV2.where(MV2.equal(A_k, 0.), math.pi/2.0, phase_arc_angle)
               
        # if A_k is negative, then add pi with phase_angle (if it is <= pi ) 
        condition1 = MV2.logical_and(MV2.less(A_k, 0.), MV2.less_equal(phase_arc_angle, math.pi))
        phase_angle = MV2.where(condition1, phase_arc_angle+math.pi, phase_arc_angle)
        # if A_k is negative, then subtract pi from phase_angle (if it is > pi ) 
        condition2 = MV2.logical_and(MV2.less(A_k, 0.), MV2.greater(phase_arc_angle, math.pi)) 
        condition3 = MV2.logical_or(condition1, condition2)
        phase_angle = MV2.where(condition3, phase_arc_angle-math.pi, phase_arc_angle)
    
        # make memory free 
        del phase_arc_angle
        
        if phase_shift:
            # subtract 15 days lag to adjust phase_angle w.r.t daily
            phase_angle -= (phase_shift *2 * math.pi) / N
        # end of if daily and not monthly:

        phase_angle = numpy.array(phase_angle)
        kangle = numpy.array(kangle)
        Y_k += C_k * MV2.cos(kangle - phase_angle)
    # end of for i in range(1,k+1):
    
    # add mean to the sum of first k-th harmonic of data 
    Y_k += Y_0
    
    # make memory free
    del y_t, Y_0
    
    sumOfMean_and_first_k_harmonic = cdms2.createVariable(Y_k, id=dataid)
    sumOfMean_and_first_k_harmonic.setAxisList(axislist)
    sumOfMean_and_first_k_harmonic.comments = 'sumOfMean_and_first_%d_harmonic' % k
    
    # make memory free
    del Y_k
    
    # return result
    return sumOfMean_and_first_k_harmonic