2017-03-27 17 views
0

私はMPIの初心者ですが、私はまだドキュメンテーションを調べています。しかし、mpi4pyについては、ほとんど作業していません。現在、マルチプロセッシングモジュールを使用して多くのコアを実行するコードを書いていますが、これをmpi4pyに置き換えて、複数のノードを使用してコードを実行する必要があります。私のコードは、マルチプロセッシングモジュールを使用しているときは下にあります。マルチプロセッシングとマルチプロセッシングpool.mapをmpi4pyに置き換える

、マルチプロセッシングなし

import numpy as np 
import multiprocessing 


start_time = time.time() 

E = 0.1 
M = 5 
n = 1000 
G = 1 
c = 1 
stretch = [10, 1] 


#Point-Distribution Generator Function 
def CDF_inv(x, e, m): 
    A = 1/(1 + np.log(m/e)) 
    if x == 1: 
     return m 
    elif 0 <= x <= A: 
     return e * x/A 
    elif A < x < 1: 
     return e * np.exp((x/A) - 1) 

#Elliptical point distribution Generator Function 

def get_coor_ellip(dist=CDF_inv, params=[E, M], stretch=stretch): 
    R = dist(random.random(), *params) 
    theta = random.random() * 2 * np.pi 
    return (R * np.cos(theta) * stretch[0], R * np.sin(theta) * stretch[1]) 


def get_dist_sq(x_array, y_array): 
    return x_array**2 + y_array**2 


#Function to obtain alpha 

def get_alpha(args): 
    zeta_list_part, M_list_part, X, Y = args 
    alpha_x = 0 
    alpha_y = 0 
    for key in range(len(M_list_part)): 
     z_m_z_x = X - zeta_list_part[key][0] 
     z_m_z_y = Y - zeta_list_part[key][1] 
     dist_z_m_z = get_dist_sq(z_m_z_x, z_m_z_y) 
     alpha_x += M_list_part[key] * z_m_z_x/dist_z_m_z 
     alpha_y += M_list_part[key] * z_m_z_y/dist_z_m_z 
    return (alpha_x, alpha_y) 

#The part of the process containing the loop that needs to be parallelised, where I use pool.map() 

if __name__ == '__main__': 
    # n processes, scale accordingly 
    num_processes = 10 
    pool = multiprocessing.Pool(processes=num_processes) 
    random_sample = [CDF_inv(x, E, M) 
        for x in [random.random() for e in range(n)]] 
    zeta_list = [get_coor_ellip() for e in range(n)] 
    x1, y1 = zip(*zeta_list) 
    zeta_list = np.column_stack((np.array(x1), np.array(y1))) 
    x = np.linspace(-3, 3, 100) 
    y = np.linspace(-3, 3, 100) 
    X, Y = np.meshgrid(x, y) 
    print len(x)*len(y)*n,'calculations to be carried out.' 
    M_list = np.array([.001 for i in range(n)]) 
    # split zeta_list, M_list, X, and Y 
    zeta_list_split = np.array_split(zeta_list, num_processes, axis=0) 
    M_list_split = np.array_split(M_list, num_processes) 
    X_list = [X for e in range(num_processes)] 
    Y_list = [Y for e in range(num_processes)] 

    alpha_list = pool.map(
      get_alpha, zip(zeta_list_split, M_list_split, X_list, Y_list)) 
    alpha_x = 0 
    alpha_y = 0 
    for e in alpha_list: 
     alpha_x += e[0] * 4 * G/(c**2) 
     alpha_y += e[1] * 4 * G/(c**2) 

print("%f seconds" % (time.time() - start_time)) 

import numpy as np 


E = 0.1 
M = 5 
G = 1 
c = 1 
M_list = [.1 for i in range(n)] 

#Point-Distribution Generator Function 

def CDF_inv(x, e, m): 
    A = 1/(1 + np.log(m/e)) 
    if x == 1: 
     return m 
    elif 0 <= x <= A: 
     return e * x/A 
    elif A < x < 1: 
     return e * np.exp((x/A) - 1) 



n = 1000 
random_sample = [CDF_inv(x, E, M) 
       for x in [random.random() for e in range(n)]] 
stretch = [5, 2] 

#Elliptical point distribution Generator Function 

def get_coor_ellip(dist=CDF_inv, params=[E, M], stretch=stretch): 
    R = dist(random.random(), *params) 
    theta = random.random() * 2 * np.pi 
    return (R * np.cos(theta) * stretch[0], R * np.sin(theta) * stretch[1]) 

#zeta_list is the list of coordinates of a distribution of points 
zeta_list = [get_coor_ellip() for e in range(n)] 
x1, y1 = zip(*zeta_list) 
zeta_list = np.column_stack((np.array(x1), np.array(y1))) 

#Creation of a X-Y Grid 
x = np.linspace(-3, 3, 100) 
y = np.linspace(-3, 3, 100) 
X, Y = np.meshgrid(x, y) 

def get_dist_sq(x_array, y_array): 
    return x_array**2 + y_array**2 


#Calculation of alpha, containing the loop that needs to be parallelised. 

alpha_x = 0 
alpha_y = 0 
for key in range(len(M_list)): 
    z_m_z_x = X - zeta_list[key][0] 
    z_m_z_y = Y - zeta_list[key][1] 
    dist_z_m_z = get_dist_sq(z_m_z_x, z_m_z_y) 
    alpha_x += M_list[key] * z_m_z_x/dist_z_m_z 
    alpha_y += M_list[key] * z_m_z_y/dist_z_m_z 
alpha_x *= 4 * G/(c**2) 
alpha_y *= 4 * G/(c**2) 

は、基本的には何か私のコードはありません、それは最初に特定の分布に従うポイントのリストを生成します。次に、点の距離の間の異なる関係を使用して数量「アルファ」を得る方程式を適用します。並列化が必要な部分は、アルファの計算に関わる単一のforループです。私がしたいのは、これを行うためにマルチプロセッシングの代わりにmpi4pyを使用することです。これをどうやって得るのかは分かりません。

答えて

1

マルチプロセッシング.mapバージョンをMPIに変換するには、scatter/gatherを使用します。あなたの場合、入力リストをランクごとに1つのチャンクに準備するのは便利です。主な違いは、すべてのコードが最初にすべてのランクで実行されることです。したがって、マストランク0のconidtionalによってのみ実行する必要があるすべてのコードを作成する必要があります。

if __name__ == '__main__': 
    comm = MPI.COMM_WORLD 
    if comm.rank == 0: 
     random_sample = [CDF_inv(x, E, M) 
         for x in [random.random() for e in range(n)]] 
     zeta_list = [get_coor_ellip() for e in range(n)] 
     x1, y1 = zip(*zeta_list) 
     zeta_list = np.column_stack((np.array(x1), np.array(y1))) 
     x = np.linspace(-3, 3, 100) 
     y = np.linspace(-3, 3, 100) 
     X, Y = np.meshgrid(x, y) 
     print len(x)*len(y)*n,'calculations to be carried out.' 
     M_list = np.array([.001 for i in range(n)]) 
     # split zeta_list, M_list, X, and Y 
     zeta_list_split = np.array_split(zeta_list, comm.size, axis=0) 
     M_list_split = np.array_split(M_list, comm.size) 
     X_list = [X for e in range(comm.size)] 
     Y_list = [Y for e in range(comm.size)] 
     work_list = list(zip(zeta_list_split, M_list_split, X_list, Y_list)) 
    else: 
     work_list = None 

    my_work = comm.scatter(work_list) 
    my_alpha = get_alpha(my_work) 

    alpha_list = comm.gather(my_alpha) 
    if comm.rank == 0: 
     alpha_x = 0 
     alpha_y = 0 
     for e in alpha_list: 
      alpha_x += e[0] * 4 * G/(c**2) 
      alpha_y += e[1] * 4 * G/(c**2) 

これは、各プロセッサの処理量が同じであれば問題ありません。通信が問題になる場合は、マスターランク0ですべてを行うのではなく、プロセッサ間でデータ生成を分割したいと思うかもしれません。

注:コードに関するいくつかのことは偽です。 alpha_[xy]np.ndarrayとなります。シリアルバージョンはエラーになります。

+0

うわー!これは完璧に動作します、ありがとう!今のところ、データの生成に時間がかかり過ぎないようですが、他のプロセッサーに配布するようにします。 alpha_ [xy]は有効な変数ではありません。実際にはalpha_xとalpha_yを使用して、勾配という別の量を導き出します。私はそれを実行すると、正常に動作するようだ... – ThunderFlash

関連する問題