Ваш пример кода содержит reset
внутри цикла. Это сбросит параметр цикла, что может вызвать проблемы. Например, если вы запустите это:
for {modelname in {"itertest1.mod","itertest2.mod"}}{
display (modelname);
for {dataname in {"itertest_a.dat","itertest_b.dat"}}{
display (dataname);
}
}
распечатает имена файлов, как мы могли бы надеяться:
modelname = itertest1.mod
dataname = itertest_a.dat
dataname = itertest_b.dat
modelname = itertest2.mod
dataname = itertest_a.dat
dataname = itertest_b.dat
Но если мы добавим оператор сброса:
for {modelname in {"itertest1.mod","itertest2.mod"}}{
reset; ### this is the only line I changed ###
display (modelname);
for {dataname in {"itertest_a.dat","itertest_b.dat"}}{
display (dataname);
}
}
тогда мы получаем ошибку: modelname is not defined
(потому что мы просто сбросили ее).
Однако даже без этой проблемы мы все равно получим жалобу на использование переменной цикла.
Решение 1: команды
В зависимости от того, что именно вы запустили, вы можете увидеть сообщение об ошибке, рекомендующее использовать оператор commands
, например:
reset;
for {scriptname in {"script1.run", "script2.run"}}{
commands (scriptname);
}
После этого будут выполняться любые команды из перечисленных .run-файлов, и вы сможете использовать их для вызова отдельных сценариев для определения моделей и данных. Поскольку вы не можете использовать общий сброс без уничтожения параметра цикла, вам нужно будет использовать другие опции для обновления файлов модели. AMPL предлагает возможность определять несколько «проблем» и переключаться между ними, что может быть или не быть полезным здесь; Я не исследовал это.
Оператор commands
задокументирован здесь , хотя TBH, я нахожу документацию немного трудной для понимания.
Решение 2: генерация кода
Если все остальное терпит неудачу, вы можете написать итеративный скрипт AMPL, который генерирует (и при необходимости запускает) второй скрипт, содержащий все комбинации модели / данных, которые вы хотите запустить, например:
param outfile symbolic := "runme_temp.run";
for{i in 1..3}{
for{j in 1..4}{
printf "\nreset;" > (outfile);
printf "\nmodel model%s;",i > (outfile);
printf "\ndata data%s;",j > (outfile);
printf "\nsolve;" > (outfile);
# add post-processing here as desired
}
}
close (outfile);
include runme_temp.run;
Это создаст и затем вызовет «runme_temp.run», который выглядит так:
reset;
model model1;
data data1;
solve;
reset;
model model1;
data data2;
solve;
и др. и т.д. Поскольку действительно позволяет использовать одеяло reset;
, это может упростить процесс очистки предыдущих моделей. Не самое достойное решение, но оно работает и может быть адаптировано к широкому спектру вещей.
Это можно улучшить, опустив циклы:
param outfile symbolic := "runme_temp.run";
for{i in 1..3, j in 1..4}{
printf "\nreset;" > (outfile);
printf "\nmodel model%s;",i > (outfile);
printf "\ndata data%s;",j > (outfile);
printf "\nsolve;" > (outfile);
# add post-processing here as desired
}
close (outfile);
include runme_temp.run;
В этом конкретном примере это не имеет большого значения, но циклы с множественным вложением могут работать медленно в AMPL; использование одного мультииндекса for
может существенно повлиять на производительность, поэтому, возможно, лучше привыкнуть к этой привычке.