Example #1
0
def main():
    global IDX_ORGN
    global lowpcut, highpcut
    parser = argparse.ArgumentParser()
    parser.add_argument("-y", "--year", type=int, help="year")
    parser.add_argument("-m",
                        "--month",
                        type=int,
                        choices=1 + np.arange(12),
                        help="month")
    parser.add_argument("-a",
                        "--advect",
                        type=str,
                        choices=["EID", "EIZ"],
                        help="source of advecting winds")
    parser.add_argument("-s", "--suffix", type=str, help="suffix")
    #parser.add_argument("-l","--level",type=int,help="P level")
    parser.add_argument("-q",
                        "--quiet",
                        type=str,
                        choices=["y", "n"],
                        help="quiet (y) or not (n)")
    parser.add_argument("-ct",
                        "--cloud_type",
                        type=str,
                        choices=["meanhigh", "veryhigh"],
                        help="cloud type filter")
    parser.add_argument("-t",
                        "--step",
                        type=int,
                        help="step in hours between two part files")
    parser.add_argument("-d",
                        "--duration",
                        type=int,
                        help="duration of integration in hours")
    parser.add_argument("-gs",
                        "--granule_size",
                        type=int,
                        help="size of the granule")
    parser.add_argument("-gn",
                        "--granule_step",
                        type=int,
                        help="number of granules in a step")
    parser.add_argument("-ab", "--age_bound", type=int, help="age_bound")
    parser.add_argument("-binx",
                        "--binx",
                        type=int,
                        help="number of grid points in longitude direction")
    parser.add_argument("-biny",
                        "--biny",
                        type=int,
                        help="number of grid points in latitude direction")
    parser.add_argument("-hmax",
                        "--hmax",
                        type=int,
                        help='maximum number of hours in traczilla simulation')
    parser.add_argument("-username", "--username", type=str, help='username')
    parser.add_argument("-userout", "--userout", type=str, help='userout')
    """ Parsed parameters"""
    # Parsed parameters
    # Interval between two part files (in hours)
    step = 6
    # Largest time to be processed (in hours)
    hmax = 1464
    # Age limit in days
    age_bound = 30
    # start date of the backward run, corresponding to itime=0
    year = 2017
    # 8 +1 means we start on September 1 at 0h and cover the whole month of August
    month = 6 + 1
    advect = 'EIZ'
    suffix = '_150_150hPa_500'
    quiet = False
    cloud_type = 'veryhigh'
    # Bound on the age of the parcel (in days)
    age_bound = 30
    # Number of parcels launched per time slot (grid size)
    binx = 320
    biny = 224
    # Number of granules in a step betwwen two part files
    granule_step = 6
    """ Non parsed parameters"""
    # Time width of the parcel slice
    slice_width = timedelta(minutes=5)
    # dtRange (now defined in satmap definition)
    #dtRange={'MSG1':timedelta(minutes=15),'Hima':timedelta(minutes=20)}
    # day=1 should not be changed
    day = 1
    # low p cut applied in exiter
    lowpcut = 3000
    # high p cut applied in exiter
    highpcut = 50000

    args = parser.parse_args()
    if args.year is not None: year = args.year
    if args.month is not None: month = args.month + 1
    if args.advect is not None: advect = args.advect
    if args.suffix is not None: suffix = args.suffix
    #if args.level is not None: level=args.level
    if args.quiet is not None:
        if args.quiet == 'y': quiet = True
        else: quiet = False
    if args.cloud_type is not None: cloud_type = args.cloud_type
    if args.step is not None: step = args.step
    if args.hmax is not None: hmax = args.hmax
    if args.binx is not None: binx = args.binx
    if args.biny is not None: biny = args.biny
    granule_size = binx * biny
    if args.granule_size is not None: granule_size = args.granule_size
    if args.duration is not None: hmax = args.duration
    if args.age_bound is not None: age_bound = args.age_bound
    if args.granule_step is not None: granule_step = args.granule_step
    if args.username is not None: username = args.username
    if args.userout is not None: userout = args.userout

    # Define main directories
    main_sat_dir = '/bdd/STRATOCLIM/flexpart_in'
    if 'ciclad' in socket.gethostname():
        traj_dir = os.path.join('/data/', username, 'flexout', 'COCHIN',
                                'BACK')
        out_dir = os.path.join('/data', userout, 'STC')
    elif ('climserv' in socket.gethostname()) | ('polytechnique'
                                                 in socket.gethostname()):
        traj_dir = os.path.join('/homedata/', username, 'flexout', 'COCHIN',
                                'BACK')
        out_dir = os.path.join('/homedata', userout, 'STC')
    else:
        print('CANNOT RECOGNIZE HOST - DO NOT RUN ON NON DEFINED HOSTS')
        exit()

    # Output diretories
    # Update the out_dir with the cloud type
    out_dir = os.path.join(out_dir, 'STC-BACK-OUT-Cochin-SAF-' + cloud_type)

    sdate = datetime(year, month, day)
    # fdate defined to make output under the name of the month where parcels are released
    fdate = sdate - timedelta(days=1)

    # Number of slices between two outputs
    dstep = timedelta(hours=step)
    nb_slices = int(dstep / slice_width)

    # size of granules launched during a step
    granule_quanta = granule_size * granule_step

    # Manage the file that receives the print output
    if quiet:
        # Output file
        print_file = os.path.join(
            out_dir, 'out',
            'BACK-' + advect + fdate.strftime('-%b-%Y') + suffix + '.out')
        fsock = open(print_file, 'w')
        sys.stdout = fsock

    print('year', year, 'month', month, 'day', day)
    print('advect', advect)
    print('suffix', suffix)

    # Directory of the backward trajectories
    ftraj = os.path.join(traj_dir,
                         'BACK-' + advect + fdate.strftime('-%b-%Y') + suffix)

    # Output file
    out_file = os.path.join(
        out_dir,
        'BACK-' + advect + fdate.strftime('-%b-%Y') + suffix + '.hdf5z')
    #out_file1 = os.path.join(out_dir,'BACK-'+advect+fdate.strftime('-%b-%Y-')+str(level)+'K'+suffix+'.hdf5b')
    #out_file2 = os.path.join(out_dir,'BACK-'+advect+fdate.strftime('-%b-%Y-')+str(level)+'K'+suffix+'.pkl')

    # Directories for the satellite cloud top files
    satdir ={'MSG1':os.path.join(main_sat_dir,'msg1','S_NWC'),\
             'Hima':os.path.join(main_sat_dir,'himawari','S_NWC')}
    """ Initialization of the calculation """
    # Initialize the grid
    gg = geosat.GeoGrid('FullAMA_SAFBox')
    # Initialize the dictionary of the parcel dictionaries
    partStep = {}
    satmap = pixmap(gg)

    # Build the satellite field generator
    get_sat = {'MSG1': read_sat(sdate,'MSG1',satmap.zone['MSG1']['dtRange'],satdir['MSG1'],pre=True),\
               'Hima': read_sat(sdate,'Hima',satmap.zone['Hima']['dtRange'],satdir['Hima'],pre=True)}

    # Open the part_000 file that contains the initial positions
    part0 = readidx107(os.path.join(ftraj, 'part_000'), quiet=True)
    print('numpart', part0['numpart'])
    numpart = part0['numpart']
    numpart_s = granule_size

    # stamp_date not set in these runs
    # current_date actually shifted by one day / sdate
    current_date = sdate
    # check flag is clean
    print('check flag is clean ',((part0['flag']&I_HIT)!=0).sum(),((part0['flag']&I_DEAD)!=0).sum(),\
                                 ((part0['flag']&I_CROSSED)!=0).sum())
    # check idx_orgn
    if part0['idx_orgn'] != 0:
        print('MINCHIA, IDX_ORGN NOT 0 AS ASSUMED, CORRECTED WITH READ VALUE')
        print('VALUE ', part0['idx_orgn'])
        IDX_ORGN = part0['idx_orgn']
    idx1 = IDX_ORGN

    # Build a dictionary to host the results
    prod0 = defaultdict(dict)
    prod0['src']['x'] = np.full(part0['numpart'],
                                fill_value=np.nan,
                                dtype='float')
    prod0['src']['y'] = np.full(part0['numpart'],
                                fill_value=np.nan,
                                dtype='float')
    prod0['src']['p'] = np.full(part0['numpart'],
                                fill_value=np.nan,
                                dtype='float')
    prod0['src']['t'] = np.full(part0['numpart'],
                                fill_value=np.nan,
                                dtype='float')
    prod0['src']['age'] = np.full(part0['numpart'],
                                  fill_value=np.nan,
                                  dtype='int')
    prod0['flag_source'] = part0['flag']
    prod0['rvs'] = np.full(part0['numpart'], 0.01, dtype='float')

    # truncate eventually to 32 bits at the output stage

    # read the part_000 file for the first granule
    partStep[0] = {}
    partStep[0]['x'] = part0['x'][:granule_size]
    partStep[0]['y'] = part0['y'][:granule_size]
    partStep[0]['t'] = part0['t'][:granule_size]
    partStep[0]['p'] = part0['p'][:granule_size]
    partStep[0]['t'] = part0['t'][:granule_size]
    partStep[0]['idx_back'] = part0['idx_back'][:granule_size]
    partStep[0]['ir_start'] = part0['ir_start'][:granule_size]
    partStep[0]['itime'] = 0

    # number of hists and exits
    nhits = 0
    nexits = 0
    ndborne = 0
    nnew = granule_size
    nold = 0

    # used to get non borne parcels
    new = np.empty(part0['numpart'], dtype='bool')
    new.fill(False)

    print('Initialization completed')
    """ Main loop on the output time steps """
    for hour in range(step, hmax + 1, step):
        pid = os.getpid()
        py = psutil.Process(pid)
        memoryUse = py.memory_info()[0] / 2**30
        print('memory use: {:4.2f} gb'.format(memoryUse))
        # Get rid of dictionary no longer used
        if hour >= 2 * step: del partStep[hour - 2 * step]

        # Read the new data
        partStep[hour] = readpart107(hour, ftraj, quiet=True)
        # Link the names as views
        partante = partStep[hour - step]
        partpost = partStep[hour]
        if partpost['nact'] > 0:
            print('hour ', hour, '  numact ', partpost['nact'], '  max p ',
                  partpost['p'].max())
        else:
            print('hour ', hour, '  numact ', partpost['nact'])
        # New date valid for partpost
        current_date -= dstep

        # Processing of water mixing ratio
        # Select non stopped parcels in partante
        selec = (prod0['flag_source'][partante['idx_back'] - IDX_ORGN]
                 & I_STOP) == 0
        idx = partante['idx_back'][selec]
        prod0['rvs'][idx-IDX_ORGN] = np.minimum(prod0['rvs'][idx-IDX_ORGN],\
                satratio(partante['p'][selec],partante['t'][selec]))
        """ Select the parcels that are common to the two steps
        ketp_a is a logical field with same length as partante
        kept_p is a logical field with same length as partpost
        After the launch of the earliest parcel along the flight track, there
        should not be any member in new.
        """
        kept_a = np.in1d(partante['idx_back'],
                         partpost['idx_back'],
                         assume_unique=True)
        kept_p = np.in1d(partpost['idx_back'],
                         partante['idx_back'],
                         assume_unique=True)
        #new_p = ~np.in1d(partpost['idx_back'],partpost['idx_back'],assume_unique=True)
        print('kept a, p ', len(kept_a), len(kept_p), kept_a.sum(),
              kept_p.sum(), '  new ',
              len(partpost['x']) - kept_p.sum())
        nnew += len(partpost['x']) - kept_p.sum()
        """ PROCESSING OF DEADBORNE PARCELS
        Manage the parcels launched during the last 6-hour which have already
        exited and do not appear in posold or posact (borne dead parcels).
        These parcels are stored in the last part of posact, at most
        the last granule_quanta parcels. """
        if numpart_s < numpart:
            print("manage deadborne", flush=True)
            # First index of the current quanta """
            numpart_s += granule_quanta
            print("idx1", idx1, " numpart_s", numpart_s)
            # Extract the last granule_size indexes from posacti, this is where the new parcels should be
            if hour == step:
                idx_act = partpost['idx_back']
            else:
                idx_act = partpost['idx_back'][-granule_quanta:]
            # Generate the list of indexes that should be found in this range
            # ACHTUNG ACHTUNG : this works because IDX_ORGN=1, FIX THAT
            idx_theor = np.arange(idx1, numpart_s + IDX_ORGN)
            # Find the missing indexes in idx_act (make a single line after validation)
            kept_borne = np.in1d(idx_theor, idx_act, assume_unique=True)
            idx_deadborne = idx_theor[~kept_borne]
            # Process these parcels by assigning exit at initial location
            prod0['flag_source'][
                idx_deadborne -
                IDX_ORGN] = prod0['flag_source'][idx_deadborne -
                                                 IDX_ORGN] | I_DEAD + I_DBORNE
            prod0['src']['x'][idx_deadborne -
                              IDX_ORGN] = part0['x'][idx_deadborne - IDX_ORGN]
            prod0['src']['y'][idx_deadborne -
                              IDX_ORGN] = part0['y'][idx_deadborne - IDX_ORGN]
            prod0['src']['p'][idx_deadborne -
                              IDX_ORGN] = part0['p'][idx_deadborne - IDX_ORGN]
            prod0['src']['t'][idx_deadborne -
                              IDX_ORGN] = part0['t'][idx_deadborne - IDX_ORGN]
            prod0['src']['age'][idx_deadborne - IDX_ORGN] = 0.
            print("number of deadborne ", len(idx_deadborne))
            ndborne += len(idx_deadborne)
            idx1 = numpart_s + IDX_ORGN
        """ PROCESSING OF CROSSED PARCELS """
        if len(kept_a) > 0:
            exits = exiter(int((partante['itime']+partpost['itime'])/2), \
                partante['x'][~kept_a],partante['y'][~kept_a],partante['p'][~kept_a],\
                partante['t'][~kept_a],partante['idx_back'][~kept_a],\
                prod0['flag_source'],prod0['src']['x'],prod0['src']['y'],\
                prod0['src']['p'],prod0['src']['t'],prod0['src']['age'],\
                part0['ir_start'], satmap.range)
            nexits += exits
            print('exit ', nexits, exits, np.sum(~kept_a),
                  len(kept_a) - len(kept_p))
        """ PROCESSING OF PARCELS WHICH ARE COMMON TO THE TWO OUTPUTS  """
        # Select the kept parcels which have not been hit yet
        # !!! Never use and between two lists, the result is wrong

        if kept_p.sum() == 0:
            live_a = live_p = kept_p
        else:
            live_a = np.logical_and(
                kept_a, (prod0['flag_source'][partante['idx_back'] - IDX_ORGN]
                         & I_DEAD) == 0)
            live_p = np.logical_and(
                kept_p, (prod0['flag_source'][partpost['idx_back'] - IDX_ORGN]
                         & I_DEAD) == 0)
        print('live a, b ', live_a.sum(), live_p.sum())
        del kept_a
        del kept_p
        """ Correction step that moves partante['x'] to avoid big jumps at the periodicity frontier on the x-axis """
        diffx = partpost['x'][live_p] - partante['x'][live_a]
        bb = np.zeros(len(diffx))
        bb[diffx > 180] = 360
        bb[diffx < -180] = -360
        partante['x'][live_a] += bb
        del bb
        del diffx
        # DOES not work in the following WAY
        #partante['x'][live_a][diffx>180] += 360
        #partante['x'][live_a][diffx<-180] -= 360

        # Build generator for parcel locations of the 5' slices
        gsp = get_slice_part(partante, partpost, live_a, live_p, current_date,
                             dstep, slice_width)
        if verbose: print('built parcel generator for ', current_date)
        """  MAIN LOOP ON THE PARCEL TIME SLICES  """

        for i in range(nb_slices):
            # get the slice for the particles
            datpart = next(gsp)
            if verbose: print('part slice ', i, datpart['time'])
            # Check whether the present satellite image is valid
            # The while should ensure that the run synchronizes
            # when it starts.

            while satmap.check('MSG1', datpart['time']) is False:
                # if not get next satellite image
                datsat1 = next(get_sat['MSG1'])
                # Check that the image is available
                if datsat1 is not None:
                    pm1 = geosat.SatGrid(datsat1, gg)
                    pm1._sat_togrid('CTTH_PRESS')
                    #print('pm1 diag',len(datsat1.var['CTTH_PRESS'][:].compressed()),
                    #                 len(pm1.var['CTTH_PRESS'][:].compressed()))
                    pm1._sat_togrid('CT')
                    pm1.attr = datsat1.attr.copy()
                    satmap.fill('MSG1', pm1, cloud_type)
                    del pm1
                    del datsat1
                else:
                    # if the image is missing, extend the lease
                    try:
                        satmap.extend('MSG1')
                    except:
                        # This handle the unlikely case where the first image is missing
                        continue
            while satmap.check('Hima', datpart['time']) is False:
                # if not get next satellite image
                datsath = next(get_sat['Hima'])
                # Check that the image is available
                if datsath is not None:
                    pmh = geosat.SatGrid(datsath, gg)
                    pmh._sat_togrid('CTTH_PRESS')
                    #print('pmh diag',len(datsath.var['CTTH_PRESS'][:].compressed()),
                    #                 len(pmh.var['CTTH_PRESS'][:].compressed()))
                    pmh._sat_togrid('CT')
                    pmh.attr = datsath.attr.copy()
                    satmap.fill('Hima', pmh, cloud_type)
                    del datsath
                    del pmh
                else:
                    # if the image is missing, extend the lease
                    try:
                        satmap.extend('Hima')
                    except:
                        # This handle the unlikely case where the first image is missing
                        continue
            """ Select the parcels located within the domain """
            # TODO TODO the values used here should be derived from parameters defined above
            indomain = np.all((datpart['x'] > -10, datpart['x'] < 160,
                               datpart['y'] > 0, datpart['y'] < 50),
                              axis=0)
            """ PROCESS THE COMPARISON OF PARCEL PRESSURES TO CLOUDS """
            if indomain.sum() > 0:
                nhits += convbirth(datpart['itime'],
                    datpart['x'][indomain],datpart['y'][indomain],datpart['p'][indomain],\
                    datpart['t'][indomain],datpart['idx_back'][indomain],\
                    prod0['flag_source'],prod0['src']['x'],prod0['src']['y'],\
                    prod0['src']['p'],prod0['src']['t'],prod0['src']['age'],\
                    satmap.ptop, part0['ir_start'],\
                    satmap.range[0,0],satmap.range[1,0],satmap.stepx,satmap.stepy,satmap.binx,satmap.biny)

            sys.stdout.flush()
        """ End of of loop on slices """

        # Check the age limit (easier to do it here)
        print("Manage age limit", flush=True)
        age_sec = part0['ir_start'][partante['idx_back'] -
                                    IDX_ORGN] - partante['itime']
        IIold_o = age_sec > (age_bound - 0.25) * 86400
        IIold_o = IIold_o & (
            (prod0['flag_source'][partante['idx_back'] - IDX_ORGN] & I_STOP)
            == 0)
        idx_IIold = partante['idx_back'][IIold_o]
        j_IIold_o = np.where(IIold_o)
        prod0['flag_source'][idx_IIold - IDX_ORGN] = prod0['flag_source'][
            idx_IIold - IDX_ORGN] | I_DEAD + I_OLD
        prod0['src']['x'][idx_IIold - IDX_ORGN] = partante['x'][j_IIold_o]
        prod0['src']['y'][idx_IIold - IDX_ORGN] = partante['y'][j_IIold_o]
        prod0['src']['p'][idx_IIold - IDX_ORGN] = partante['p'][j_IIold_o]
        prod0['src']['t'][idx_IIold - IDX_ORGN] = partante['t'][j_IIold_o]
        prod0['src']['age'][idx_IIold - IDX_ORGN] = (
            (part0['ir_start'][idx_IIold - IDX_ORGN] - partante['itime']) /
            86400)
        print("number of IIold ", len(idx_IIold))
        nold += len(idx_IIold)

        # find parcels still alive       if kept_p.sum()==0:
        try:
            nlive = ((prod0['flag_source'][partpost['idx_back'] - IDX_ORGN]
                      & I_DEAD) == 0).sum()
            n_nohit = ((prod0['flag_source'][partpost['idx_back'] - IDX_ORGN]
                        & I_HIT) == 0).sum()
        except:
            nlive = 0
            n_nohit = 0
        print('end hour ', hour, '  numact', partpost['nact'], ' nexits',
              nexits, ' nhits', nhits, ' nlive', nlive, ' nohit', n_nohit)
        # check that nlive + nhits + nexits = numpart, should be true after the first day
        if part0['numpart'] != nexits + nhits + nlive + ndborne:
            print('@@@ ACHTUNG numpart not equal to sum ', part0['numpart'],
                  nexits + nhits + nlive + ndborne)
    """ End of the procedure and storage of the result """
    pid = os.getpid()
    py = psutil.Process(pid)
    memoryUse = py.memory_info()[0] / 2**30
    print('memory use before clean: {:4.2f} gb'.format(memoryUse))
    del partante
    del partpost
    del live_a
    del live_p
    del datpart
    prod0['rvs'] = prod0['rvs'].astype(np.float32)
    for var in ['age', 'p', 't', 'x', 'y']:
        prod0['src'][var] = prod0['src'][var].astype(np.float32)
    pid = os.getpid()
    py = psutil.Process(pid)
    memoryUse = py.memory_info()[0] / 2**30
    print('memory use after clean: {:4.2f} gb'.format(memoryUse))
    #output file
    #pickle.dump(prod0,gzip.open(out_file,'wb'))
    #try:
    #    dd.io.save(out_file1,prod0,compression='blosc')
    #except:
    #    print('error with dd blosc')
    try:
        dd.io.save(out_file, prod0, compression='zlib')
    except:
        print('error with dd zlib')
    """ End of the procedure and storage of the result """
    #output file
    #dd.io.save(out_file2,prod0,compression='zlib')
    #pickle.dump(prod0,gzip.open(out_file,'wb'))
    # close the print file
    if quiet: fsock.close()
