def add_zones(location, NPP, max_time_experiment):
    '''Function used to add zones of several ensembles together.

        Loaded variables :
            NPP01_Z1 or NPP11_dead for example, depends on provided arg NPP

        Saves made : 
            Sum_Zones (dict) : contains sums of Z1, Z2, Z3, Z4, Z5, dead

        Args : 
            location (str): path to the file with the saved opt such as path = '/data/ebent/Octopus/output/' + location + '/'
            NPP (str):      number from 01 to 12 for the ensemble of particles being studied
            max_time_experiment (int) : used to crop each zone from the end to have same sizes
        '''
    from func_pickle import pickle_load, pickle_save

    Ensembles = {}
    Z = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'dead']
    npp = NPP
    path = '/data/ebent/Octopus/output/' + location + '/'
    max_time_experiment = max_time_experiment

    # Start by loading each zone and saving it in a dictionary (Zones) of a dictionary (Ensembles)
    for NPP in npp:
        Zones = {}

        for zone in Z:
            Zones[zone] = pickle_load('NPP' + NPP + '_' + zone,
                                      path,
                                      verbose=False)[max_time_experiment:]

        Zones['dead'] = Zones['dead'] - Zones['dead'][0]
        Ensembles[NPP] = Zones

    pickle_save('Ensembles', path, Ensembles)

    # Then sum up each different zone together with the other ones of each ensemble and save it in a dictionary (Sum_Zones)
    Sum_Zones = {}

    for NPP in npp:
        for zone in Z:
            if NPP == '01':
                Sum_Zones[zone] = Ensembles[NPP][zone].copy()
            else:
                Sum_Zones[zone] += Ensembles[NPP][zone]

    pickle_save('Sum_Zones', path, Sum_Zones)
def func_mask(casename, NPP, location, lon_W, lon_E, lat_S, lat_N):
    '''Function mask Octopus output.
    
    Masks the particles that go on land and particles with wrong initial position (because if particles were initialized on bathymetry, they are randomly shuffled somewere else. This function calls the function post_processing(casename, NPP, location) which is an automated version of p_xy.py

    Args :
	casename (str): casename used to save Octopus opt
	NPP (str):      number from 01 to 12 for the ensemble of particles being masked
	location (str): path to the file with the saved opt such as path = '/data/ebent/Octopus/output/' + location + '/'
        lon_W (float):  longitude west of box of initialisation for the particles as described in init_parti_xyz.py
	lon_E (float):  longitude east of box of initialisation for the particles as described in init_parti_xyz.py
	lat_S (float):  latitude south of box of initialisation for the particles as described in init_parti_xyz.py
	lat_N (float):  latitude north of box of initialisation for the particles as described in init_parti_xyz.py

    Saves made : 
    	LON, LAT, DEP, xround, yround, zround

    '''
    from func_pickle import pickle_load, pickle_save
    from func_p_xy import post_processing
    
    import numpy as np
    import h5py
    import netCDF4
    
    load_path2='/data/SO12/runs/RUN_BLING_Dec2017/SO12_RUN/DIAGNOSTICS/'
    load_path3='/data/soccom/GRID_12/'
    
    # Load files
    file1 = netCDF4.Dataset(load_path2+'so12_i0_year2006_5day_Salt.nc','r')
    
    # This is hFacC for the SOUTHERN HEMISPHERE
    file_h = h5py.File(load_path3 + 'grid.mat','r')
    hFacC = file_h.get('hFacC')
    hFacC = np.array(hFacC)
    Xf = file_h.get('XC')
    Xf = np.array(Xf)
    Yf = file_h.get('YC')
    Yf = np.array(Yf)
    
    # On selectionne la bonne taille de hFacC == taille de "bigger domain"
    lon_min   = 1440 
    lon_max   = 3241
    lat_min   = 0 
    lat_max   = 1024
    
    YC        = file1.variables['lat'][lat_min:lat_max] # de -77,99 a -40,05
    XC        = file1.variables['lon'][lon_min:lon_max] # de 120,04 a 270,04
    XC, YC    = np.meshgrid(XC, YC)
    
    hfacc = hFacC[:, lat_min:lat_max, lon_min:lon_max]
    
    
    ################### Extract the output of Octopus ###########################
    
    # Call function post_processing that I wrote    
    lon, lat, dep, xround, yround, zround = post_processing(casename=casename, NPP=NPP, location=location)
    
    LON = np.ma.masked_array(lon, mask=False)
    LAT = np.ma.masked_array(lat, mask=False)
    DEP = np.ma.masked_array(dep, mask=False)
    
    # Put a mask on hfacc==0
    for p in range(LON.shape[1]):
        for t in range(LON.shape[0]):
            if LON.mask[t,p]==True: 
                continue
            if hfacc[zround[t,p], yround[t,p], xround[t,p]]==0.:
                #print t,p
                LON.mask[t:,p]=True
    
    # Put a mask on all time steps after the first LON.mask[t,p]==True for each parti
    for p in range(LON.shape[1]):
        for t in range(LON.shape[0]):
            if LON.mask[t,p]==True:
                LON.mask[t:,p]=True
                break
    
    # Mask particles that have an initial pos out of the box I chose (this happens because of the pb of bathymetry in initial pos)
    parti = []
    for p in range(LON.shape[1]):
        if LON[0,p]<lon_W or LON[0,p]>lon_E or LAT[0,p]<lat_S or LAT[0,p]>lat_N:
            LON.mask[:,p]=True
            parti.append(p)
    
    print ''
    print 'Number of particles that are out of the initial box on first time step :', len(parti)
    print ''

    # Make sure all pos have the same mask
    LAT.mask = LON.mask
    DEP.mask = LON.mask
    
    xround.mask = LON.mask
    yround.mask = LON.mask
    zround.mask = LON.mask
    
    # Save the variables
    path = '/data/ebent/Octopus/output/' + location + '/'
    pickle_save('NPP' + NPP + '_DEP', path, DEP)
    pickle_save('NPP' + NPP + '_LAT', path, LAT)
    pickle_save('NPP' + NPP + '_LON', path, LON)
    
    pickle_save('NPP' + NPP + '_zround', path, zround)
    pickle_save('NPP' + NPP + '_yround', path, yround)
    pickle_save('NPP' + NPP + '_xround', path, xround)
