2015-05-21 6 views
7

Ich versuche, einige parallele Optimierung mit PyOpt zu führen. Der schwierige Teil ist, dass ich innerhalb meiner Zielfunktion einen C++ - Code mit mpi ausführen möchte.Python mit integriertem Aufruf von mpirun

Mein Python-Skript ist die folgende:

#!/usr/bin/env python  
# Standard Python modules 
import os, sys, time, math 
import subprocess 


# External Python modules 
try: 
    from mpi4py import MPI 
    comm = MPI.COMM_WORLD 
    myrank = comm.Get_rank() 
except: 
    raise ImportError('mpi4py is required for parallelization') 

# Extension modules 
from pyOpt import Optimization 
from pyOpt import ALPSO 

# Predefine the BashCommand 
RunCprogram = "mpirun -np 2 CProgram" # Parallel C++ program 


######################### 
def objfunc(x): 

    f = -(((math.sin(2*math.pi*x[0])**3)*math.sin(2*math.pi*x[1]))/((x[0]**3)*(x[0]+x[1]))) 

    # Run CProgram 
    os.system(RunCprogram) #where the mpirun call occurs 

    g = [0.0]*2 
    g[0] = x[0]**2 - x[1] + 1 
    g[1] = 1 - x[0] + (x[1]-4)**2 

    time.sleep(0.01) 
    fail = 0 
    return f,g, fail 

# Instantiate Optimization Problem 
opt_prob = Optimization('Thermal Conductivity Optimization',objfunc) 
opt_prob.addVar('x1','c',lower=5.0,upper=1e-6,value=10.0) 
opt_prob.addVar('x2','c',lower=5.0,upper=1e-6,value=10.0) 
opt_prob.addObj('f') 
opt_prob.addCon('g1','i') 
opt_prob.addCon('g2','i') 

# Solve Problem (DPM-Parallelization) 
alpso_dpm = ALPSO(pll_type='DPM') 
alpso_dpm.setOption('fileout',0) 
alpso_dpm(opt_prob) 
print opt_prob.solution(0) 

Ich betreibe diesen Code verwenden:

mpirun -np 20 python Script.py 

Allerdings bin ich die folgende Fehlermeldung erhalten:

[user:28323] *** Process received signal *** 
[user:28323] Signal: Segmentation fault (11) 
[user:28323] Signal code: Address not mapped (1) 
[user:28323] Failing at address: (nil) 
[user:28323] [ 0] /lib64/libpthread.so.0() [0x3ccfc0f500] 
[user:28323] *** End of error message *** 

Ich vermute, dass die 2 verschiedenen mpirun Aufrufe (derjenige, der das Python - Skript aufruft und der innerhalb der Skript) stehen miteinander in Konflikt. Irgendwelche Hinweise darauf, wie das zu lösen ist?

Vielen Dank !!

+0

Haben Sie Daten zwischen den python-Prozesse mit mpi Kommunikation auszutauschen oder sind Sie nur mit 'mpi4py' mehrere isolierte Instanzen laufen. Wenn dies der Fall ist, können Sie das 'subprocess'-Modul in Python verwenden, um mehrere Threads zu erzeugen, von denen jeder eine' mpirun'-Instanz aufrufen kann (mit 'subprocess.Popen'). Ich mache das häufig und habe keine Probleme gehabt. Wenn Sie 'Script.py' auf mehreren Computern ausführen, ist dies möglicherweise nicht möglich ... –

Antwort

1

Siehe Calling mpi binary in serial as subprocess of mpi application: der sicherste Weg zu gehen ist, MPI_Comm_spawn() zu verwenden. Schauen Sie sich zum Beispiel this manager-worker example an.

Eine schnelle Lösung wäre die Verwendung von subprocess.Popen wie von @EdSmith signalisiert. Beachten Sie jedoch, dass das Standardverhalten von subprocess.Popen die Umgebung des übergeordneten Elements verwendet. Meine Vermutung ist, dass es für os.system() das gleiche ist. Leider werden einige Umgebungsvariablen von mpirun hinzugefügt, abhängig von der MPI-Implementierung, z. B. OMPI_COMM_WORLD_RANK oder OMPI_MCA_orte_ess_num_procs. Um diese Umgebungsvariablen anzuzeigen, geben Sie import os ; print os.environ in einen mpi4py-Code und in eine einfache Python-Shell ein. Diese Umgebungsvariablen können zu einem Ausfall des Subprozesses führen. So hatte ich eine Zeile hinzufügen, um sich zu befreien ... was ziemlich schmutzig ist ... Es läuft darauf hinaus:

args = shlex.split(RunCprogram) 
    env=os.environ 
    # to remove all environment variables with "MPI" in it...rather dirty... 
    new_env = {k: v for k, v in env.iteritems() if "MPI" not in k} 

    #print new_env 
    # shell=True : watch for security issues... 
    p = subprocess.Popen(RunCprogram,shell=True, env=new_env,stdout=subprocess.PIPE, stdin=subprocess.PIPE) 
    p.wait() 
    result="process myrank "+str(myrank)+" got "+p.stdout.read() 
    print result 

kompletten Testcode, lief durch mpirun -np 2 python opti.py:

#!/usr/bin/env python  
# Standard Python modules 
import os, sys, time, math 
import subprocess 
import shlex 


# External Python modules 
try: 
    from mpi4py import MPI 
    comm = MPI.COMM_WORLD 
    myrank = comm.Get_rank() 
except: 
    raise ImportError('mpi4py is required for parallelization') 

# Predefine the BashCommand 
RunCprogram = "mpirun -np 2 main" # Parallel C++ program 


######################### 
def objfunc(x): 

    f = -(((math.sin(2*math.pi*x[0])**3)*math.sin(2*math.pi*x[1]))/((x[0]**3)*(x[0]+x[1]))) 

    # Run CProgram 
    #os.system(RunCprogram) #where the mpirun call occurs 
    args = shlex.split(RunCprogram) 
    env=os.environ 
    new_env = {k: v for k, v in env.iteritems() if "MPI" not in k} 

    #print new_env 
    p = subprocess.Popen(RunCprogram,shell=True, env=new_env,stdout=subprocess.PIPE, stdin=subprocess.PIPE) 
    p.wait() 
    result="process myrank "+str(myrank)+" got "+p.stdout.read() 
    print result 



    g = [0.0]*2 
    g[0] = x[0]**2 - x[1] + 1 
    g[1] = 1 - x[0] + (x[1]-4)**2 

    time.sleep(0.01) 
    fail = 0 
    return f,g, fail 

print objfunc([1.0,0.0]) 

Grund Arbeiter, zusammengestellt von mpiCC main.cpp -o main:

#include "mpi.h" 

int main(int argc, char* argv[]) { 
    int rank, size; 

    MPI_Init (&argc, &argv);  
    MPI_Comm_rank (MPI_COMM_WORLD, &rank); 
    MPI_Comm_size (MPI_COMM_WORLD, &size); 

    if(rank==0){ 
     std::cout<<" size "<<size<<std::endl; 
    } 
    MPI_Finalize(); 

    return 0; 

}