Проблема с записью в файл в TCL-скрипте

salex50

Пользуюсь программой, в которую встроен TCL (TK-консоль: tkcon v2.3, Using: Tcl v8.5.6 / Tk v8.5.6).
Я написала скрипт, который записывает данные в файл. При размере файла 23162 bytes - программа вылетает с ошибкой "Microsoft Visual C++ Runtime library. Runtime error!" . В командной строке появляется строчка "unable to alloc 24 bytes". (ХР)
На другом компьютере скрипт так же вылетает, но уже при размере файла 225073 bytes, и при этом ничего не пишет. (Vista)
Кто-нибудь сталкивался с таким? и как можно с этим бороться? :confused:

okis

Покажи, что за скрипт.

salex50

Скрипт достаточно большой...
вот эта часть относится к записи в файл. Но он работает без ошибок, пока размер output файла не превышает определенный размер.
set outputfile [open all.dat w]
set i 3
puts -nonewline $outputfile "frame "
while {$i <= $hb+2} {
puts -nonewline $outputfile "$ldonatom($i)*$laccatom($i) "
incr i
}
puts $outputfile " "
set j 0
set num_frames [molinfo top get numframes]
for {set n 0} {$n < $num_frames} {incr n} {
puts -nonewline $outputfile "$n "
hbonds -sel1 [atomselect top "resid $ldon and not water"] -sel2 [atomselect top "resid $lacc and not water"] -writefile yes -upsel no -frames $n:$n -DA D -dist 3.1 -ang 30 -plot no -polar yes -type unique -detailout tmp.dat
set inputfile [open tmp.dat r]
set i 3
while {$i <= $hb+2} {
set count 0
seek $inputfile 0 start
while {[gets $inputfile line] >= 0} {
incr j
if {$j>2} then {
set occup($j) [split $line " "]
if {[lindex $occup($j) 0] eq $ldonatom($i) && [lindex $occup($j) 2] eq $laccatom($i)} then {
incr count
}
}
}
puts -nonewline $outputfile "$count "
incr i
}
close $inputfile
puts $outputfile " "
}
close $outputfile

salex50

проблема, вероятно, где-то в скрипте :crazy:
потому что другой мой скрипт без проблем пишет файлы таких размеров...
я много раз обращаюсь к открытому для записи файлу. это может как-то влиять?

margadon

ты главное проверь что ты не открываешь его тыщу раз

Maurog

if {[lindex $occup($j) 0] eq $ldonatom($i) && [lindex $occup($j) 2] eq $laccatom($i)} then {
incr count
}
в Tcl нет команды then, если только синтаксис не был подхачен
надо так

if {condition} {
do something
}

похоже, что глючит программа, внутри которой расположился Tcl
можно попробовать вырезать все обращения к не-Tcl-library командам, таким как atomselect, molinfo, hbonds (заменить их фейками какими-нибудь) и проверить работоспособность

oliver11

в Tcl нет команды then, если только синтаксис не был подхачен
Там есть syntactic sugar у команды if.
А глючит действительно скорее всего внешняя программа или откуда там берутся эти команды.

Maurog

Там есть syntactic sugar у команды if.
точно. никогда не использовал его :ooo:

salex50

Я нашла ошибку в скрипте - забыла поставить обнуление счетчика j перед циклом. И он создавал все время новые элементы вместо того, чтобы затирать старые.
но это решило проблему не полностью - теперь вылетает при размере файла 520192 bytes.
Может быть есть какие-то внутренние ограничения на количество элементов в списке или количество переменных, которое может храниться в памяти?..... :confused:

Maurog

Я нашла ошибку в скрипте
теперь вылетает при размере файла 520192 bytes.
ты не нашла ошибку :grin:
Пользуюсь программой, в которую встроен TCL
о какой программе речь? какая версия ?

salex50

Думаешь это совпадение, что скрипт теперь работает дольше? :ooo:
TK-консоль: tkcon v2.3, Using: Tcl v8.5.6 / Tk v8.5.6

Программа VMD1.8.7 - если это чем-то поможет.
И все таки бывают ли внутренние ограничения на количество переменных? Если бывают, то о числах каких порядков идет речь?

oliver11

Кажется, вверху я был несколько неправ...
set occup($j) [split $line " "]
Массив съедает всю память? Что там в $line вообще?

salex50