Example #2
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This is testing the SAFBox

Created on Fri Jun  8 13:33:15 2018

@author: Bernard Legras
"""

import geosat
from SAFNWCnc import SAFNWC_CTTH
from datetime import datetime

date = datetime(2017, 7, 22, 3, 45)
dat = SAFNWC_CTTH(date, 'msg1', BBname='SAFBox')
gg = geosat.GeoGrid('FullAMA_SAFBox')
dat._CTTH_PRESS()
p1 = geosat.SatGrid(dat, gg)
p1._sat_togrid('CTTH_PRESS')
p1.chart('CTTH_PRESS')
Example #3
0
# Himawari read
hima = geosat.Himawari(date)
# read IR0
hima._get_IR0()
hima._get_var('WV_062')
hima._get_var('WV_073')
hima.close()
# MSG1 read
msg1 = geosat.MSG1(date)
msg1._get_IR0()
msg1._get_var('WV_062')
msg1._get_var('WV_073')
msg1.close()
# grid projection and match
for grid in ['KTM', 'MesoInd', 'FullAMA']:
    gg = geosat.GeoGrid(grid)
    # associate grid and sat
    phima = geosat.SatGrid(hima, gg)
    pmsg1 = geosat.SatGrid(msg1, gg)
    # project by closest neigbour
    # and do angular correction
    for var in ['IR0', 'WV_062', 'WV_073']:
        phima._sat_togrid(var)
        pmsg1._sat_togrid(var)
    # angular correction for 'IR0'
    phima._sza_correc()
    pmsg1._sza_correc()

    # patching
    ppt = pmsg1.patch(phima, 90.75, ['IR0', 'WV_062', 'WV_073'])
    ppt.chart('IR0', txt='brightness temperature infrared 10.8')
Example #4
0
def main():
    global IDX_ORGN
    parser = argparse.ArgumentParser()
    parser.add_argument("-y", "--year", type=int, help="year")
    parser.add_argument("-m",
                        "--month",
                        type=int,
                        choices=1 + np.arange(12),
                        help="month")
    parser.add_argument("-d1",
                        "--day1",
                        type=int,
                        choices=1 + np.arange(31),
                        help="day1")
    parser.add_argument("-d2",
                        "--day2",
                        type=int,
                        choices=1 + np.arange(31),
                        help="day2")
    parser.add_argument(
        "-a",
        "--advect",
        type=str,
        choices=["OPZ", "EAD", "EAZ", "EID", "EIZ", "EID-FULL", "EIZ-FULL"],
        help="source of advecting winds")
    parser.add_argument("-s",
                        "--suffix",
                        type=str,
                        help="suffix for special cases")
    parser.add_argument("-q",
                        "--quiet",
                        type=str,
                        choices=["y", "n"],
                        help="quiet (y) or not (n)")
    #parser.add_argument("-c","--clean0",type=bool,help="clean part_000")
    parser.add_argument("-t",
                        "--step",
                        type=int,
                        help="step in hour between two part files")
    parser.add_argument("-ct",
                        "--cloud_type",
                        type=str,
                        choices=["meanhigh", "veryhigh", "silviahigh"],
                        help="cloud type filter")
    parser.add_argument("-k",
                        "--diffus",
                        type=str,
                        choices=['01', '1', '001'],
                        help='diffusivity parameter')
    parser.add_argument("-v",
                        "--vshift",
                        type=int,
                        choices=[0, 1, 2],
                        help='vertical shift')
    parser.add_argument("-hm",
                        "--hmax",
                        type=int,
                        help='maximum considered integration time')

    # to be updated
    # Define main directories
    if 'ciclad' in socket.gethostname():
        main_sat_dir = '/data/legras/flexpart_in/SAFNWC'
        #SVC_Dir = '/bdd/CFMIP/SEL2'
        traj_dir = '/data/akottayil/flexout/STC/BACK'
        out_dir = '/data/legras/STC'
    elif ('climserv' in socket.gethostname()) | ('polytechnique'
                                                 in socket.gethostname()):
        main_sat_dir = '/data/legras/flexpart_in/SAFNWC'
        #SVC_Dir = '/bdd/CFMIP/SEL2'
        traj_dir = '/data/akottayil/flexout/STC/BACK'
        out_dir = '/homedata/legras/STC'
    else:
        print('CANNOT RECOGNIZE HOST - DO NOT RUN ON NON DEFINED HOSTS')
        exit()
    """ Parameters """
    step = 3
    hmax = 732
    dstep = timedelta(hours=step)
    # time width of the parcel slice
    slice_width = timedelta(minutes=5)
    # number of slices between two outputs
    nb_slices = int(dstep / slice_width)
    # default values of parameters
    # date of the flight
    year = 2017
    month = 7 + 1
    day1 = 1
    day2 = 10
    advect = 'EAD'
    suffix = ''
    quiet = False
    clean0 = True
    cloud_type = 'silviahigh'
    diffus = '01'
    vshift = 0
    super = ''
    args = parser.parse_args()
    if args.year is not None: year = args.year
    if args.month is not None: month = args.month + 1
    if args.advect is not None: advect = args.advect
    if args.day1 is not None: day1 = args.day1
    if args.day2 is not None: day2 = args.day2
    if args.suffix is not None: suffix = '-' + args.suffix
    if args.hmax is not None: hmax = args.hmax
    if args.quiet is not None:
        if args.quiet == 'y': quiet = True
        else: quiet = False
    #if args.clean0 is not None: clean0 = args.clean0
    if args.cloud_type is not None: cloud_type = args.cloud_type
    if args.step is not None: step = args.step
    if args.diffus is not None: diffus = args.diffus
    diffus = '-D' + diffus
    if args.vshift is not None:
        vshift = args.vshift
        if vshift > 0:
            super = 'super' + str(vshift)

    # Update the out_dir with the cloud type and the super paramater
    out_dir = os.path.join(out_dir, 'SVC-BACK-OUT-SAF-' + super + cloud_type)
    try:
        os.mkdir(out_dir)
        os.mkdir(out_dir + '/out')
    except:
        print('out_dir directory already created')

    # Dates beginning and end
    date_beg = datetime(year=year, month=month, day=day1, hour=0)
    date_end = datetime(year=year, month=month, day=day2, hour=0)

    # Manage the file that receives the print output
    if quiet:
        # Output file
        print_file = os.path.join(
            out_dir, 'out',
            'BACK-SVC-EID-FULL-' + date_beg.strftime('%b-%Y-day%d-') +
            date_end.strftime('%d-D01') + '.out')
        fsock = open(print_file, 'w')
        sys.stdout = fsock

    # initial time to read the sat files
    # should be after the end of the flight
    sdate = date_end + timedelta(days=1)
    print('year', year, 'month', month, 'day', day2)
    print('advect', advect)
    print('suffix', suffix)

    # patch to fix the problem of the data hole on the evening of 2 August 2017
    if sdate == datetime(2017, 8, 2): sdate = datetime(2017, 8, 3, 6)

    # Directories of the backward trajectories and name of the output file
    ftraj = os.path.join(
        traj_dir, 'BACK-SVC-EID-FULL-' + date_beg.strftime('%b-%Y-day%d-') +
        date_end.strftime('%d-D01'))
    out_file2 = os.path.join(
        out_dir, 'BACK-SVC-EID-FULL-' + date_beg.strftime('%b-%Y-day%d-') +
        date_end.strftime('%d-D01') + '.hdf5')

    # Directories for the satellite cloud top files
    satdir ={'MSG1':os.path.join(main_sat_dir,'msg1','S_NWC'),\
             'Hima':os.path.join(main_sat_dir,'himawari','S_NWC')}
    """ Initialization of the calculation """
    # Initialize the grid
    gg = geosat.GeoGrid('FullAMA_SAFBox')
    # Initialize the dictionary of the parcel dictionaries
    partStep = {}
    satmap = pixmap(gg)

    # Build the satellite field generator
    get_sat = {'MSG1': read_sat(sdate,'MSG1',satmap.zone['MSG1']['dtRange'],satdir['MSG1'],pre=True,vshift=vshift),\
               'Hima': read_sat(sdate,'Hima',satmap.zone['Hima']['dtRange'],satdir['Hima'],pre=True,vshift=vshift)}

    # Read the index file that contains the initial positions
    part0 = readidx107(os.path.join(ftraj, 'part_000'), quiet=True)
    print('numpart', part0['numpart'])
    # stamp_date not set in these runs
    # current_date actually shifted by one day / sdate
    # We assume here that part time is defined from this day at 0h
    # sdate defined above should be equal or posterior to current_date
    current_date = sdate
    # check flag is clean
    print('check flag is clean ',((part0['flag']&I_HIT)!=0).sum(),((part0['flag']&I_DEAD)!=0).sum(),\
                                 ((part0['flag']&I_CROSSED)!=0).sum())
    # check idx_orgn
    if part0['idx_orgn'] != 0:
        print('MINCHIA, IDX_ORGN NOT 0 AS ASSUMED, CORRECTED WITH READ VALUE')
        print('VALUE ', part0['idx_orgn'])
        IDX_ORGN = part0['idx_orgn']

    # Build a dictionary to host the results
    prod0 = defaultdict(dict)
    prod0['src']['x'] = np.empty(part0['numpart'], dtype='float')
    prod0['src']['y'] = np.empty(part0['numpart'], dtype='float')
    prod0['src']['p'] = np.empty(part0['numpart'], dtype='float')
    prod0['src']['t'] = np.empty(part0['numpart'], dtype='float')
    prod0['src']['age'] = np.empty(part0['numpart'], dtype='int')
    prod0['flag_source'] = part0['flag']
    # truncate eventually to 32 bits at the output stage

    # read the part_000 file
    partStep[0] = readpart107(0, ftraj, quiet=True)
    # cleaning is necessary for runs starting in the fake restart mode
    # otherwise all parcels are thought to exit at the first step
    if clean0:
        partStep[0]['idx_back'] = []

    # number of hists and exits
    nhits = 0
    nexits = 0
    ndborne = 0
    nnew = 0

    # used to get non borne parcels
    new = np.empty(part0['numpart'], dtype='bool')
    new.fill(False)

    print('Initialization completed')
    """ Main loop on the output time steps """
    for hour in range(step, hmax + 1, step):
        pid = os.getpid()
        py = psutil.Process(pid)
        memoryUse = py.memory_info()[0] / 2**30
        print('memory use: {:4.2f} gb'.format(memoryUse))
        # Get rid of dictionary no longer used
        if hour >= 2 * step: del partStep[hour - 2 * step]
        # Read the new data
        partStep[hour] = readpart107(hour, ftraj, quiet=True)
        # Link the names
        partante = partStep[hour - step]
        partpost = partStep[hour]
        if partpost['nact'] > 0:
            print('hour ', hour, '  numact ', partpost['nact'], '  max p ',
                  partpost['p'].max())
        else:
            print('hour ', hour, '  numact ', partpost['nact'])
        # New date valid for partpost
        current_date -= dstep
        """ Select the parcels that are common to the two steps
        ketp_a is a logical field with same length as partante
        kept_p is a logical field with same length as partpost
        After the launch of the earliest parcel along the flight track, there
        should not be any member in new
        The parcels
        """
        kept_a = np.in1d(partante['idx_back'],
                         partpost['idx_back'],
                         assume_unique=True)
        kept_p = np.in1d(partpost['idx_back'],
                         partante['idx_back'],
                         assume_unique=True)
        #new_p = ~np.in1d(partpost['idx_back'],partpost['idx_back'],assume_unique=True)
        print('kept a, p ', len(kept_a), len(kept_p), kept_a.sum(),
              kept_p.sum(), '  new ',
              len(partpost['x']) - kept_p.sum())
        """ IDENTIFY AND TAKE CARE OF DEADBORNE AS NON BORNE PARCELS """
        if (hour < ((day2 - day1 + 5) * 24)) & (partpost['nact'] > 0):
            new[partpost['idx_back'][~kept_p] - IDX_ORGN] = True
            nnew += len(partpost['x']) - kept_p.sum()
        if hour == ((day2 - day1 + 5) * 24):
            ndborne = np.sum(~new)
            prod0['flag_source'][~new] |= I_DBORNE + I_DEAD
            prod0['src']['x'][~new] = part0['x'][~new]
            prod0['src']['y'][~new] = part0['y'][~new]
            prod0['src']['p'][~new] = part0['p'][~new]
            prod0['src']['t'][~new] = part0['t'][~new]
            prod0['src']['age'][~new] = 0
            print('number of dead borne', ndborne, part0['numpart'] - nnew)
            del new
        """ INSERT HERE CODE FOR NEW PARCELS """
        # nothing to be done for new parcels, just wait and see
        """ PROCESSING OF CROSSED PARCELS """
        if len(kept_a) > 0:
            exits = exiter(int((partante['itime']+partpost['itime'])/2), \
                partante['x'][~kept_a],partante['y'][~kept_a],partante['p'][~kept_a],\
                partante['t'][~kept_a],partante['idx_back'][~kept_a],\
                prod0['flag_source'],prod0['src']['x'],prod0['src']['y'],\
                prod0['src']['p'],prod0['src']['t'],prod0['src']['age'],\
                part0['ir_start'], satmap.range)
            nexits += exits
            print('exit ', nexits, exits, np.sum(~kept_a),
                  len(kept_a) - len(kept_p))
        """ PROCESSING OF PARCELS WHICH ARE COMMON TO THE TWO OUTPUTS  """
        # Select the kept parcels which have not been hit yet
        # !!! Never use and between two lists, the result is wrong

        if kept_p.sum() == 0:
            live_a = live_p = kept_p
        else:
            live_a = np.logical_and(
                kept_a, (prod0['flag_source'][partante['idx_back'] - IDX_ORGN]
                         & I_DEAD) == 0)
            live_p = np.logical_and(
                kept_p, (prod0['flag_source'][partpost['idx_back'] - IDX_ORGN]
                         & I_DEAD) == 0)
        print('live a, b ', live_a.sum(), live_p.sum())

        # Build generator for parcel locations of the 5' slices
        gsp = get_slice_part(partante, partpost, live_a, live_p, current_date,
                             dstep, slice_width)
        if verbose: print('built parcel generator for ', current_date)
        """  MAIN LOOP ON THE PARCEL TIME SLICES  """

        for i in range(nb_slices):
            # get the slice for the particles
            datpart = next(gsp)
            if verbose: print('part slice ', i, datpart['time'])
            # Check whether the present satellite image is valid
            # The while should ensure that the run synchronizes
            # when it starts.
            while satmap.check('MSG1', datpart['time']) is False:
                # if not get next satellite image
                datsat1 = next(get_sat['MSG1'])
                # Check that the image is available
                if datsat1 is not None:
                    pm1 = geosat.SatGrid(datsat1, gg)
                    pm1._sat_togrid('CTTH_PRESS')
                    #print('pm1 diag',len(datsat1.var['CTTH_PRESS'][:].compressed()),
                    #                 len(pm1.var['CTTH_PRESS'][:].compressed()))
                    pm1._sat_togrid('CT')
                    if vshift > 0: pm1._sat_togrid('CTTH_TEMPER')
                    pm1.attr = datsat1.attr.copy()
                    satmap.fill('MSG1', pm1, cloud_type, vshift=vshift)
                    del pm1
                    del datsat1
                else:
                    # if the image is missing, extend the lease
                    try:
                        satmap.extend('MSG1')
                    except:
                        # This handle the unlikely case where the first image is missing
                        continue
            while satmap.check('Hima', datpart['time']) is False:
                # if not get next satellite image
                datsath = next(get_sat['Hima'])
                # Check that the image is available
                if datsath is not None:
                    pmh = geosat.SatGrid(datsath, gg)
                    pmh._sat_togrid('CTTH_PRESS')
                    #print('pmh diag',len(datsath.var['CTTH_PRESS'][:].compressed()),
                    #                 len(pmh.var['CTTH_PRESS'][:].compressed()))
                    pmh._sat_togrid('CT')
                    if vshift > 0: pmh._sat_togrid('CTTH_TEMPER')
                    pmh.attr = datsath.attr.copy()
                    satmap.fill('Hima', pmh, cloud_type, vshift=vshift)
                    del datsath
                    del pmh
                else:
                    # if the image is missing, extend the lease
                    try:
                        satmap.extend('Hima')
                    except:
                        # This handle the unlikely case where the first image is missing
                        continue
            """ PROCESS THE COMPARISON OF PARCEL PRESSURES TO CLOUDS """
            if len(datpart['x']) > 0:
                nhits += convbirth(datpart['itime'],
                    datpart['x'],datpart['y'],datpart['p'],datpart['t'],datpart['idx_back'],\
                    prod0['flag_source'],prod0['src']['x'],prod0['src']['y'],\
                    prod0['src']['p'],prod0['src']['t'],prod0['src']['age'],\
                    satmap.ptop, part0['ir_start'],\
                    satmap.range[0,0],satmap.range[1,0],satmap.stepx,satmap.stepy,satmap.binx,satmap.biny)

            sys.stdout.flush()
        """ End of of loop on slices """
        # find parcels still alive       if kept_p.sum()==0:
        try:
            nlive = ((prod0['flag_source'][partpost['idx_back'] - IDX_ORGN]
                      & I_DEAD) == 0).sum()
            n_nohit = ((prod0['flag_source'][partpost['idx_back'] - IDX_ORGN]
                        & I_HIT) == 0).sum()
        except:
            nlive = 0
            n_nohit = 0
        print('end hour ', hour, '  numact', partpost['nact'], ' nexits',
              nexits, ' nhits', nhits, ' nlive', nlive, ' nohit', n_nohit)
        # check that nlive + nhits + nexits = numpart, should be true after the first day
        if part0['numpart'] != nexits + nhits + nlive + ndborne:
            print('@@@ ACHTUNG numpart not equal to sum ', part0['numpart'],
                  nexits + nhits + nlive + ndborne)
    """ End of the procedure and storage of the result """
    #output file
    dd.io.save(out_file2, prod0, compression='zlib')
    #pickle.dump(prod0,gzip.open(out_file,'wb'))
    # close the print file
    if quiet: fsock.close()
Example #5
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This script tests the behavior of geosat with a MSG1 image with missing lines

Created on Sat Jun 10 16:16:30 2017

@author: Bernard Legras
"""
import geosat
from datetime import datetime

