GNU Parallel para uma iteração while loop, aninhada

0

Eu tenho um pedaço de código que leva 30 horas em um supercomputador; o administrador diz que pode usar apenas um núcleo de cada vez. Ele executa uma parte do código de geração de imagens por meio de uma matriz de 60 por 60, com cada iteração (3600 deles) executando o programa de criação de imagens zdichi_eps e gravando dados em um arquivo. Meu pensamento é que o script abaixo pode ser reescrito usando o comando GNU PARALLEL, e talvez usando loops for em vez dos dois loops while. Desde que eu posso usar até 64 núcleos, isso diminuiria o tempo signifidcantly eu pensaria. Por favor, dê uma olhada e me diga o que você pensa. Como isso seria mudado? É possível? Obrigado! Eu ficaria feliz em doar para qualquer causa para o indivíduo útil para uma versão de trabalho que me impede de lutar com o datacenter!

set tb = gau_9.tab      # tab file
set target = reformat   # target name (from the command line)
set dte = May2010v1     # date of the run.
set mult1 = 0.7958  # multiplication factor
set mult2 = 'echo $mult1 | awk '{printf("%.6f",$1/2)}''
set inclin = 40       # inclination angle
set vsin = 113.3        # vsini
set aim = 0.03221 # <chisq aim>
set tphot = 5600    # photosphere temperature
set tspot = 4100    # spot temperature
set omega0 = 11.0038    # omega_0; matched to the period
set startx = 10.8   # starting omega_eq
set stepx = 0.01    # step in omega_eq
set nx = 60         # number of datapoint for omega_eq
set starty = 0.0     # starting domega
set stepy = 0.01    # step in domega
set ny = 60     # number of datapoints for domega.
set npts = 30       # number of points used in zdichi_ep        set spec = 
$target.rs
set tab  = $tb
set b1 = $target.b1
set s1 = $target.s1
set out  = $target$aim$dte.out
set map  = $target$aim$dte.m
set junk = $target.dr_junk
set screen = $target.screen.dat
set zdi = $target.zdi.in
set om
set do

set ntot = 0
echo " " > $out 
echo " " > $junk
echo " " > $screen

echo "starting diffrot" > $target.afile

set i = 0 

while ($i < $nx) 
  set omega = 'echo $startx $stepx $i | awk '{printf("%.5f",$1+$2*$3)}''
  echo "Count i, Count ny " $i $ny
  echo "omega : " $omega
  set line
  set j = 0 
  while ($j < $ny) 
    echo "Count J Count ny " $j  $ny
    set domeg = 'echo $starty $stepy $j | awk '{printf("%.5f",$1+$2*$3)}''
    echo "1 delta omega : " $domeg
    set test = 'echo $omega $domeg | awk '{tmp = $1-0.361387*$2-4.461019; 
    tmp = sqrt(tmp*tmp); if (tmp < 0.02) print 1; else print 0; }''
    echo "test value : " $test 
    set test = 1
    if ($test == 0) then
        set spot = 9.000000
        set chi2 = 9.000000
        set testzdi = 9.00000
    else
        set beta  = 'echo $omega $omega0 | awk '{printf("%e",1.0-$1/$2)}''
        set gamma = 'echo $domeg $omega0 | awk '{printf("%e",$1/$2)}''
        echo "test, beta and gamma : " $test $beta $gamma
        echo "22 sending data to zdichi via diffrot2"
        echo "33 The data sent :" $vsin $spec $tab $mult1 $beta $aim $gamma $mult2 >> $screen

        # setting up the input file for zdichi_eps

        echo n > $zdi
        echo n >> $zdi
        echo 5000 $inclin $vsin >> $zdi
        echo n >> $zdi
        echo 1 >> $zdi
        echo $tphot $tspot >> $zdi
        echo $beta $gamma >> $zdi
        echo $spec >> $zdi
        echo $tab >> $zdi
        echo $mult1 $mult2 >> $zdi
        echo y >> $zdi
        echo 1.0 >> $zdi
        echo 1 >> $zdi
        echo y >> $zdi
        echo 1 >> $zdi
        echo $aim $npts >> $zdi
        echo $b1 >> $zdi
        echo y >> $zdi
        echo $s1 >> $zdi

        # finished setting up the input file for zdichi_eps

        /home/zdichi_eps < $zdi >> $out
        echo "44 finished with zdichi" 
        @ ntot++ 
        set chi2 = 'tail -20 $out | grep '<29>' | awk '{printf("%.6f", $3)}''
        set spot = 'tail -20 $out | grep '<29>' | awk '{printf("%.6f", $5)}''
        set testzdi = 'tail -20 $out | grep '<29>' | awk '{printf("%.6f", $6)}''
        echo "55 The returned values were: " $omega $domeg $test $chi2 $spot $testzdi >> $screen
    endif   

    if ($i == 0) then 
        set do = 'echo $do $domeg'
    endif

    set line = 'echo $line $chi2'
    @ j++

  end
  set om = 'echo $om $omega'
  echo $line >> $junk
  @ i++
end
    
por Gregory Perugini 21.12.2017 / 21:39

2 respostas

3

A maneira mais rápida de paralelizar esse tipo de coisa:

  1. Grave todos os arquivos de parâmetro reformat.zdi.${i}_${j}.in
  2. Chame seu programa em todos os arquivos por meio de paralelismo

por exemplo. isso:

#!/bin/bash
for f in ./reformat.zdi.*.in ;do
    echo "/home/zdichi_eps < $f > ${f%.in}.out"
done | parallel -j64
    
por 21.12.2017 / 22:18
0

No Bash, o modo preferido seria criar uma função que utilizasse $i e $j como parâmetros:

do_zdichi() {
  i="$1"
  j="$2"
  [set all variables here]
  /home/zdichi_eps < $zdi >> $out
  [postprocess output]
}
export -f do_zdichi
eval parallel do_zdichi ::: {0..$nx} ::: {0..$ny}

Você só precisa certificar-se na função de que qualquer nome de arquivo para o qual você escreve possui um nome exclusivo (por exemplo, output.$i.$j é bom, mas myoutput não é), portanto não é sobrescrito por outro processo em paralelo .

    
por 09.02.2018 / 14:44