J’ai participé en juillet au coding-camp OpenMole (j’y reviendrais surement plus tard, ou pas), où j’ai découvert un moyen d’embarquer R dans OpenMole ! Cela m’ouvre des perspectives inimaginables il y a encore quelques semaines !
Et oui parce qu’on va pouvoir piloter Netlogo avec R dans OpenMole ! Un vrai jeu de poupée russe ! Mais comme les poupées russes, il va falloir procéder par étape pour pouvoir bénéficier de la puissance de la parallélisation sur son propre desktop comme sur un cluster ou une grille et cela sans effort supplémentaire !
Etape 1 : Netlogo dans R
Je vais sauter celle du modèle Netlogo fonctionnel, pour l’exemple on va prendre un modèle de la librairie : ants . La première chose qu’on va faire c’est l’embarquer dans R. Pour cela il faudra avoir le package RNetlogo installé évidemment .
##Script R pour explorer les données le modèle ants de NetLogo #Chargement du package RNetLogo library(RNetLogo) #localiser l'installation de netlogo nl.path = "/opt/netlogo-5.3.1-64/app/" NLStart(nl.path, gui = TRUE) #lance netlogo avec (TRUE) ou non (FALSE) une GUI ##Définition du chemin du modèle model.path = "/opt/netlogo-5.3.1-64/app/models/Sample Models/Biology/Ants.nlogo" ## chargement du modèle dans netlogo NLLoadModel(model.path) ################################# ## CREATION DU PLAN D'EXPERIENCE ################################# # Ici on va définir le domaine d'exploration de notre modèle # Pour simplifier ici on le met dans le même script, mais il serait plus # judicieux de l'écrire dans un fichier Rdata ou csv quand on passera à # l'encapsulage dans OpenMole diff.rate = seq(from = 0, to = 100, by = 10) ##explorer le parametre de 0 à 100 par pas de 10 evap.rate = seq(from = 0, to = 100, by = 10) pop.dif = seq(from = 40, to = 200, by = 20) replication = seq(from = 1, to = 10, by = 1) #Création d'un data frame avec toutes les combinaison des paramètres pl.exp = expand.grid(pop = pop.dif, diff = diff.rate, evap = evap.rate) ################################# ## RUN Netlogo ################################# ##créer un dataframe vide qui sera supprimé quand on passera à openmole data.df = data.frame() #for(i in 1:length(pl.exp[,1])){ for(i in 1:5){ # Pour chaque ligne du tableau on va lancer une simulation # ATTENTION : Cette première boucle se fera par la suite dans OpenMole ##Maping des variables dans netlogo NLCommand("set population ", pl.exp$pop[i]) NLCommand("set diffusion-rate ", pl.exp$diff[i]) NLCommand("set evaporation-rate ", pl.exp$evap[i]) ## Lancement de la commande setup du modèle NLCommand("setup") ## créer un reporter qui stock la valeur de la somme de nourriture des patches food = NLDoReport(2000, "go", "sum [food] of patches") data.df = cbind(data.df, food) } data.df = t(data.df) plot(x = 1:length(data.df[,1]), y = data.df[,2], type = "l")
On a maintenant un script fonctionnel, mais il faudrait pouvoir le paralléliser. Si on voulait rester dans R il y aurait des solutions assez faciles avec les packages « snow » ou « parallel ». Cela nous conduirait à paralléliser pour une machine donnée. En utilisant OpenMole, on va être capable de paralléliser de manière transparente sur notre ordinateur de bureau, mais aussi sans effort et avec un script identique sur un cluster ou une grille de calcul.
Etape 2 : empaqueter R avec care
Voilà l’étape un peu fastidieuse (à mon sens) mais nécessaire. Les dev. d’OpenMole nous invite à utiliser care, un logiciel qui va scanner notre script pour créer une archive contenant toutes les dépendances dont aura besoin openMole pour exécuter une instance.
Modifier le srcipt
Avant cela une petite modification du script R s’impose . L’idée ici est de passer un argument au script pour lui spécifier la ligne du jeu de paramètres que l’on veut lancer et stocker les résultats dans un fichier CSV (par exemple).
##Script R pour explorer les données le modèle ants de NetLogo # Notre script va accepter un argument passé en ligne de commande args<-commandArgs(trailingOnly = TRUE) args <- as.numeric(args) ## on passe un chiffre #Chargement du package RNetLogo sans message d'info suppressPackageStartupMessages(library(RNetLogo, quietly = TRUE, warn.conflicts = TRUE)) #localiser l'installation de netlogo nl.path = "/opt/netlogo-5.3.1-64/app/" NLStart(nl.path, gui = FALSE) #lance netlogo avec (TRUE) ou non (FALSE) une gui ##Définition du chemin du modèle model.path = "/opt/netlogo-5.3.1-64/app/models/Sample Models/Biology/Ants.nlogo" ## chargement du modelé dans netlogo NLLoadModel(model.path) ################################# ## CREATION DU PLAN D'EXPERIENCE ################################# # Ici on va définir le domaine d'exploration de notre modèle # Pour simplifier ici on le met dans le même script, mais il serait plus # judicieux de l'écrire dans un fichier Rdata ou csv quand on passera à # l'encapsulage dans OpenMole diff.rate = seq(from = 0, to = 100, by = 10) ##explorer le parametre de 0 à 100 par pas de 10 evap.rate = seq(from = 0, to = 100, by = 10) pop.dif = seq(from = 40, to = 200, by = 20) replication = seq(from = 1, to = 10, by = 1) #Creation d'un data frame avec toutes les combinaisons des paramètres pl.exp = expand.grid(pop = pop.dif, diff = diff.rate, evap = evap.rate) ################################# ## RUN Netlogo ################################# ##Maping des variables dans netlogo NLCommand("set population ", pl.exp$pop[args]) NLCommand("set diffusion-rate ", pl.exp$diff[args]) NLCommand("set evaporation-rate ", pl.exp$evap[args]) ## Lancement de la commande setup du modele NLCommand("setup") ## creer un reporter qui stock la valeur de la somme de nourriture des patches food = as.data.frame(NLDoReport(2000, "go", "sum [food] of patches")) # # save(food, file = "/mypath/food.RData") NLQuit()
Une fois le script modifié, on peut tester que tout fonctionne
R --slave -f run_netlogo.R --args 4
Ce qui doit avoir pour effet de sauvegarder un fichier food.Rdata en itilisant la ligne 4 (args) du data frame créé dans le script.
Créer un package pour OpenMole
L’idée ici est de créer un package qui contient R, le script, et toutes ses dépendances (RNetlogo et Netlogo). Pour cela on utilisera care. Il vous faudra télécharger l’exécutable et le rendre exécutable soit dans le répertoire courant, soit dans les bins.
Ensuite l’usage est assez simple :
./care-x86_64 -o r.tar.gz.bin R --slave -f run_netlogo.R --args 4
Cela va avoir pour effet de lancer dans care votre script et lui permettre de détecter les dépendances. Cela peut prendre du temps en fonction du temps d’exécution de votre script.
Vous obtenez en sortie une archive nommée r.tar.gz.bin et vous pourrez passer à OpenMole !
Etape 3 : Embarquer R dans OpenMole
Vous pouvez lancer votre session OpenMole.
cd openmole_ex_dir/ ./openmole
Cela devrait avoir pour effet d’ouvrir votre navigateur préféré : Firefox (ou chrome… ça marche aussi). Dans l’interface graphique, vous pouvez charger une archive care.
Un widget bien fait détecte le paramétrage de votre script et vous propose un squelette de script openmole. Il ne vous restera plus qu’à le peaufiner pour pouvoir paralléliser tout ça. 😀
val i3 = Val[Int] //table of correspondance val output = Val[File] val rTask = CARETask(workDirectory / "myscript.tar.gz.bin", "R --slave -f run_grid.R --args ${i3}") set( inputs += (i3), //Default values. Can be removed if OpenMOLE Vals are set by values coming from the workflow outputs += (i3), outputFiles += ("simulation.RData", output) ) val copyHook = CopyFileHook(output, workDirectory / "resultats/run_result_${i3}.RData") val exploration = ExplorationTask( (i3 in (1 to 24 by 1)) ) val env = LocalEnvironment(2) //defined number of thread used by the mole exploration -< (rTask hook copyHook on env)
Enjoy et merci pour le travail incroyable de la team OpenMole !