date = datetime(2017, 6, 8, 7)

ah = geosat.MSG1(date)
gg = geosat.GeoGrid('MesoInd')

ah._get_IR0()
ph = geosat.SatGrid(ah, gg)
ph._sat_togrid('IR0')
ah.show('IR0')
ph.chart('IR0', txt='BT MSG1')
Example #6
0
def main():
    
    # to be updated
    if socket.gethostname() == 'graphium':
        pass
    elif 'ciclad' in socket.gethostname():
        #main_sat_dirSAF = '/data/legras/flexpart_in/SAFNWC'
        main_sat_dir1 = '/bdd/STRATOCLIM/flexpart_in'
        output_dir = '/data/legras/STC/pixmaps'
    elif ('climserv' in socket.gethostname()) | ('polytechnique' in socket.gethostname()):
        #main_sat_dirSAF = '/data/legras/flexpart_in/SAFNWC'
        main_sat_dir1 = '/bdd/STRATOCLIM/flexpart_in'
    else:
         print ('CANNOT RECOGNIZE HOST - DO NOT RUN ON NON DEFINED HOSTS')
         exit()
         
    parser = argparse.ArgumentParser()
    #parser.add_argument("-y","--year",type=int,help="year")
    parser.add_argument("-m1","--month1",type=int,choices=1+np.arange(12),help="month")
    parser.add_argument("-d1","--day1",type=int,choices=1+np.arange(31),help="day")
    parser.add_argument("-m2","--month2",type=int,choices=1+np.arange(12),help="month")
    parser.add_argument("-d2","--day2",type=int,choices=1+np.arange(31),help="day")
    #parser.add_argument("-N","--NewSAF",type=bool,help='NewSAF')
    #parser.add_argument("-H","--doHima",type=bool,help='doHima')

    """ Parameters """
    # Starting time
    # This date must fall on a cloudtop boundary, that it 0 or 12h
    month1 = 8
    day1 = 16
    #sdate = datetime(2017,month1,day1,0)
    #sdate = datetime(2017,7,21,0)
    # Ending time (backward)
    month2 = 7
    day2 = 13
    #edate = datetime(2017,7,13,0)
    # time between two comparisons
    dstep = timedelta (hours=2)
    # dtRange
    #dtRangeSAF = {'MSG1':timedelta(minutes=15),'Hima':timedelta(minutes=20)}
    #dtRange1   = {'MSG1':timedelta(minutes=30),'Hima':timedelta(minutes=20)}
    # SAF filters
    #good = True
    #opaq = True
    
    args = parser.parse_args()
    if args.month1 is not None: month1 = args.month1
    if args.month2 is not None: month2 = args.month2
    if args.day1 is not None: day1 = args.day1
    if args.day2 is not None: day2 = args.day2
    #if args.NewSAF is not None: NewSAF = args.NewSAF
    #if args.doHima is not None: doHima = args.doHima
    
    sdate = datetime(2017,month1,day1,0)
    edate = datetime(2017,month2,day2,0)
    
    # Directories for the satellite cloud top files
    #satdirSAF ={'MSG1':os.path.join(main_sat_dirSAF,'msg1','S_NWC'),\
    #            'Hima':os.path.join(main_sat_dirSAF,'himawari','S_NWC')}
    satdir1 = {'MSG1':os.path.join(main_sat_dir1,'StratoClim+1kmD_msg1-c'),\
               'Hima':os.path.join(main_sat_dir1,'StratoClim+1kmD_himawari-d')}

    """ Initialization of the calculation """
    # Initialize the grid
    if NewSAF:
        gg = geosat.GeoGrid('FullAMA_SAFBox')
    else:
        gg = geosat.GeoGrid('FullAMA')
        output_dir += '-StdSAF'
    satmapSAF = pixmap(gg,'SAF')
    satmap1 = pixmap(gg,'1')
    satfill = {}

    # Build the satellite field generator
    get_sat1 = {'MSG1': read_sat1(sdate,satmap1.zone['MSG1']['dtRange1'],satdir1['MSG1'],pre=True),\
                'Hima': read_sat1(sdate,satmap1.zone['Hima']['dtRange1'],satdir1['Hima'],pre=True)}
    #get_satSAF = {'MSG1': read_satSAF(sdate,'MSG1',satmapSAF.zone['MSG1']['dtRangeSAF'],satdirSAF['MSG1'],pre=True),\
    #              'Hima': read_satSAF(sdate,'Hima',satmapSAF.zone['Hima']['dtRangeSAF'],satdirSAF['Hima'],pre=True)}
    get_satSAF = {'MSG1': read_satSAF(sdate,'MSG1',satmapSAF.zone['MSG1']['dtRangeSAF'],pre=True),\
                  'Hima': read_satSAF(sdate,'Hima',satmapSAF.zone['Hima']['dtRangeSAF'],pre=True)}
    current_date = sdate

    """ Main loop on the output time steps """
    while current_date > edate:
        print('searching ',current_date) 
        
        # Fill the pixmap for cloudtops
        
        while satmap1.check('MSG1',current_date) is False:
            # if not get next satellite slice
            try:
                next(satfill['MSG1'])
            # read new satellite file if the slice generator is over
            except:
                datsatm = next(get_sat1['MSG1'])
                satfill['MSG1'] = satmap1.fill1('MSG1',datsatm)
                next(satfill['MSG1'])               
        if verbose: print('check 1 MSG1 ',satmap1.check('MSG1',current_date),'##',current_date,
                      '##',satmap1.zone['MSG1']['ti'],'##',satmap1.zone['MSG1']['tf'])
        if doHima:              
            while satmap1.check('Hima',current_date) is False:
                try:
                    next(satfill['Hima'])
                except:
                    datsath = next(get_sat1['Hima'])
                    satfill['Hima'] = satmap1.fill1('Hima',datsath)
                    next(satfill['Hima'])
            if verbose: print('check 1 Hima ',satmap1.check('Hima',current_date),'##',current_date,
                          '##',satmap1.zone['Hima']['ti'],'##',satmap1.zone['Hima']['tf'])

        # Fill the pixmap for SAF
        # Check whether the present satellite image is valid
        # The while should ensure that the run synchronizes when it starts.
            
        while satmapSAF.check('MSG1',current_date) is False:
            # if not get next satellite image 
            datsatm = next(get_satSAF['MSG1'])
            # Check that the image is available
            if datsatm is not None:
                # all the data need to be read because of possible gaps 
                # and extensions to be done in such cases
                pmm = geosat.SatGrid(datsatm,gg)
                pmm._sat_togrid('CTTH_PRESS')
                #print('pm1 diag',len(datsat1.var['CTTH_PRESS'][:].compressed()),
                #                 len(pm1.var['CTTH_PRESS'][:].compressed()))
                pmm._sat_togrid('ctth_alti')
                pmm._sat_togrid('ctth_tempe')
                pmm._sat_togrid('ctth_quality')
                pmm._sat_togrid('ctth_conditions')
                pmm._sat_togrid('ctth_status_flag')
                pmm._sat_togrid('ctth_method')
                pmm._sat_togrid('CT')
                pmm._sat_togrid('ct_cumuliform')
                pmm._sat_togrid('ct_multilayer')
                pmm._sat_togrid('ct_status_flag')
                pmm._sat_togrid('CMa')
                pmm._sat_togrid('cma_status_flag')
                pmm._sat_togrid('cma_quality')
                pmm.attr = datsatm.attr.copy()
                satmapSAF.fillSAF('MSG1',pmm)
                del pmm
                #del datsat1
            else:
                # if the image is missing, extend the lease of previous image
                try:
                    satmapSAF.extend('MSG1')
                    if debug2: print ('MSG1 extension ',satmapSAF.zone['MSG1']['ti'])
                except:
                    # This handle the unlikely case where the first image is missing
                    continue
        #print('match MSG1 ',datsatm.attr['date'],datsatm.attr['lease_time'])
        if verbose: print('check SAF MSG1 ',satmapSAF.check('MSG1',current_date),'##',current_date,
                      '##',satmapSAF.zone['MSG1']['ti'],'##',satmapSAF.zone['MSG1']['tf'])
                     
        if doHima:                
            while satmapSAF.check('Hima',current_date) is False:
                # if not get next satellite image 
                datsath = next(get_satSAF['Hima'])
                # Check that the image is available
                if datsath is not None:
                    # not elegant as it duplicates the while test but saves 
                    # some processing
                    #if (current_date <= datsath.attr['lease_time']) | \
                    #   (current_date > datsath.attr['date']): continue
                    # not a good odea when some image is missing
                    pmh = geosat.SatGrid(datsath,gg)
                    pmh._sat_togrid('CTTH_PRESS')
                    #print('pmh diag',len(datsath.var['CTTH_PRESS'][:].compressed()),
                    #                 len(pmh.var['CTTH_PRESS'][:].compressed()))
                    pmh._sat_togrid('ctth_tempe')
                    pmh._sat_togrid('ctth_alti')
                    pmh._sat_togrid('ctth_quality')
                    pmh._sat_togrid('ctth_conditions')
                    pmh._sat_togrid('ctth_status_flag')
                    pmh._sat_togrid('ctth_method')
                    pmh._sat_togrid('CT')
                    pmh._sat_togrid('ct_cumuliform')
                    pmh._sat_togrid('ct_multilayer')
                    pmh._sat_togrid('ct_status_flag')
                    pmh._sat_togrid('CMa')
                    pmh._sat_togrid('cma_status_flag')
                    pmh._sat_togrid('cma_quality')
                    pmh.attr = datsath.attr
                    satmapSAF.fillSAF('Hima',pmh)
                    #del datsath
                    del pmh
                else:
                    # if the image is missing, extend the leaseof previous image
                    try:
                        satmapSAF.extend('Hima')
                        if debug2: print ('Hima extension ',satmapSAF.zone['Hima']['ti'])
                    except:
                        # This handle the unlikely case where the first image is missing
                        continue
            #print('match Hima ',datsath.attr['date'],datsath.attr['lease_time'])      
            if verbose: print('check SAF Hima ',satmapSAF.check('Hima',current_date),'##',current_date,
                          '##',satmapSAF.zone['Hima']['ti'],'##',satmapSAF.zone['Hima']['tf'])
        
        outfile = os.path.join(output_dir,current_date.strftime('%Y-%m-%dT%H%M'))
        with gzip.open(outfile,'wb') as f:
           pickle.dump([satmapSAF,satmap1],f)
        print('OUTPUT for time ',current_date,'\n')
        current_date -= dstep
        sys.stdout.flush() 
