2017-02-22 2 views
0

Je travaille sur du code qui boucle sur plusieurs fichiers netcdf (gros ~ 28G). Les fichiers netcdf ont plusieurs variables 4D [heure, est-ouest, sud-nord, hauteur] dans un domaine. L'objectif est de faire une boucle sur ces fichiers et de faire une boucle sur chaque emplacement de toutes ces variables dans le domaine et de tirer certaines variables pour les stocker dans un grand tableau. Quand il y a des fichiers manquants ou incomplets, je remplis les valeurs avec 99.99. À l'heure actuelle, je ne fais que tester en bouclant plus de 2 fichiers netcdf par jour, mais pour une raison quelconque, cela prend une éternité (~ 14 heures). Je ne suis pas sûr s'il y a un moyen d'optimiser ce code. Je ne pense pas que python devrait prendre autant de temps pour cette tâche, mais c'est peut-être un problème avec python ou mon code. Ci-dessous mon code nous espérons qu'il est lisible et des suggestions sur la façon de faire cela plus rapidement est grandement appréciée:Comment rendre mon code python plus rapide

#Domain to loop over 
k_space = np.arange(0,37) 
j_space = np.arange(80,170) 
i_space = np.arange(200,307) 

predictors_wrf=[] 
names_wrf=[] 

counter = 0 
cdate = start_date 
while cdate <= end_date: 
    if cdate.month not in month_keep: 
     cdate+=inc 
     continue 
    yy = cdate.strftime('%Y')   
    mm = cdate.strftime('%m') 
    dd = cdate.strftime('%d') 
    filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00' 
    for i in i_space: 
     for j in j_space: 
      for k in k_space: 
        if os.path.isfile(filename): 
         f = nc.Dataset(filename,'r') 
         times = f.variables['Times'][1:] 
         num_lines = times.shape[0] 
         if num_lines == 144: 
          u = f.variables['U'][1:,k,j,i] 
          v = f.variables['V'][1:,k,j,i] 
          wspd = np.sqrt(u**2.+v**2.) 
          w = f.variables['W'][1:,k,j,i] 
          p = f.variables['P'][1:,k,j,i] 
          t = f.variables['T'][1:,k,j,i] 
         if num_lines < 144: 
          print "partial files for WRF: "+ filename 
          u = np.ones((144,))*99.99 
          v = np.ones((144,))*99.99 
          wspd = np.ones((144,))*99.99 
          w = np.ones((144,))*99.99 
          p = np.ones((144,))*99.99 
          t = np.ones((144,))*99.99 
        else: 
         u = np.ones((144,))*99.99 
         v = np.ones((144,))*99.99 
         wspd = np.ones((144,))*99.99 
         w = np.ones((144,))*99.99 
         p = np.ones((144,))*99.99 
         t = np.ones((144,))*99.99 
         counter=counter+1 
        predictors_wrf.append(u) 
        predictors_wrf.append(v) 
        predictors_wrf.append(wspd) 
        predictors_wrf.append(w) 
        predictors_wrf.append(p) 
        predictors_wrf.append(t) 
        u_names = 'u_'+str(k)+'_'+str(j)+'_'+str(i) 
        v_names = 'v_'+str(k)+'_'+str(j)+'_'+str(i) 
        wspd_names = 'wspd_'+str(k)+'_'+str(j)+'_'+str(i) 
        w_names = 'w_'+str(k)+'_'+str(j)+'_'+str(i) 
        p_names = 'p_'+str(k)+'_'+str(j)+'_'+str(i) 
        t_names = 't_'+str(k)+'_'+str(j)+'_'+str(i) 
        names_wrf.append(u_names) 
        names_wrf.append(v_names) 
        names_wrf.append(wspd_names) 
        names_wrf.append(w_names) 
        names_wrf.append(p_names) 
        names_wrf.append(t_names) 
    cdate+=inc 
+0

Vous pouvez utiliser le multitraitement pour traiter les fichiers en même temps. arrangez les espaces k, j, i pour les différents processus et laissez chacun d'eux faire sa propre tâche – haifzhan

+0

Qu'est-ce que 'nc.Dataset'? De plus, avant de pouvoir * améliorer * la vitesse, vous devez savoir pourquoi il est lent. Vous aurez besoin de profiler votre code et * mesure *. –

+0

c'est comment je lis dans les fichiers netcdf avec python J'ai une déclaration plus tôt dans le code non montré ici: import netCDF4 comme nc – HM14

Répondre

1

Ceci est un premier passage boiteux pour resserrer votre forloop s. Étant donné que vous n'utilisez la forme de fichier qu'une seule fois par fichier, vous pouvez déplacer la manipulation en dehors de la boucle, ce qui devrait réduire le volume de chargement des données lors de l'interruption du traitement. Je n'ai toujours pas ce que counter et inc font comme ils ne semblent pas être mis à jour dans la boucle. Vous voulez certainement regarder dans les performances de concaténation de chaîne répétée, ou comment les performances de votre appending à predictors_wrf et names_wrf regarde comme points de départ

k_space = np.arange(0,37) 
j_space = np.arange(80,170) 
i_space = np.arange(200,307) 

predictors_wrf=[] 
names_wrf=[] 

counter = 0 
cdate = start_date 
while cdate <= end_date: 
    if cdate.month not in month_keep: 
     cdate+=inc 
     continue 
    yy = cdate.strftime('%Y')   
    mm = cdate.strftime('%m') 
    dd = cdate.strftime('%d') 
    filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00' 
    file_exists = os.path.isfile(filename) 
    if file_exists: 
     f = nc.Dataset(filename,'r') 
     times = f.variables['Times'][1:] 
     num_lines = times.shape[0] 
    for i in i_space: 
     for j in j_space: 
      for k in k_space: 
        if file_exists:  
         if num_lines == 144: 
          u = f.variables['U'][1:,k,j,i] 
          v = f.variables['V'][1:,k,j,i] 
          wspd = np.sqrt(u**2.+v**2.) 
          w = f.variables['W'][1:,k,j,i] 
          p = f.variables['P'][1:,k,j,i] 
          t = f.variables['T'][1:,k,j,i] 
         if num_lines < 144: 
          print "partial files for WRF: "+ filename 
          u = np.ones((144,))*99.99 
          v = np.ones((144,))*99.99 
          wspd = np.ones((144,))*99.99 
          w = np.ones((144,))*99.99 
          p = np.ones((144,))*99.99 
          t = np.ones((144,))*99.99 
        else: 
         u = np.ones((144,))*99.99 
         v = np.ones((144,))*99.99 
         wspd = np.ones((144,))*99.99 
         w = np.ones((144,))*99.99 
         p = np.ones((144,))*99.99 
         t = np.ones((144,))*99.99 
         counter=counter+1 
        predictors_wrf.append(u) 
        predictors_wrf.append(v) 
        predictors_wrf.append(wspd) 
        predictors_wrf.append(w) 
        predictors_wrf.append(p) 
        predictors_wrf.append(t) 
        u_names = 'u_'+str(k)+'_'+str(j)+'_'+str(i) 
        v_names = 'v_'+str(k)+'_'+str(j)+'_'+str(i) 
        wspd_names = 'wspd_'+str(k)+'_'+str(j)+'_'+str(i) 
        w_names = 'w_'+str(k)+'_'+str(j)+'_'+str(i) 
        p_names = 'p_'+str(k)+'_'+str(j)+'_'+str(i) 
        t_names = 't_'+str(k)+'_'+str(j)+'_'+str(i) 
        names_wrf.append(u_names) 
        names_wrf.append(v_names) 
        names_wrf.append(wspd_names) 
        names_wrf.append(w_names) 
        names_wrf.append(p_names) 
        names_wrf.append(t_names) 
    cdate+=inc 
1

Je n'ai pas beaucoup de suggestions, mais deux ou trois choses à dire.

Ne pas ouvrir ce fichier tant de fois

D'abord, vous définissez cette variable et filename puis à l'intérieur de cette boucle (au plus profond: trois pour boucles profondes), vous vérifiez si le fichier existe et ouverture là sans doute (je ne sais pas ce que nc.Dataset fait, mais je suppose qu'il doit ouvrir le fichier et le lire):

filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00' 
    for i in i_space: 
     for j in j_space: 
      for k in k_space: 
        if os.path.isfile(filename): 
         f = nc.Dataset(filename,'r') 

Cela va être assez inefficace. Vous pouvez certainement l'ouvrir une fois si le fichier ne change pas avant toutes vos boucles.

Essayez d'utiliser moins de boucles

Tous ces éléments imbriqués pour-boucles aggravent le nombre d'opérations que vous devez effectuer. Suggestion générale: essayez d'utiliser des opérations numpy à la place.

Utilisez cprofile

Si vous voulez savoir pourquoi vos programmes prennent beaucoup de temps, l'une des meilleures façons de découvrir est de leur profil.

2

Pour vos questions, je pense que multiprocessing vous aidera beaucoup. J'ai parcouru vos codes et j'ai quelques conseils ici.

  1. Sans utiliser l'heure de début, mais les noms de fichiers comme itérateurs dans vos codes. Enveloppez une fonction pour trouver tous les noms de fichiers en fonction de l'heure et renvoyer une liste de tous les noms de fichiers.

    def fileNames(start_date, end_date): 
        # Find all filenames. 
        cdate = start_date 
        fileNameList = [] 
        while cdate <= end_date: 
         if cdate.month not in month_keep: 
          cdate+=inc 
          continue 
         yy = cdate.strftime('%Y')   
         mm = cdate.strftime('%m') 
         dd = cdate.strftime('%d') 
         filename = wrf_path+'\wrfoutRED_d01_'+yy+'-'+mm+'-'+dd+'_'+hour_str+'_00_00' 
         fileNameList.append(filename) 
         cdate+=inc 
    
        return fileNameList 
    
  2. Enveloppez vos codes qui récupèrent vos données et les remplissent avec 99.99, l'entrée de la fonction est le nom du fichier.

    def dataExtraction(filename): 
        file_exists = os.path.isfile(filename) 
        if file_exists: 
         f = nc.Dataset(filename,'r') 
         times = f.variables['Times'][1:] 
         num_lines = times.shape[0] 
        for i in i_space: 
         for j in j_space: 
          for k in k_space: 
           if file_exists:  
            if num_lines == 144: 
             u = f.variables['U'][1:,k,j,i] 
             v = f.variables['V'][1:,k,j,i] 
             wspd = np.sqrt(u**2.+v**2.) 
             w = f.variables['W'][1:,k,j,i] 
             p = f.variables['P'][1:,k,j,i] 
             t = f.variables['T'][1:,k,j,i] 
            if num_lines < 144: 
             print "partial files for WRF: "+ filename 
             u = np.ones((144,))*99.99 
             v = np.ones((144,))*99.99 
             wspd = np.ones((144,))*99.99 
             w = np.ones((144,))*99.99 
             p = np.ones((144,))*99.99 
             t = np.ones((144,))*99.99 
            else: 
             u = np.ones((144,))*99.99 
             v = np.ones((144,))*99.99 
             wspd = np.ones((144,))*99.99 
             w = np.ones((144,))*99.99 
             p = np.ones((144,))*99.99 
             t = np.ones((144,))*99.99 
             counter=counter+1 
            predictors_wrf.append(u) 
            predictors_wrf.append(v) 
            predictors_wrf.append(wspd) 
            predictors_wrf.append(w) 
            predictors_wrf.append(p) 
            predictors_wrf.append(t) 
            u_names = 'u_'+str(k)+'_'+str(j)+'_'+str(i) 
            v_names = 'v_'+str(k)+'_'+str(j)+'_'+str(i) 
            wspd_names = 'wspd_'+str(k)+'_'+str(j)+'_'+str(i) 
            w_names = 'w_'+str(k)+'_'+str(j)+'_'+str(i) 
            p_names = 'p_'+str(k)+'_'+str(j)+'_'+str(i) 
            t_names = 't_'+str(k)+'_'+str(j)+'_'+str(i) 
            names_wrf.append(u_names) 
            names_wrf.append(v_names) 
            names_wrf.append(wspd_names) 
            names_wrf.append(w_names) 
            names_wrf.append(p_names) 
            names_wrf.append(t_names) 
    
    
        return zip(predictors_wrf, names_wrf) 
    
  3. Utilisation du multitraitement pour effectuer votre travail. Généralement, tous les ordinateurs ont plus de 1 cœurs de processeur. Le multitraitement aidera à augmenter la vitesse quand il y a des calculs massifs de CPU. À mon expérience précédente, le multitraitement réduira jusqu'à 2/3 le temps consommé pour d'énormes ensembles de données.

    Mises à jour: Après avoir testé de nouveau mes codes et mes fichiers le 25 février 2017, j'ai trouvé que l'utilisation de 8 cœurs pour un grand ensemble de données m'a permis d'économiser 90% du temps réduit. Enfin, faites attention aux structures de données ici car c'est plutôt compliqué. J'espère que cela t'aides. S'il vous plaît laissez des commentaires si vous avez d'autres questions.