def count_zones(location, NPP, npts):
    '''Function to count how many particles of the Octopus output are in each 5 zones of the domain of study.
    
    Function first counts how many particles are "alive" for at least one time step then counts for each zone at each time step how many particles are in. Also counts the particles that "die" which is equivalent of one a particle gets masked.

    Args :
        location (str): path to the file with the saved opt such as path = '/data/ebent/Octopus/output/' + location + '/'
        NPP (str):      number from 01 to 12 for the ensemble of particles being studied
        npts (int):     total number of particles in this ensemble
    
    Loaded variables :
        LON, LAT, DEP, xround, yround, zround, southern_front

    Saves made : 
        Z1, Z2, Z3, Z4, Z5, dead
    '''

    import numpy as np
    from func_pickle import pickle_load, pickle_save

    southern_front = pickle_load('ACC_southern_front',
                                 '/data/ebent/',
                                 verbose=False)
    southern_front = np.ma.masked_array(southern_front, mask=False)

    path = '/data/ebent/Octopus/output/' + location + '/'
    DEP = pickle_load('NPP' + NPP + '_DEP', path, verbose=False)
    LAT = pickle_load('NPP' + NPP + '_LAT', path, verbose=False)
    LON = pickle_load('NPP' + NPP + '_LON', path, verbose=False)

    zround = pickle_load('NPP' + NPP + '_zround', path, verbose=False)
    yround = pickle_load('NPP' + NPP + '_yround', path, verbose=False)
    xround = pickle_load('NPP' + NPP + '_xround', path, verbose=False)

    W_boundary = 12  # 121,04 degrees
    E_boundary = 1560  # 250,04 degrees

    # Count the particles that are "alive" during part of the time serie
    are_alive = []
    for p in range(npts):
        south_front = southern_front[
            yround[:, p],
            xround[:, p]]  # select southern_front of one particle traj
        south_front.mask = xround[:, p].mask

        parti_are_dead = np.squeeze(
            np.array(np.ma.where(xround.mask[:, p] == False)))
        if parti_are_dead.size > 0.:
            are_alive.append(p)

    print ''
    print 'Number of particles "alive" :', len(are_alive)

    # Particle analysis : count the particles in each zone according to time
    Z1 = np.zeros(xround.shape[0])
    Z2 = np.zeros(xround.shape[0])
    Z3 = np.zeros(xround.shape[0])
    Z4 = np.zeros(xround.shape[0])
    Z5 = np.zeros(xround.shape[0])
    dead = np.zeros(xround.shape[0])

    for p in are_alive:  #range(npts)
        south_front = southern_front[
            yround[:, p],
            xround[:, p]]  # select southern_front of one particle traj
        south_front.mask = xround[:,
                                  p].mask  # mask elements of south_front that are irrelevant
        #print ''
        #print 'nb of parti :', p
        for t in range(xround.shape[0]):
            if south_front[t] != 0 and xround[t, p] > W_boundary and xround[
                    t, p] < E_boundary:
                #print t, 'in RG'
                Z1[t] += 1
                #print Z1[t], Z2[t], Z3[t], Z4[t], Z5[t], dead[t]

            elif south_front[t] == 0:
                #print t, 'north'
                Z2[t:] += 1
                #print Z1[t], Z2[t], Z3[t], Z4[t], Z5[t], dead[t]
                break  # after the break, the particle is considered forever in the zone
            elif xround[t, p] <= W_boundary:
                #print t,'out to the west'
                Z3[t:] += 1
                #print Z1[t], Z2[t], Z3[t], Z4[t], Z5[t], dead[t]
                break
            elif xround[t, p] >= E_boundary:
                #print t, 'east'
                Z4[t:] += 1
                #print Z1[t], Z2[t], Z3[t], Z4[t], Z5[t], dead[t]
                break
            elif xround[t, p] <= W_boundary and xround[t, p] >= E_boundary:
                #print t, 'east and west'
                Z5[t:] += 1
                #print Z1[t], Z2[t], Z3[t], Z4[t], Z5[t], dead[t]
                break

            elif south_front[t - 1] != 0 and xround[
                    t - 1, p] > W_boundary and xround[
                        t - 1, p] < E_boundary and xround.mask[t, p] == True:
                #print t, 'parti is dead !'
                dead[t:] += 1
                #print Z1[t], Z2[t], Z3[t], Z4[t], Z5[t], dead[t]
                #print Z1[t-1], Z2[t-1], Z3[t-1], Z4[t-1], Z5[t-1], dead[t-1]
                break
            ##print Z1[t], Z2[t], Z3[t], Z4[t], Z5[t], dead[t]

    print ''
    print 'Different zones at t = 0 :', Z1[0], Z2[0], Z3[0], Z4[0], Z5[
        0], dead[0]
    print 'Different zones at t =', xround.shape[0], ':', Z1[-1], Z2[-1], Z3[
        -1], Z4[-1], Z5[-1], dead[-1]
    print 'check at t = 0 :', Z1[0] + Z2[0] + Z3[0] + Z4[0] + Z5[0] + dead[0]
    print 'check at t = 44 :', Z1[44] + Z2[44] + Z3[44] + Z4[44] + Z5[
        44] + dead[44]
    print 'check at t = 100 :', Z1[100] + Z2[100] + Z3[100] + Z4[100] + Z5[
        100] + dead[100]
    print 'check at t =', xround.shape[
        0], ':', Z1[-1] + Z2[-1] + Z3[-1] + Z4[-1] + Z5[-1] + dead[-1]
    print ''

    pickle_save('NPP' + NPP + '_Z1', path, Z1, verbose=False)
    pickle_save('NPP' + NPP + '_Z2', path, Z2, verbose=False)
    pickle_save('NPP' + NPP + '_Z3', path, Z3, verbose=False)
    pickle_save('NPP' + NPP + '_Z4', path, Z4, verbose=False)
    pickle_save('NPP' + NPP + '_Z5', path, Z5, verbose=False)
    pickle_save('NPP' + NPP + '_dead', path, dead, verbose=False)