Example #7
0
def main():

    parser = argparse.ArgumentParser()
    parser.add_argument("-s",
                        "--segment",
                        type=str,
                        choices=[
                            "May.11", "May.21", "Jun.01", "Jun.11", "Jun.21",
                            "Jul.01", "Jul.11", "Jul.21", "Aug.01", "Aug.11",
                            "Aug.21", "Sep.01", "Sep.11", "Sep.21", "OctBeg"
                        ],
                        help="segment to be processed")
    seg_dates = {
        'Jul.01': [datetime(2017, 7, 1, 0),
                   datetime(2017, 7, 11, 0)],
        'Jul.11': [datetime(2017, 7, 11, 0),
                   datetime(2017, 7, 21, 0)],
        'Jul.21': [datetime(2017, 7, 21, 0),
                   datetime(2017, 8, 1, 0)],
        'Aug.01': [datetime(2017, 8, 1, 0),
                   datetime(2017, 8, 11, 0)],
        'Aug.11': [datetime(2017, 8, 11, 0),
                   datetime(2017, 8, 21, 0)],
        'Aug.21': [datetime(2017, 8, 21, 0),
                   datetime(2017, 9, 1, 0)],
        'Jun.01': [datetime(2017, 6, 1, 0),
                   datetime(2017, 6, 11, 0)],
        'Jun.11': [datetime(2017, 6, 11, 0),
                   datetime(2017, 6, 21, 0)],
        'Jun.21': [datetime(2017, 6, 21, 0),
                   datetime(2017, 7, 1, 0)],
        'Sep.01': [datetime(2017, 9, 1, 0),
                   datetime(2017, 9, 11, 0)],
        'Sep.11': [datetime(2017, 9, 11, 0),
                   datetime(2017, 9, 21, 0)],
        'Sep.21': [datetime(2017, 9, 21, 0),
                   datetime(2017, 10, 1, 0)],
        'May.21': [datetime(2017, 5, 21, 0),
                   datetime(2017, 6, 1, 0)],
        'May.11': [datetime(2017, 5, 11, 0),
                   datetime(2017, 5, 21, 0)],
        'OctBeg': [datetime(2017, 10, 1, 0),
                   datetime(2017, 10, 3, 0)]
    }

    seg = 'Jul.11'

    args = parser.parse_args()
    if args.segment is not None:
        seg = args.segment

    date1 = seg_dates[seg][0]
    date2 = seg_dates[seg][1]

    gg = geosat.GeoGrid('FullAMA_SAFBox')

    date = date1

    output_dir = '/data/legras/STC/STC-SAFNWC-OUT'

    gM = get_msg1(date1, date2, gg)
    gH = get_himawari(date1, date2, gg)

    # date1 should correspond to a date where both images are available
    # in order to start properly
    phM = next(gM)
    phH = next(gH)
    make_new_comp = True

    while date < date2:

        # Check new msg1 to be loaded
        if phM.expiration == date:
            pp = next(gM)
            # If available image, get it
            # if not,  extend validity of previous image
            if pp is not None:
                phM = pp
                make_new_comp = True
            else:
                phM.expiration += timedelta(minutes=delta_msg1)
        if phH.expiration == date:
            pp = next(gH)
            # If available image, get it
            # if not,  extend validity of previous image
            if pp is not None:
                phH = pp
                make_new_comp = True
            else:
                phH.expiration += timedelta(minutes=delta_himawari)

        if make_new_comp:
            comb = phM.patch(phH, 90.75, [
                'CTTH_PRESS', 'CT', 'ctth_status_flag', 'ctth_quality',
                'ct_multilayer'
            ])
            comb.var['CTTH_PRESS'][comb.var['CTTH_PRESS'] < 0] = np.ma.masked
            comb.var['CTTH_PRESS'][
                comb.var['CTTH_PRESS'] > 65000] = np.ma.masked
            # compact the CT field and the flags into a single 32 bit variable
            comb.var['cloud_flag'] = (comb.var['CT'].astype(np.uint32) << 24) \
                + (comb.var['ctth_quality'].astype(np.uint32) << 16) \
                + (comb.var['ct_multilayer'].astype(np.uint32) << 8) \
                +  comb.var['ctth_status_flag'].astype(np.uint32)
            comb.var['cloud_flag'].__setmask__(comb.var['CTTH_PRESS'].mask)
            filename = date.strftime('SAFNWC-PTOP-%Y-%m-%d-%H:%M.pkl')
            day_dir = os.path.join(output_dir, date.strftime('%Y/%m/%Y-%m-%d'))
            try:
                os.mkdir(day_dir)
            except:
                pass
            # output containing the cloud top pressure and the good/opaq flag
            fullname = os.path.join(day_dir, filename)
            with gzip.open(fullname, 'wb') as f:
                pickle.dump([comb.var['CTTH_PRESS'], comb.var['cloud_flag']],
                            f,
                            protocol=3)
            print('new file', date, np.ma.count_masked(comb.var['CTTH_PRESS']))
            del comb

        date += timedelta(minutes=delta_time)
        make_new_comp = False