стандартная line: ASP73-Main-N GLY69-Main-O 100.00%
Величина i и j примерно 200
величина n где-то 3000-5000
и я уже заменила occup($j) на occup - так чтобы не создавать большой массив, а записывать временную информацию все время в одну переменную.
после обнуления j с матрицей occup($j) - скрипт стал дольше работать
после обнуления j и замены матрицы на переменную occup - вообще ничего не изменилось - скрипт вылетает в тот же самый момент.
сейчас скрипт выглядит так:
set outputfile [open $nf-all.dat w]
set i 3
puts -nonewline $outputfile "frame "
while {$i <= $hb+2} {
puts -nonewline $outputfile "$ldonatom($i)*$laccatom($i) "
incr i
}
puts $outputfile " "
set j 0
set num_frames [molinfo top get numframes]
for {set n 0} {$n < $num_frames} {incr n} {
puts -nonewline $outputfile "$n "
hbonds -sel1 [atomselect top "resid $ldon and not water"] -sel2 [atomselect top "resid $lacc and not water"] -writefile yes -upsel no -frames $n:$n -DA D -dist $dist -ang $ang -plot no -polar yes -type unique -detailout tmp.dat
set inputfile [open tmp.dat r]
set i 3
while {$i <= $hb+2} {
set count 0
set j 0
seek $inputfile 0 start
while {[gets $inputfile line] >= 0} {
incr j
if {$j>2} then {
set occup [split $line " "]
if {[lindex $occup 0] eq $ldonatom($i) && [lindex $occup 2] eq $laccatom($i)} then {
incr count
}
}
}
puts -nonewline $outputfile "$count "
incr i
}
close $inputfile
puts $outputfile " "
}
close $outputfile

salex50

при удалении строки
hbonds -sel1 [atomselect top "resid $ldon and not water"] -sel2 [atomselect top "resid $lacc and not water"] -writefile yes -upsel no -frames $n:$n -DA D -dist $dist -ang $ang -plot no -polar yes -type unique -detailout tmp.dat

скрипт не виснет.
hbonds - это встроенный скрипт... :crazy:
Если предположить, что после 1000 обращений к нему, скажем кончается память или превышается лимит чего-нибудь, можно как-нибудь все "обнулять" в процессе работы моего скрипта?

oliver11

Выглядит всё вполне легитимно.
Я правильно понимаю, что объём используемой процессом памяти резко растёт, потом возникает runtime error?
Upd. Написанное ниже уже неактуально, ибо вы это сделали.
Попробуйте локализовать проблему: поотключать вывод в файл, выключить часть циклов.
Было бы ещё интересно собрать vmd с debug info, чтобы посмотреть, где падает.

oliver11

Не виснет - в смысле не падает?
Дайте описание atomselect и hbonds.

salex50

ага - работает до конца
а как на счет "обнуления"? такое вообще можно сделать?
а какое именно нужно описание? у этого скрипта открытый код, но для меня он слишком сложный.

oliver11

Описание - в смысле документация. Хотя можно и код (лучше и то, и другое).
Обнуление - можно с помощью interp делать дочерние интерпретаторы, в них исполнять код, потом их удалять. Но это уже извращения пошли.
А hbonds в других скриптах используется? Если да, то там память кончается?

salex50

Я попробовала разбить задачу для n = 3000 на 3 задачи по 1000 шагов.
Если запускать последовательно маленькие, то они прекрасно работают, а одна большая не работает (
Конечно, можно написать скрипт так, чтобы первая задача начинала запись в output файл, а остальные продолжали - но это как-то странно.
Здесь документация по всем плагинам и есть ссылка на страничку с HBonds (раздел Analysis но там ничего нет интересного. Вероятно, Plugin Developer Documentation: - это то, что нужно.
VMD plugins
А внизу есть ссылка для скачивания. Но если нужно, могу прислать отдельно код к hbonds.

salex50

Решила автоматически разбивать расчет на несколько маленьких с помощью второго скрипта. В результате задача с n шагами, где n = 3000-5000, прекрасно считается в несколько запусков по 200 шагов.
Вероятно, это и есть способ очищать память - заканчивать работу процедуры и начинать заново.
В любом случае ничего лучше в голову не приходит :(
Спасибо всем за помощь! :)
Оставить комментарий
Имя или ник:
Комментарий: