Новосибирский институт органической химии им. Н.Н. Ворожцова СО РАН Лаборатория изучения механизмов органических реакций |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
steps#!/usr/bin/perl -ws %CONFIG = ( gaussian => { input_extension => '.gjf', output_extension => '.log', outputs_dir => "./logs", each_output_to_named_dir => 0, run => 'g09 !INPUT!', }, pcgamess => { input_extension => '.inp', # Обязательный параметр. Д.б. уникальным для каждой программы run => './pcgamess -r -f -p -i !INPUT! -o !OUTPUT!', #run => 'mpirun -np 2 ./pcgamess -r -f -p -i !INPUT! -o !OUTPUT!', # Обязательный параметр. Слова !INPUT! и !OUTPUT! не нужно изменять, # они лишь обозначают место, где будут соответствующие имена файлов # Про опции см. http://classic.chem.msu.su/gran/gamess/comm_line.html output_extension => '.out', # Подставится вместо input_extension. Если отсутсвует или пустая строка, # то в качестве output'а будет имя input-файла без расширения. outputs_dir => "./outs", # Если отсутствует, то './outs' each_output_to_named_dir => 1, # Нужно ли на каждый расчет свою директорию. Default 0 renamed_files => {PUNCH=>'.dat', IRCDATA=>'.IRCDATA.dat'}, # Жестко заданные имена файлов (ключи), которые следует переименовать, # заменив input_extension на нужные расширения (величины) }, priroda => { input_extension => '.in', run => '/usr/local/lib/priroda/p6_32 !INPUT! !OUTPUT!', }, orca => { input_extension => '.ino', run => 'orca !INPUT! > !OUTPUT!', }, test => { input_extension => '.ttt', output_extension => '.out', outputs_dir => "./outs", each_output_to_named_dir => 1, run => 'cat !INPUT! > !OUTPUT!; touch PUNCH IRCDATA; sleep 5', # *nix #run => 'type !INPUT! > !OUTPUT! && copy !INPUT! PUNCH && copy !INPUT! IRCDATA && perl -e "sleep 5"', # win renamed_files => {PUNCH=>'.dat', IRCDATA=>'.IRCDATA.dat'}, }, ); ############################################################################ use vars qw($h $debug); # Опции (my $proga = $0) =~ s/.*[\/\\]//; if ($h) { print <<HELP; Скрипт для запуска расчетов, input-файлы которых собраны в отдельную папку. Usage: $proga [-h|-debug] [mask] Идеология такова: input-файлы собираются в отдельную папку, из этой папки запускается скрипт. Скрипт выбирает файлы с расширениями, перечисленными в %CONFIG (в начале скрипта). Для каждой расчетной программы д.б. свое расширение input-файла, именно по нему скрипт определяет, какой программой запускать расчет. В %CONFIG также должно быть поле run -- это строка запуска расчетной программы. Остальные поля не обязательны. См. комментарии в тексте скрипта. В начале каждого расчета выбирается самый старый input-файл, переносится в другую папку и в ней запускается на счет. Там же будут output-файлы. Так как каждый раз папка с инпутами сканируется по новой, можно добавлять в нее новые input-файлы. При запуске скрипта в домашней директории создается скрытый файл '.$proga.run', который удаляется по окончании работы. Если этот файл существует, повторный запуск скрипта блокируется. В качестве параметра скрипту может быть дана маска (маски), например, $proga *.inp *.in -- расчет только pcgamess и priroda Маски (как csh) будут работать и на Windows, хотя cmd их не понимает. Если параметры отсутствуют, то обрабатываются все файлы, имеющие расширения, перечисленные в %CONFIG. Чтобы посчитать отдельный файл (файлы), нужно просто дать его имя как параметр. С опцией -debug скрипт будет подробно описывать свои действия. HELP exit; } ############################################################################ use Cwd 'abs_path'; my $flag = "$ENV{HOME}/.$proga.run"; if (-e $flag) { die "$proga is already running!\n"; } else { warn "Create flag file $flag\n" if $debug; open L, '>', $flag or die "Can't create $flag: $!\n"; close L; } # В качестве аргументов можно задавать маски типа *.inp в стиле csh @ARGV = ('*.*') unless @ARGV; # Вспомогательная строка типа .inp|.in для регулярного выражения $EXT = join '|', map {s/(\W)/\\$1/g; $_} map {$CONFIG{$_}{input_extension}} keys %CONFIG; warn "Extensions for regexp: $EXT\n" if $debug; # Запоминаем полный путь рабочей директории, чтобы потом можно было сюда вернуться $cwd = abs_path('.'); warn "Current work dir: $cwd\n\n" if $debug; # Пока в рабочей директории остаются подходящие input-файлы while ( $input_name = get_input_names() ) { warn "Processing $input_name\n" if $debug; # Получаем имя input-файла без расширения и расширение ($name,$ext) = $input_name =~ /(.+)($EXT)$/; # Имя программы, соответствующее расширению input-файла ($program) = grep {$CONFIG{$_}{input_extension} eq $ext} keys %CONFIG; warn "Filename: $name, extension: $ext, program: $program\n" if $debug; # Директория для output'ов (если не задана, то ./outs) $outputs_dir = $CONFIG{$program}{outputs_dir} || './outs'; # Создаем эту директорию, если ее нет if (! -d $outputs_dir) { warn "Create $outputs_dir\n" if $debug; mkdir $outputs_dir or die "Can't create $outputs_dir: $!\n"; } # Если нужно на каждый расчет свою директорию if ( $CONFIG{$program}{each_output_to_named_dir} ) { $output_dir = "$outputs_dir/$name"; # Создаем такую директорию, если ее нет if (! -d $output_dir) { mkdir($output_dir) || die("Can't create $output_dir: $!\n"); } } else { $output_dir = $outputs_dir; } # Двигаем input-файл в директорию, где будет проходить расчет if (abs_path($output_dir) ne $cwd) { warn "Move $input_name to $output_dir\n" if $debug; rename($input_name, "$output_dir/$input_name") || die("Can't move $input_name to $output_dir: $!\n"); } # а если эта директория совпадает с рабочей, то переименовываем input-файл else { warn "Rename $input_name to ${input_name}_run\n" if $debug; rename($input_name, $input_name.'_run') || die("Can't Rename $input_name to ${input_name}_run: $!\n"); } # Генерируем имя output-файла $output_name = $name; $output_name .= ".$CONFIG{$program}{output_extension}" if $CONFIG{$program}{output_extension}; warn "Output: $output_name\n" if $debug; # Переходим в директорию, где будет проходить расчет warn "Change dir to $output_dir\n" if $debug; chdir $output_dir or die "Can't chdir to $output_dir: $!\n"; # Генерируем строку запуска программы $run = $CONFIG{$program}{run} or die "No run string for $program in %CONFIG\n"; $run =~ s/!INPUT!/"$input_name"/g; $run =~ s/!OUTPUT!/"$output_name"/g; warn "Run: $run\n" if $debug; # Печатаем... print "$program: $name ... "; $time0 = time; # Запускаем программу system $run; # Печатаем время счета printf "Done for %.3f h\n", (time - $time0)/3600; # Postprocessing if (ref $CONFIG{$program}{renamed_files} eq 'HASH') { while (my ($file,$ext) = each %{$CONFIG{$program}{renamed_files}}) { next if ! -f $file; warn "Rename $file to $name$ext\n" if $debug; rename($file, $name.$ext) || warn("Can't rename $file to $name$ext: $!\n"); } } # Возвращаемся в рабочую директорию, где лежат input-файлы warn "Change dir to work dir $cwd\n" if $debug; chdir $cwd or die "Can't chdir to work dir $cwd: $!\n"; warn "\n" if $debug; } print " Processing finished\n"; warn "Delete flag file $flag\n" if $debug; unlink $flag; exit(0); # Сканирование директории с input-файлами с раскрытием маски # Возвращается самый старый input-файл sub get_input_names { my @input_names = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [$_, (stat)[9]] } grep { /(?:$EXT)$/ } grep { -f } map { glob } @ARGV; warn "Current sorted by date input files: @input_names\n" if $debug; return $input_names[0]; } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||