Example #8
0
            qual_data = v2018_data.ncid.variables['ctth_quality'][:].data
            #             for i in range(len(flag_values)):
            if fname == 'All':
                fmask = np.zeros(flag_data.shape).astype(bool)
            else:
                fi = np.where(np.asarray(flag_meaning) == fname)[0][0]
                fval = flag_values[fi]
                fmask = ~(flag_data == fval)
#             qmaks = (qual_data == qual_values[2+3]) | (qual_data == qual_values[2+2])  | (qual_data == qual_values[2+4])
#             mask = qmaks | fmask
            mask = fmask
            v2018_data._CTTH_PRESS()
            v2018_data.var['CTTH_PRESS'].data[mask] = v2018_maskprod.fill_value

            #: Change to new grid
            v2018_gg = geosat.GeoGrid('FullAMA_SAFBox')
            v2018_p1 = geosat.SatGrid(v2018_data, v2018_gg)
            v2018_p1._sat_togrid(grid_type)
            #: Decide which one to use
            if fm:
                #: hPa
                use_data = np.where(v2018_prod != v2018_maskprod.fill_value,
                                    v2018_prod / 100, v2018_prod)
            else:
                use_data = v2018_p1.var[grid_type].data

            #: Create mask width valid data

            v2018_valid_mask = createClimMask(use_data, clim[0], clim[1],
                                              v2018_maskprod.fill_value)
            #: Add to results
Example #9
0
Created on Thu Apr 13 17:52:48 2017

This script tests and demonstrates the main features of geosat.py.

@author: Bernard Legras
"""
import geosat
#import pickle,gzip
#import numpy as np
from datetime import datetime
#import matplotlib.pyplot as plt
#%%
date = datetime(year=2017, month=3, day=15, hour=19)
# Himawari read and plot
ah = geosat.Himawari(date)
gg = geosat.GeoGrid('FullAMA')
ah._get_IR0()
ph = geosat.SatGrid(ah, gg)
ph._sat_togrid('IR0')
ah.show('IR0')
ph.chart('IR0', txt='BT himawari')
# MSG1 read and plot
a1 = geosat.MSG1(date)
a1._get_IR0()
p1 = geosat.SatGrid(a1, gg)
p1._sat_togrid('IR0')
a1.show('IR0')
p1.chart('IR0', txt='BT msg1')
# MSG3 read and plot
a3 = geosat.MSG3(date)
a3._get_IR0()
def main():
    global IDX_ORGN
    parser = argparse.ArgumentParser()
    parser.add_argument("-y", "--year", type=int, help="year")
    parser.add_argument("-m1",
                        "--month1",
                        type=int,
                        choices=1 + np.arange(12),
                        help="month1")
    parser.add_argument("-m2",
                        "--month2",
                        type=int,
                        choices=1 + np.arange(12),
                        help="month2")
    parser.add_argument("-d1",
                        "--day1",
                        type=int,
                        choices=1 + np.arange(31),
                        help="day1")
    parser.add_argument("-d2",
                        "--day2",
                        type=int,
                        choices=1 + np.arange(31),
                        help="day2")
    parser.add_argument("-a",
                        "--advect",
                        type=str,
                        choices=["OPZ", "EAD", "EAZ", "EID", "EIZ"],
                        help="source of advecting winds")
    parser.add_argument("-s",
                        "--suffix",
                        type=str,
                        help="suffix for special cases")
    parser.add_argument("-q",
                        "--quiet",
                        type=str,
                        choices=["y", "n"],
                        help="quiet (y) or not (n)")
    parser.add_argument("-l", "--level", type=int, help="PT level")
    #parser.add_argument("-c","--clean0",type=bool,help="clean part_000")
    parser.add_argument("-t",
                        "--step",
                        type=int,
                        help="step in hour between two part files")
    #parser.add_argument("-ct","--cloud_type",type=str,choices=["meanhigh","veryhigh","silviahigh"],help="cloud type filter")
    #parser.add_argument("-k","--diffus",type=str,choices=['01','1','001'],help='diffusivity parameter')
    parser.add_argument("-v",
                        "--vshift",
                        type=int,
                        choices=[0, 10],
                        help='vertical shift')
    parser.add_argument("-hm",
                        "--hmax",
                        type=int,
                        help='maximum considered integration time (hour)')
    parser.add_argument("-b",
                        "--bak",
                        type=str,
                        choices=["y", "n"],
                        help="backup (y) or not (n)")
    parser.add_argument("-c",
                        "--cont",
                        type=str,
                        choices=["y", "n"],
                        help="continuation (y) or not (n)")
    parser.add_argument("-bs",
                        "--bakstep",
                        type=int,
                        help='backup step (hour)')

    # to be updated
    # Define main directories
    if 'ciclad' in socket.gethostname():
        #main_sat_dir = '/data/legras/flexpart_in/SAFNWC'
        #SVC_Dir = '/bdd/CFMIP/SEL2'
        traj_dir = '/data/legras/flexout/STC/Sivan'
        out_dir = '/data/legras/STC'
        #out_dir = '/data/legras/STC'
    elif ('climserv' in socket.gethostname()) | ('polytechnique'
                                                 in socket.gethostname()):
        traj_dir = '/data/legras/flexout/STC/Sivan'
        out_dir = '/homedata/legras/STC'
    else:
        print('CANNOT RECOGNIZE HOST - DO NOT RUN ON NON DEFINED HOSTS')
        exit()
    """ Parameters """
    # Output step of the trajectories in hour
    step = 6
    hmax = 3360
    #hmax = 18
    dstep = timedelta(hours=step)
    # time width of the parcel slice
    # might be better passed as a parameter
    age_bound = 44.5
    # time width of the parcel slice
    slice_width = timedelta(minutes=5)
    # number of slices between two outputs
    nb_slices = int(dstep / slice_width)
    # Number of parcels launched per time slot (1 per degree on a 170x50 grid)
    granule_size = 8500
    # number of granules in step hours
    granule_step = 6
    # size of granules launched during step hours
    granule_quanta = granule_size * granule_step
    # default values of parameters
    # date of the flight
    year = 2017
    month1 = 7
    month2 = 9
    day1 = 1
    day2 = 30
    advect = 'EAD'
    suffix = ''
    quiet = False
    clean0 = True
    backup = False
    backup_step = 40 * step
    restart = False
    #cloud_type = 'silviahigh'
    #diffus = '01'
    vshift = 0
    level = 380
    super = ''
    # Step of GridSat
    dtRange = timedelta(hours=3)
    args = parser.parse_args()
    if args.year is not None: year = args.year
    if args.month1 is not None: month1 = args.month1
    if args.month2 is not None: month2 = args.month2
    if args.advect is not None: advect = args.advect
    if args.day1 is not None: day1 = args.day1
    if args.day2 is not None: day2 = args.day2
    if args.level is not None: level = args.level
    if args.hmax is not None: hmax = args.hmax
    if args.suffix is not None: suffix = '-' + args.suffix
    if args.quiet is not None:
        if args.quiet == 'y': quiet = True
        else: quiet = False
    #if args.clean0 is not None: clean0 = args.clean0
    #if args.cloud_type is not None: cloud_type = args.cloud_type
    if args.step is not None: step = args.step
    #if args.diffus is not None: diffus = args.diffus
    #diffus = '-D' + diffus
    if args.vshift is not None:
        vshift = args.vshift
        if vshift > 0:
            super = '-super' + str(vshift)
    if args.bak is not None:
        if args.bak == 'y': backup = True
        else: backup = False
    if args.bakstep is not None: backup_step = args.bakstep
    if args.cont is not None:
        if args.cont == 'y': restart = True
        else: restart = False

    # Update the out_dir with the cloud type and the super paramater
    out_dir = os.path.join(out_dir, 'STC-Sivan-OUT-GridSat-WMO' + super)
    try:
        os.mkdir(out_dir)
        os.mkdir(out_dir + '/out')
    except:
        print('out_dir directory already created')

    # Dates beginning and end
    date_beg = datetime(year=year, month=month1, day=day1, hour=0)
    date_end = datetime(year=year, month=month2, day=day2, hour=0)

    # Manage the file that receives the print output
    if quiet:
        # Output file
        #print_file = os.path.join(out_dir,'out','BACK-SVC-EAD-'+date_beg.strftime('%b-%Y-day%d-')+date_end.strftime('%d-D01')+'.out')
        print_file = os.path.join(
            out_dir, 'out', 'Sivan-T2-' + advect + '-JAS-' +
            date_beg.strftime('%Y-') + str(level) + 'K.out')
        fsock = open(print_file, 'w')
        sys.stdout = fsock

    # initial time to read the sat files
    # should be after the latest launch date
    sdate = date_end + timedelta(days=1)
    print('year', year, 'month1', month1, 'day1', day1, 'month2', month2,
          'day2', day2)
    print('advect', advect)
    print('suffix', suffix)

    # patch to fix the problem of the data hole on the evening of 2 August 2017
    # should not happen
    #if sdate == datetime(2017,8,2): sdate = datetime(2017,8,3,6)

    # Directory of the backward trajectories (input) and name of the output file
    ftraj = os.path.join(
        traj_dir, 'Sivan-' + advect + '-JAS-' + date_beg.strftime('%Y-') +
        str(level) + 'K')
    out_file2 = os.path.join(
        out_dir, 'Sivan-T2-' + advect + '-JAS-' + date_beg.strftime('%Y-') +
        str(level) + 'K.hdf5')
    # backup file
    if backup:
        bak_file_prod0 = os.path.join(
            out_dir, 'Sivan-T2-' + advect + '-JAS-' +
            date_beg.strftime('%Y-') + str(level) + 'K-backup-prod0.hdf5')
        bak_file_params = os.path.join(
            out_dir, 'Sivan-T2-' + advect + '-JAS-' +
            date_beg.strftime('%Y-') + str(level) + 'K-backup-params.hdf5')
    """ Initialization of the calculation """
    # Initialize the dictionary of the parcel dictionaries
    partStep = {}
    # initialize a grid that will be used to before actually doing any read
    gg = geosat.GeoGrid('GridSat')

    # Build the satellite field generator
    get_sat = read_sat(sdate, dtRange, pre=True, vshift=vshift)
    # Build the ECMWF field generator (both available at 3 hour interval)
    get_ERA5 = read_ERA5(sdate, dtRange, pre=True)
    # Read the index file that contains the initial positions
    part0 = readidx107(os.path.join(ftraj, 'part_000'), quiet=False)
    print('numpart', part0['numpart'])
    numpart = part0['numpart']
    numpart_s = granule_size  # because of parcels launched at time 0
    # stamp_date not set in these runs
    # current_date actually shifted by one day / sdate
    # We assume here that part time is defined from this day at 0h
    # sdate defined above should be equal or posterior to current_date
    current_date = sdate
    # check flag is clean
    print('check flag is clean ',((part0['flag']&I_HIT)!=0).sum(),((part0['flag']&I_DEAD)!=0).sum(),\
                                 ((part0['flag']&I_CROSSED)!=0).sum())
    # check idx_orgn
    if part0['idx_orgn'] != 0:
        print(
            'MINCHIA, IDX_ORGN NOT 0 ASSTC-M55-OUT-SAF-super1silviahigh ASSUMED, CORRECTED WITH READ VALUE'
        )
        print('VALUE ', part0['idx_orgn'])
        IDX_ORGN = part0['idx_orgn']
    idx1 = IDX_ORGN

    # Build a dictionary to host the results
    prod0 = defaultdict(dict)
    prod0['src']['x'] = np.empty(part0['numpart'], dtype='float')
    prod0['src']['y'] = np.empty(part0['numpart'], dtype='float')
    prod0['src']['p'] = np.empty(part0['numpart'], dtype='float')
    prod0['src']['t'] = np.empty(part0['numpart'], dtype='float')
    prod0['src']['age'] = np.empty(part0['numpart'], dtype='int')
    prod0['flag_source'] = part0['flag']
    # Set rvs at arbitrary large value
    prod0['rvs'] = np.full(part0['numpart'], 0.01, dtype='float')
    # truncate eventually to 32 bits at the output stage

    # read the part_000 file
    if not restart:
        partStep[0] = readpart107(0, ftraj, quiet=False)
        # cleaning is necessary for runs starting in the fake restart mode
        # otherwise all parcels are thought to exit at the first step
        if clean0:
            partStep[0]['idx_back'] = []
        # parcels with longitude east of zero degree are set to negative values
        partStep[0]['x'][partStep[0]['x'] > 180] -= 360

    # number of hists and exits
    nhits = 0
    nexits = 0
    ndborne = 0
    nnew = granule_size  # because of parcels launched at time 0
    nold = 0
    offset = 0

    # initialize datsat to None to force first read
    datsat = None

    # used to get non borne parcels (presently unused)
    #new = np.empty(part0['numpart'],dtype='bool')
    #new.fill(False)

    print('Initialization completed')

    if restart:
        print('restart run')
        try:
            params = fl.load(bak_file_params)
            prod0 = fl.load(bak_file_prod0)
        except:
            print('cannot load backup')
            return -1
        [
            offset, nhits, nexits, nold, ndborne, nnew, idx1, numpart_s,
            current_date
        ] = params['params']
        partStep[offset] = readpart107(offset, ftraj, quiet=True)
        partStep[offset]['x'][partStep[offset]['x'] > 180] -= 360
        # Initialize sat and ERA5 yield one step ahead as a precaution
        get_sat = read_sat(current_date + dstep,
                           dtRange,
                           pre=True,
                           vshift=vshift)
        get_ERA5 = read_ERA5(current_date + dstep, dtRange, pre=True)
    """ Main loop on the output time steps """
    for hour in range(step + offset, hmax + 1, step):
        pid = os.getpid()
        py = psutil.Process(pid)
        memoryUse = py.memory_info()[0] / 2**30
        print('memory use: {:4.2f} gb'.format(memoryUse))
        # Get rid of dictionary no longer used
        if hour >= 2 * step:
            try:
                del partStep[hour - 2 * step]
            except:
                print('nothing to delete')

        # Read the new data
        partStep[hour] = readpart107(hour, ftraj, quiet=True)
        # Link the names as views
        partante = partStep[hour - step]
        partpost = partStep[hour]
        # parcels with longitude east of zero degree are set to negative values
        # done with try to prevent errors when the file is empty
        try:
            partpost['x'][partpost['x'] > 180] -= 360
            #print("partpost x ",partpost['x'].min(),partpost['x'].max())
        except:
            pass

        if partpost['nact'] > 0:
            print('hour ', hour, '  numact ', partpost['nact'], '  max p ',
                  partpost['p'].max())
        else:
            print('hour ', hour, '  numact ', partpost['nact'])
        # New date valid for partpost
        current_date -= dstep

        # Processing of water mixing ratio
        # Select non stopped parcels in partante
        if len(partante['idx_back']) > 0:
            selec = (prod0['flag_source'][partante['idx_back'] - IDX_ORGN]
                     & I_STOP) == 0
            idx = partante['idx_back'][selec]
            prod0['rvs'][idx-IDX_ORGN] = np.minimum(prod0['rvs'][idx-IDX_ORGN],\
                satratio(partante['p'][selec],partante['t'][selec]))
        """ Select the parcels that are common to the two steps
        ketp_a is a logical field with same length as partante
        kept_p is a logical field with same length as partpost
        After the launch of the earliest parcel along the flight track, there
        should not be any member in new
        The parcels
        """
        kept_a = np.in1d(partante['idx_back'],
                         partpost['idx_back'],
                         assume_unique=True)
        kept_p = np.in1d(partpost['idx_back'],
                         partante['idx_back'],
                         assume_unique=True)
        #new_p = ~np.in1d(partpost['idx_back'],partpost['idx_back'],assume_unique=True)
        print('kept a, p ', len(kept_a), len(kept_p), kept_a.sum(),
              kept_p.sum(), '  new ',
              len(partpost['x']) - kept_p.sum())
        nnew += len(partpost['x']) - kept_p.sum()
        """ PROCESSING OF DEADBORNE PARCELS
        Manage the parcels launched during the last 6-hour which have already
        exited and do not appear in posold or posact (borne dead parcels).
        These parcels are stored in the last part of posact, at most
        the last granule_quanta parcels. """
        if numpart_s < numpart:
            # First index of the current quanta """
            numpart_s += granule_quanta
            print("manage deadborne idx1", idx1, " numpart_s", numpart_s)
            # Extract the last granule_size indexes from posacti, this is where the new parcels should be
            if hour == step:
                idx_act = partpost['idx_back']
            else:
                idx_act = partpost['idx_back'][-granule_quanta:]
            # Generate the list of indexes that should be found in this range
            # This should works for both values of IDX_orgn
            idx_theor = np.arange(idx1, numpart_s + IDX_ORGN)
            # Find the missing indexes in idx_act (make a single line after validation)
            kept_borne = np.in1d(idx_theor, idx_act, assume_unique=True)
            idx_deadborne = idx_theor[~kept_borne]
            # Process these parcels by assigning exit at initial location
            prod0['flag_source'][
                idx_deadborne -
                IDX_ORGN] = prod0['flag_source'][idx_deadborne -
                                                 IDX_ORGN] | I_DEAD + I_DBORNE
            prod0['src']['x'][idx_deadborne -
                              IDX_ORGN] = part0['x'][idx_deadborne - IDX_ORGN]
            prod0['src']['y'][idx_deadborne -
                              IDX_ORGN] = part0['y'][idx_deadborne - IDX_ORGN]
            prod0['src']['p'][idx_deadborne -
                              IDX_ORGN] = part0['p'][idx_deadborne - IDX_ORGN]
            prod0['src']['t'][idx_deadborne -
                              IDX_ORGN] = part0['t'][idx_deadborne - IDX_ORGN]
            prod0['src']['age'][idx_deadborne - IDX_ORGN] = 0.
            print("number of deadborne ", len(idx_deadborne))
            ndborne += len(idx_deadborne)
            idx1 = numpart_s + IDX_ORGN
        """ PROCESSING OF CROSSED PARCELS """
        if len(kept_a) > 0:
            exits = exiter(int((partante['itime']+partpost['itime'])/2), \
                partante['x'][~kept_a],partante['y'][~kept_a],partante['p'][~kept_a],\
                partante['t'][~kept_a],partante['idx_back'][~kept_a],\
                prod0['flag_source'],prod0['src']['x'],prod0['src']['y'],\
                prod0['src']['p'],prod0['src']['t'],prod0['src']['age'],\
                part0['ir_start'], gg.box_range)
            nexits += exits
            print('exit ', nexits, exits, np.sum(~kept_a),
                  len(kept_a) - len(kept_p))
        """ PROCESSING OF PARCELS WHICH ARE COMMON TO THE TWO OUTPUTS  """
        # Select the kept parcels which have not been hit yet
        # !!! Never use and between two lists, the result is wrong

        if kept_p.sum() == 0:
            live_a = live_p = kept_p
        else:
            live_a = np.logical_and(
                kept_a, (prod0['flag_source'][partante['idx_back'] - IDX_ORGN]
                         & I_DEAD) == 0)
            live_p = np.logical_and(
                kept_p, (prod0['flag_source'][partpost['idx_back'] - IDX_ORGN]
                         & I_DEAD) == 0)
        print('live a, b ', live_a.sum(), live_p.sum())
        """ Correction step that moves partante['x'] to avoid big jumps at the periodicity frontier on the x-axis
        To be activated in the FULL version"""
        # if kept_p.sum()>0:
        #     diffx = partpost['x'][live_p] - partante['x'][live_a]
        #     bb = np.zeros(len(diffx))
        #     bb[diffx>180] = 360
        #     bb[diffx<-180] = -360
        #     partante['x'][live_a] += bb
        #     del bb
        #     del diffx
        # del kept_p
        # del kept_a
        # DOES not work in the following WAY
        #partante['x'][live_a][diffx>180] += 360
        #partante['x'][live_a][diffx<-180] -= 360

        # Build generator for parcel locations of the 5' slices
        gsp = get_slice_part(partante, partpost, live_a, live_p, current_date,
                             dstep, slice_width)
        if verbose: print('built parcel generator for ', current_date)
        """  MAIN LOOP ON THE PARCEL TIME SLICES  """

        for i in range(nb_slices):
            # get the slice for the particles
            datpart = next(gsp)
            # Check x within (-180,180), necessary when GridSat is used
            #if datpart['x'] != []:
            if len(datpart['x']) > 0:
                datpart['x'] = (datpart['x'] + 180) % 360 - 180
            if verbose: print('part slice ', i, datpart['time'])
            # Check whether the present satellite image is valid
            # The while should ensure that the run synchronizes
            # when it starts.
            while check(datsat, datpart['time']) is False:
                # if not get next satellite image
                datsat = next(get_sat)
                datera = next(get_ERA5)
            """ PROCESS THE COMPARISON OF PARCEL PRESSURES TO CLOUDS """
            if len(datpart['x']) > 0:
                # tropopause pressure at the location of the parcels
                #print('ptropo x ',datpart['x'].min(),datpart['x'].max())
                ptrop = datera.fP(np.transpose([datpart['y'], datpart['x']]))
                nhits += convbirth(datpart['itime'],
                    datpart['x'],datpart['y'],datpart['p'],datpart['t'],datpart['idx_back'],\
                    prod0['flag_source'],ptrop,prod0['src']['x'],prod0['src']['y'],\
                    prod0['src']['p'],prod0['src']['t'],prod0['src']['age'],\
                    datsat.var['IR0'], part0['ir_start'],\
                    datsat.geogrid.box_range[0,0],datsat.geogrid.box_range[1,0],datsat.geogrid.stepx,\
                    datsat.geogrid.stepy,datsat.geogrid.box_binx,datsat.geogrid.box_biny)
        """ End of of loop on slices """
        """ INSERT HERE CODE FOR PARCELS ENDING BY AGE
        Important: if the age limit is set in the run, the age_bound needs to
        be decremented by one output step. Otherwise, the parcel disappeared
        and is wrongly processed as crossed."""
        # Check the age limit (easier to do it here)
        if len(partante['idx_back']) > 0:
            age_sec = part0['ir_start'][partante['idx_back'] -
                                        IDX_ORGN] - partante['itime']
            IIold_o = age_sec > (age_bound - (step / 24)) * 86400
            IIold_o = IIold_o & (
                (prod0['flag_source'][partante['idx_back'] - IDX_ORGN]
                 & I_STOP) == 0)
            idx_IIold = partante['idx_back'][IIold_o]
            j_IIold_o = np.where(IIold_o)
            prod0['flag_source'][idx_IIold - IDX_ORGN] = prod0['flag_source'][
                idx_IIold - IDX_ORGN] | I_DEAD + I_OLD
            prod0['src']['x'][idx_IIold - IDX_ORGN] = partante['x'][j_IIold_o]
            prod0['src']['y'][idx_IIold - IDX_ORGN] = partante['y'][j_IIold_o]
            prod0['src']['p'][idx_IIold - IDX_ORGN] = partante['p'][j_IIold_o]
            prod0['src']['t'][idx_IIold - IDX_ORGN] = partante['t'][j_IIold_o]
            prod0['src']['age'][idx_IIold - IDX_ORGN] = (
                (part0['ir_start'][idx_IIold - IDX_ORGN] - partante['itime']) /
                86400)
            print("manage age limit: number of IIold ", len(idx_IIold))
            nold += len(idx_IIold)

        # find parcels still alive after processing this step  if kept_p.sum()==0:
        try:
            nlive = ((prod0['flag_source'][partpost['idx_back'] - IDX_ORGN]
                      & I_DEAD) == 0).sum()
            n_nohit = ((prod0['flag_source'][partpost['idx_back'] - IDX_ORGN]
                        & I_HIT) == 0).sum()
        except:
            nlive = 0
            n_nohit = 0

        # check that nlive + nhits + nexits = numpart, should be true after the first day
        if numpart_s != nexits + nhits + nlive + ndborne + nold:
            print('@@@ ACHTUNG numpart_s not equal to sum ', numpart_s,
                  nexits + nhits + nlive + ndborne + nold)

        print('end hour ',
              hour,
              '  numact',
              partpost['nact'],
              ' nexits',
              nexits,
              ' nhits',
              nhits,
              ' nlive',
              nlive,
              ' nohit',
              n_nohit,
              ' nold',
              nold,
              flush=True)

        sys.stdout.flush()

        if backup & (hour % backup_step == 0):
            fl.save(bak_file_prod0, prod0)
            fl.save(
                bak_file_params, {
                    'params': [
                        hour, nhits, nexits, nold, ndborne, nnew, idx1,
                        numpart_s, current_date
                    ]
                })
    """ End of the procedure and storage of the result """
    pid = os.getpid()
    py = psutil.Process(pid)
    memoryUse = py.memory_info()[0] / 2**30
    print('memory use before clean: {:4.2f} gb'.format(memoryUse))
    del partante
    del partpost
    del live_a
    del live_p
    del datpart
    prod0['rvs'] = prod0['rvs'].astype(np.float32)
    for var in ['age', 'p', 't', 'x', 'y']:
        prod0['src'][var] = prod0['src'][var].astype(np.float32)
    pid = os.getpid()
    py = psutil.Process(pid)
    memoryUse = py.memory_info()[0] / 2**30
    print('memory use after clean: {:4.2f} gb'.format(memoryUse))
    #output file
    fl.save(out_file2, prod0, compression='zlib')
    #pickle.dump(prod0,gzip.open(out_file,'wb'))
    # close the print file
    if quiet: fsock.close()