Главная страница проекта                         

 

 

 

 

 

 

 

 

 

 

Реализация программы

Операционной системой для  программы была выбрана ОС Linux от RedHat inc. Выбор связан с тем, что данная ОС является свободно распространяемой (по крайней мере ее ранние версии: RedHat 5.0, 6.0, 7.2, 8.0, 9.0) и отличается своей особой устойчивостью в работе. Кроме того данная ОС является основной в ЛКХСФ. Компилировался код с помощью специальной библиотеки компиляторов gcc версий 2.96.88 и 3.2.2. Текст программы переносим между версиями RedHat выше 6.0. Для Linux RedHat 5.0 работает только бинарный файл программы, предварительно скомпилированный на старших версиях ОС с флагом -static, то есть в командной строке это будет выглядеть так

% g++ Carttesius.C -о cartm -static

где g++— компилятор C++ из библиотеки gcc, -о - флаг спецификации имени выходного исполняемого файла. Флаг -static нужен для статического включения стандартных библиотек С++, то есть требуемая стандартная библиотека будет включена в тело исполняемого файла. Без этого флага при запуске программа будет вызывать нужную библиотеку, которой может не быть в данной ОС, как это и происходит в случае RedHat 5.O. Такой подход (статическое подключение библиотек) дает выигрыш в переносимости, но размер программы при этом значительно растет (в случае Carteius в 2,5 раза).

На данный момент компания RedHat inc. прекратила выпуск ОС с одноименным названием и открыла новую ветку ОС Fedora Core. Новая ОС теперь лишь частично поддерживается компанией RedHat и стала свободным проектом (Fedora Project). Однако, несмотря на это, Fedora Core имеет полную совместимость с RedHat и программа Cartesius работает также на данной ОС (Fedora Core версий 1 и 2).

Ниже приводится полный список операционных систем, поддерживающих программу Cartesius:

•   RedHat 5.0, 6.0, 7.2 с gcc версии 2.96;

•   RedHat 8.0 с gcc версии 3;

•   RedHat 9.0 с gcc версии 3.2.2;

•   Fedora Core 1 с gcc версии 3.3;

•   Fedora Core 2 с gcc версий 3.3.2 и 3.4.

К моменту написания созданы методы чтения для программ ECF 2 .5, BFSCF и Molcryst 1.0. Требует доработки чтение для программы BF 2002.

При конструировании методов активно использовалась так называемая Библиотека стандартных шаблонов (БСШ) или в английской аббревиатуре STL (Standart Template Library). Это библиотека в составе C++, включающая в себя основной набор контейнерных классов, алгоритмов и итераторов ("счетчиков"). В основной своей массе компоненты БСШ являются интструментами манипуляции над объектами абстрактных (не стандартных) классов.

Чтение ECF 2.5 (метод ReadECFO)

Метод состоит из двух частей: чтение входного файла и создание объекта molecule.

Для написания чтения входного файла за основу был взят основной файл программы ECF 2.5 ehscf2_5.f (текст на языке Fortran 77).

Метод имеет тип void, то есть метод при вызове не будет возвращать какое-либо значение

void ReadECFO

Далее после заголовка определяются основные константы внутри метода:

const long int NUMATM = 300; const long int MAXORB = 1500; const long int NUMD  = 5;

где NUMATM - максимальное число атомов в молекуле; MAXORB - масималь-ное число орбиталей; NUMD - число d-орбиталей (нужен как грамматический параметр).

После идет определение основных переменных метода:

char Keywrd[80];

char Koment[80];

char Title[80];

int FormChMol; // Formal charge of ecf molecule

int dElecNum;  // Number of d-electrones

int FormChCAt; // Formal charge of central atom

int Natoms;

char AtName[2][NUMATM];

int NNSS[NUMATM]; // Number of nonstandard shells for atoms

int fl36; // Flag for central atom

char symm[3]; // Ecf molecule Group of symmetry

double С [3][NUMATM];  // Cartesian coordinates of atoms

где Keywrd - строка с ключевыми словами; Koment - коментарий к задаче; FormChMol - формальный заряд молекулы (некоторое целое число); dElecNum - фактическое число d-электронов у центрального атома; FormChCAt - формальный заряд центрального атома (некоторое целое число); Natoms - число атомов в молекуле; AtName - имя атома (в периодической таблице); NNSS - число нестандартных оболочек для атома (оболочек требующих нестандартной параметризации); fl36 - одна из тонкостей написания входного файла - это число ставится напротив атома комплексообразователя после декартовых координат (история возникновения не известна); symm - группа симметрии молекулы; С - декартовы координаты атомов.

Из определения видно, что большинство переменных заданы в виде статических массивов. Данный подход не является хорошим с точки зрения экономии объемов памяти. Хотя в последнее время доступные объемы памяти для хранения данных значительно выросли, однако остается проблема со скоростью доступа к этим данным. Некоторыми производителями эта проблема частично в настоящий момент решена, но соответствующее оборудование остается все еще весьма дорогостоящим. Кроме того сейчас остро стоит проблема стабильности работы жестких дисков больших объемов.

При запуске программа занимает некоторый участок жесткого диска и если этот участок будет слишком велик, то скорость выполнения программы будет замедляться (иногда значительно). Проблема может быть решена двумя путями: использование динамического отведения участков памяти вместо статического и использование оперативной памяти в качестве хранилища данных. В последнем случае сильно растет скорость работы программы, но возникает необходимость увеличения объемов ОЗУ и увеличивается риск краха системы при слишком активном использовании оперативной памяти. Современное развитие технологии оперативного хранения данных (DDR или DDR2) пришло не только к огромным скоростям доступа к памяти, но и к значительному росту вероятности возникновения ошибки во время работы устройства, то есть, проще говоря, современные ОЗУ могут работать нестабильно.

Таким образом, в будущем код будет переписываться под использование динамического распределения памяти.

После задания основных переменных создаются перменные для чтения входного файла:

ifstream in  ("F0R005"); char buffer[80];

где переменная входного потока (ifstream в С++) in имеет строгую привязку к имени файла F0R005. Переменная buffer необходима для хранения прочитанной строки .

Факт строгой привязки к имени входного файла с данными по задаче вводит значительные ограничения для использования программы: имена файлов, определенные пользователем будут переименовываться в одно, что может привести к непредвиденным конфликтам с именами файлов (для программы ECF 2.5 имя FQR005 является стандартным). Для большей гибкости использования метода целесообразно сохранять пользовательские имена.

Чтение строк происходит следующим образом:

in.getline(buffer, 80);

после чего значение buffer передается другим переменным с помощью функции sscanf (стандартная функция в C++).

Вторая часть метода посвящена передаче значений полученных выше переменных полям объекта molecule.

Вначале инициализуются переменные NumberOf Atoms и Charge класса Composition:

this->Composition.NumberOfAtoms=Natoms; this->Composition.Charge  = some_value;

Дадим пояснение использования ключевого слова this. Когда функция, принадлежащая классу, для обработки данных конкретного объекта, этой функции автоматически и неявно передается указатель на тот объект, для которого функция вызвана. Этот указатель имеет фиксированное имя this и незаметно для программиста определен в каждой функции класса следующим образом:

имя_класса * const this = адрес_обрабатываемого_объекта

(значением указателя в языке С++ служит адрес участка памяти, выделенного для объекта конкретного типа).

Далее идет цикл for для записи в поля классов Composition, Geometry и для Structure в поле ао:

for(int  ia=0;   ia < this->Composition.NumberOfAtoms;ia++) ¦C

В цикле инициализуются переменные типов point, node, atom и ао с помощью функций AddPoint(), AddNode(), AddAtom() и AddAtomBasis() соответственно. Эти же функции инициализованные переменные записывают в вектора указателей соответствующих типов: pPoints, pNodes, pAtoms и pAOBasis.

После определения состава и геометрии молекулы идет определение электронной структуры. Частично она определена выше для базиса атомных орбиталей. Дальше описываются группы, число которых в методе ECF строго 3: группа d-электронов металла, группа электронов лигандов плюс s- и р-орбитали металла и группа остовных электронов всех атомов.

Группа строится из одноэлектронных состояний (One Electron State -OES), представляющих собой в общем случае линейную комбинацию атомных орбиталей (ЛКАО). OES имеет тип тар (один из типов в БСШ), строящийся как вектор пар строго связанных между собой объектов. Для одноэлектронных состояний такими объектами являются атомные орбитали и их веса (типа double) в разложении ЛКАО. Тип функций соответствующих атомных орбиталей для объекта molecule пока не важен (нет соответствующих рабочих типов данных), но в будущем предполагается обязательным давать такие определения введением нужных типов данных. Сейчас можно об орбиталях говорить лишь как об "этикетках" без привязки к типу. В методе ECF атомные орбитали являются слэтеров-скими (или орбитали Слэтера-Зенера), то есть имеют следующий вид:

где Nn - нормировочный множитель, £ - орбитальная экспонента, Yim -сферическая гармоника, п* - постоянное число, определямое эмпирически и связанное с главным квантовым числом п (например, при п = 4 п* = 3,7).

Сами одноэлектронные состояние записываются в вектор subspace, который вместе с числом электронов, мультиплетностью и некоторыми другими переменными передается функции AddGroup() класса Structure для создания новой группы.

Важной особенностью конструирования групп для данного метода (связаной с самим методом ECF) является "одноорбитальность" всех одноэлектронных состояний, то есть каждое одноэлектронное состояние соответствует некоторой атомной орбитали с весом 1,0. Кроме того из данных по группам в методе ECF невозможно извлечь информацию о связях в молекуле.

Чтение BFSCF (метод ReadBFSCFO)

Способ чтения входного потока для программы BFSCF во много схож; с изложенным выше для ECF 2.5, поэтому приводятся лишь некоторые особенности кода.

Метод ReadBFSCF также имеет неопределенный тип void:

void ReadBFSCFO

Вначале приводится определение основных констант внутри метода:

const long  int MAXHEV=65;

const long  int MAXLIT=42;

const long  int NUMATM=107;

const long  int MAXGRP=92;

const long  int MAX0RB=442; // ?

где MAXHEV - максимальное число "тяжелых"атомов (с атомным номером не меньше 18), MAXLIT - максимальное число легких атомов (соответственно с атомным номером меньше 18), NUMATM - максимальное суммарное число атомов, MAXGRP - максимальное число групп, MAX0RB -максимальное число орбиталей.

Первой особенностью в ReadBFSCF является возможность задания любого не большего 92 числа электронных групп. Кроме того, составляющие группу одноэлектронные состояния могут быть не "одноорбиталь-ными", то есть одноэлектронные состояния могут быть гибридами в терминах Л К АО, составленными из нескольких атомных орбиталей с некоторыми затравочными весами (коэффициентами при них в разложении ЛКАО).

При создании групп, соответствующих двухцентровым связям и непо-деленным парам электронов, в вектор pArcs объектов типа arc записыа-ется информация о связях в молекуле.

Последней опредляется группа остовных электронов.

Чтение Molcryst (метод ReadMolCryst ())

Метод имеет неопределенный тип void:

void ReadMolCryst()

{

Основные константы внутри метода:

const   int MATMOL  = 50;

const   int MAXTYP  = 1;

const   int MAXMOL  = 5;

const   int MAXIND         = 4;

const   int MAXTEMP = 10;

const   int MAXPOINT    = 10;

const   int MAXSPEED    = 10;

где MATMOL - максимальное число атомов в молекуле, MAXTYP - максимальное число типов молекул в элементарной ячейке (без привязки к симметрии), MAXMQL - максимальное число молекул в элементарной ячейке, MAXIND - максимальное число симметрийно независимых молекул, МАХТЕМР - максимальное число температур, при которых должен расчитываться кристалл, MAXPOINT - максимальное число точек в обратном пространстве, MAXSPEED - максимальное число направлений для расчета скорости звука в кристалле.

Для программы Molcryst достаточно задать только геометрию и атомный состав. Особенности электронной структуры не учитываются при расчетах, поэтому записываются только поля классов Composition и Geometry.

В текущей реализации программы Molcryst возможно задание только одного типа молекул, поэтому в методе ReadMolCryst () не возникает проблема, которая была отмечена в разделе "Входной поток программы Molcryst 1.0", связанная с необходимостью создания нескольких объектов molecule.

Дополнительные методы в программе Cartesius:

WriteXMLO HWriteVRMLO

Несмотря на то, что эти методы всего лишь дополнительные, они являются попыткой решения одной из важнейших проблем современной вычислительной химии, а именно проблемы компьютерного представления молекулы и/или молекулярной системы, отражающего максимально все детали структуры и удобного в обращении и для стандартизации.

В настоящий момент существует огромное число форматов хранения информации о молекуле. Среди них наиболее известным является формат языка CML (Chemical Markup Language), созданный на основе языка XML (extensible Markup Language). Сам язык XML в свою очередь является универсальным и главное расширяемым языком разметки. С помощью соответствующего обработчика xml-файлов пользователь может получить представление об иерархии документа и имеет возможность быстрого доступа к отдельным его элементам. Расширяемость языка XML достигается путем создания документов DTD (Document Type Definition), в которых определяются все новые (опредляемые создателем расширения) теги (управляющие слова разметки) вместе с определением их основных характеристик (параметров). Собственно говоря, таким образом и был создан язык CML. Главным недостатком CML является несовсем точное, а иногда несовсем корректное (с точки зрения химии) описание структуры молекулы.

В ЛКХСФ А. Л. Чугреевым было предложено создание нового расширения языка XML, во многом схожего с CML, но призванного более точно (опять же с химической точки зрения) определять структуру молекулярной системы. Предварительное название расширения - MOLXML.

Метод WriteXML () создан для вывода значений полей объекта molecule в формате MOLXML.

Для визуализации молекулярных данных может также быть использован формат языка VRML (Virtual Reality Modeling Language). Как следует из его названия, VRML является языком моделирования виртуальной реальности. Полное описание (специфиацию) этого языка можно найти на сайте Web3D. В программе Cartesius выводом в этом формате занимается метод WriteVRML, написанный аспирантом ЛКХСФ М. Забаловым.

Охарактеризуем каждый из методов.

WriteXMLO

В формате MOLXML основным тегом является <molecule>, внутри которого определяются все остальные структурные данные.

Первыми определяются данные по составу общего характера: число атомов, формальный заряд молекулы и число электронов в системе. Все данные передаются в качестве параметров тега <composition>, то есть:

<composition numat=...   charge=...  numelsys=...   >

В методе WriteXMLO это записывается следующим образом:

int elecnum=0;

Ngroups=this->Structure.pGroups.size();

for(int g=0;g<=Ngroups-l;g++)

{

elecnum=elecnum+this->Structure.pGroups[g]->NumberOfElectrons; }

cout «  "\t<composition  "; NumAt=this->Composition.pAtoms.size(); cout «  "numat=\""  « NumAt «  "\"  ";

cout «  "charge=\""  « this->Composition.Charge  «  "\IMI; cout «  " numelsys=\""  « elecnum «  "\">"  « endl;

Далее записываются данные по атомному составу внутри тега <atoms>. Список состоит из тегов <atom> с параметрами порядковый номер, атомный номер и символ в периодической таблице:

<atom id=...  num=...   symbol="..."  >

или в программном виде (далее просто code:):

cout «  "\t\t<atoms>"  « endl;

for(int a=0;a<=this->Composition.pAtoms.size()-1;a++)

{

sprintf (buff er, "°/od" , (this->Composition.pAtoms [a] ->Id+l));

cout « "\t\t\t<atom id=\"" « buffer « "\" num=\"";

AtNum=this->Composition.pAtoms[a]->pElement->AtomicNumber;

sprintf (buff er, "°/od" ,this->Composition.pAtoms [a] ->pElement->AtomicNumber);

cout « buffer « "\" symbol=\"";

cout << periodic::MendeleevPeriodicTable[AtNum].Render.Symbol;

cout « "\"/>" « endl;

cout « "\t\t</atoms>" « endl; cout « "\t</composition>" « endl; cout « endl;

Так заканчивается ввод по составу и начинается описание молекулярного графа, заключенное внутри тега <mol_graph>. В качестве параметров этого тега опредляются числа вершин и дуг:

<mol_graph numnodes=...  numarcs=...   > code:

cout «  "\t<mol_graph  ";

NumNodes=this->MolGraph.pNodes.size();

cout «  "numnodes=\""  « NumNodes «  "\"  ";

NumArcs=this->MolGraph.pArcs.size();

cout «  "numarcs=\""  « NumArcs «  "\">"  « endl;

При описании вершины определяется ее порядковый номер и валентность (количество дуг, сходящихся в данной вершине):

<node id=...  valence=...   > code:

cout « "\t\t<nodes>" « endl; for(int n=0;n<=NumNodes-l;n++)

sprintf (buff er, "°/.d" , (this->MolGraph.pNodes [n] ->Id+l)); cout « "\t\t\t<node id=\"" « buffer « "\" "; if(this->MolGraph.pNodes[n]->Valence!=0)

sprintf(buffer,"%d",this->MolGraph.pNodes[n]->Valence); cout « "valence=\"" « buffer « "\"/>" « endl;

else

cout «  "valence=\"UNDEFV7>"   « endl;

cout «  "\t\t</nodes>"  « endl;

После описываются дуги с параметрами порядка (кратности) и номерами атомов, образующих связь:

<arc order=...  re=...   1е=...   > code:

if(NumArcs!=0) {

cout « "\t\t<arcs>" « endl;

for(int arc=O;arc<=NumArcs-l;arc++)

sprintf(buffer,"%d",this->MolGraph.pArcs[arc]->Qrder); cout « "\t\t\t<arc order=\"" « buffer « "\" "; sprintf(buffer,"%d",this->MolGraph.pArcs[arc]->pRe->Id+l); cout « "re=\"" « buffer « "\" ";

sprintf(buffer,"°/.d",this->MolGraph.pArcs[arc]->pLe->Id+l); cout « "le=\"" « buffer « "\"/>" « endl; }

cout « "\t\t</arcs>" « endl; }

cout « "\t</mol_graph>" << endl; cout « endl;

Описание геометрии включает только список точек. Тег <geometry> имеет единственный параметр: число точек. Каждая точка имеет свой порядковый номер и три декартовы координаты:

<geometry nump=... > <points>

<point id=... x=... y=... z=... /> </points> </geometry>

code:

cout « "\t<geometry ";

NumP=this->Geometry.pPoints.size();

cout « "nump=\"" « NumP « "\">" « endl;

cout « "\t\t<points>" « endl;

for(int p=0;p<=this->Geometry.pPoints.

sprintf (buffer, "°/.d" , (this->Geometry. pPoints [p] ->Id+l));

cout « "\t\t\t<point id=\"" « buffer « "\" x=\"";

sprintf (buff er, "°/of " ,this->Geometry .pPoints [p] ->R[0] );

cout « buffer « "\" y=\"";

sprintf (buff er, "°/of " ,this->Geometry .pPoints [p] ->R[1] );

cout  « buffer «  "\"  z=\"";

sprintf (buff er, "°/of " ,this->Geometry .pPoints [p] ->R[2] );

cout « buffer « "\"/>" « endl; }

cout « "\t\t</points>" « endl; cout « "\t</geometry>" « endl; cout « endl;

В этом месте необходимо отметить, что такого описания точек не достаточно. Требуется свобода в определении системы координат, а также необходимо указавывать единицы измерения (ангстремы, нанометры и т.п.).

Последним блоком в описании структуры идет построение электронной системы молекулы. Главным тегом является <structure> с параметрами полной мультиплетности молекулы, число входящих в нее групп и количество атомных орбиталей, формирующих базис для расчетов молекулы:

<structure spinmult=... ngroups=... numatorb=... > code:

cout « "\t<structure ";

cout « "spinmult=\"" « this->Structure.SpinMultiplicity « "\" ";

cout « "ngroups=\"" « Ngroups « "\" ";

cout « "numatorb=\"" « this->Structure.NumberOfAtomicOrbitals « \

"\">" « endl;

За этим тегом следует список атомных орбиталей, заключенный в тегах <aos> </aos>. Каждый элемент списка имеет в качестве параметров порядковый номер, три квантовых числа (п, 1, ш), полностью определяющих данную атомную орбиталь, и порядковый номер атома, которому принадлежит орбиталь:

<ао id=...  n=...   1=...  т=...   atid=...   > code:

cout « "\t\t<aos>" « endl;

for(int atos=0;atos<=this->Structure.pAOBasis.size()-1;atos++)

pCAO=this->Structure.pAOBasis[atos];

sprintf (buffer, "°/.d" ,pCA0->0rbital.n);

cout « "\t\t\t<ao id=\"" « (atos+1) « "\" n=\"" « buffer;

sprintf (buffer, "°/od" ,pCA0->0rbital. 1);

cout « "\" 1=\"" « buffer;

sprintf (buffer, "°/.d" ,pCA0->0rbital.m);

cout « "\" m=\"" « buffer « "\"  ";

cout « "atid=\""  «   (pCAO->pAtom->Id+l)   «  "\">"  « endl;

cout « "\t\t\t</ao>"  « endl;

cout «  "\t\t</aos>"  « endl;

Описание структуры заканчивается списком групп, определяемых набором одноэлектронных состояний, которые в свою очередь представляют собой линейные комбинации атомных орбиталей, определенных выше. Параметрами тега <group> являются его порядковый номер, количество электронов в группе, мультиплетность группы и число одноэлектронных состояний:

<group id=...  numel=...   spinmult=...  noes=...   > code:

cout « "\t\t<groups>" « endl;

map<cao*,double>::iterator piter;

int count_ao=0;

int curr_size=O;

for(int g=0;g<=Ngroups-l;g++)

sprintf (buff er, "°/od" ,this->Structure.pGroups [g] ->NumberOf Electrons);

cout « "\t\t\t<group id=\"" « (g+1) « "\" numel=\"" « buffer;

sprintf (buff er, "°/od" ,this->Structure.pGroups [g] ->SpinMultiplicity);

cout « "\" spinmult=\"" « buffer;

cout « "\" noes=\"" « \

this->Structure.pGroups[g]->Subspace.size()-curr_size;

curr_size=this->Structure.pGroups[g]->Subspace.size();

cout « "\">" « endl;

Тег <oes> определяют порядковый номер одноэлектронного состояния и число составляющих его атомных орбиталей:

<oes oesid=...  num_orb=...   > code:

for(int ioes=0;ioes<=this->Structure.pGroups Eg]->Subspace.size()-l;ioes++)

int count=0;

pOES=this->Structure.pGroups[g]->Subspace[ioes]; count=pOES->Lcao.size(); piter=pOES->Lcao .beginO ; pCAO=piter->first; if(count!=0) {

int if_icount=0;

cout « "\t\t\t\t<oes oesid=\"" « (pOES->Id) « \

"\" num_orb=\"" « count « "\">" « endl;

Соответствующие данному одноэлектронному состоянию атомные ор-битали определяются порядковым номером в определенном выше списке и коэффициентом в разложении Л К АО:

<ао aoid=...   coef=...   /> code:

for(int icount=0;icount<count;icount++)

{

int pcao_id=0;

int ncao=0;

int lcao=0;

int mcao=0;

piter=pOES->Lcao .beginO ;

pCAO=piter->first;

pAt om=pCAQ->pAt om;

ncao=pCAO->Orbital.n;

lcao=pCAO->Orbital.1;

mcao=pCAO->Orbital.m;

for (int i=O;i<=this->Structure.pAOBasis.size()-l;i++)

{

if(this->Structure.pAOBasis[i]->pAtom == pAtom &&

this->Structure.pAOBasis[i]->0rbital.n == ncao &J this->Structure.pAOBasis[i]->0rbital.l == lcao &J this->Stmcture.pAOBasis[i]->0rbital.m == mcao ) {

pcao_id=i;

count_ao++;

if(piter->second!=0)

{

cout « "\t\t\t\t\t<ao aoid=\"" « (pcao_id+l)

IIII .

cout « "\" coef=\"" « piter->second « "V

cout « "/>" « endl;

if_icount++;

pOES->Lcao.erase(piter);

if(if_icount!=0)

cout « "\t\t\t\t</oes>" « endl;

cout « "\t\t\t</group>" « endl « endl;

cout « "\t\t</groups>" « endl; cout « "\t</structure>" « endl; cout « endl;

cout « "</molecule>" « endl; cout « endl;

Приведенным выше блоком заканчивается метод WriteXMLO. Основным недостатком этого блока является алгоритм вывода атомных орбиталей в Л К АО. Для доступа к каждой последующей АО требует удаления предыдущей:

pOES->Lcao.erase(piter);

Таким образом, после применения WriteXMLO, структура объекта разрушается. Разработка более гибкого алгоритма пока дело будущего. Выходной файл на примере молекулы этилена (C2H6):

<?xml version="1.0"?>

<molecule>

<composition numat="6">

<atoms>

<atom id="l" num="6" symbol="C"/>

<atom id="2" num="6" symbol="C"/>

<atom id="3" num="l" symbol="H"/>

<atom id="4" num="l" symbol="H"/>

<atom id="5" num="l" symbol="H"/>

<atom id="6" num="l" symbol="H"/>

</atoms>

</composition>

<mol_grapli numnodes="6"  numarcs="5">

<nodes>

<node id="l" valence="4"/>

<node id="2" valence="4"/>

<node id="3" valence="lll/>

<node id="4" valence="lll/>

<node id="5" valence="lll/>

<node id="6" valence="lll/>

</nodes>

<arcs>

<arc order="2" re="0" le="l"/>

<arc order="l" re="0" le="2"/>

<arc order="l" re="0" le="3"/>

<arc order="l" re="l" le="4"/>

<arc order="l" re="l" le="5"/>

</arcs>

</mol_graph>

<geometry nump="6">

<points>

<point id="l" x="0.000000" y="0.000000" z="0.000000"/>

<point id="2" x="l.334500" y="0.000000" z="0.000000"/>

<point id="3" x="-0.596200" y="0.911300" z="0.000000"/>

<point id="4" x="-0.596200" y="-0.911300" z="0.000000"/>

<point id="5" x="l.930700" y="0.911300" z="0.000000"/>

<point id="6" x="l.930700" y="-0.911300" z="0.000000"/>

</points>

</geometry>

<structure spinmult="l" ngroups="6" numatorb="14">

<aos>

<ao id="l" n="l" l="0" m="0" atid="l">

</ao>

<ao id="2" n="2" l="0" m="0" atid="l">

</ao>

<ao id="3" n="2" 1="1" m="-l" atid="l">

</ao>

<ao id="4" n="2" 1="1" m="0" atid="l">

</ao>

<ao id="5" n="2" 1="1" m="l" atid="l">

</ao>

<ao id="6" n="l" l="0" m="0" atid="2">

</ao>

<ao id="7" n="2" l="0" m="0" atid="2">

</ao>

<ao id="8" n="2" 1="1" m="-l" atid="2">

</ao>

<ao id="9" n="2" 1="1" m="0" atid="2">

</ao>

<ao id="10" n="2" 1="1" m="l" atid="2">

</ao>

<ao id="ll" n="l" l="0" m="0" atid="3">

</ao>

<ao id="12" n="l" l="0" m="0" atid="4">

</ao>

<ao id="13" n="l" l="0" m="0" atid="5">

</ao>

<ao id="14" n="l" l="0" m="0" atid="6">

</ao>

</aos>

<groups>

<group id="l" numel="2" spinmult="l" noes="2">

<oes oesid="2" num_orb="6">

<ao aoid="2" coef="0.57735"/>

<ao aoid="3" coef="-0.348518"/>

<ao aoid="5" coef="0.738378"/>

<ao aoid="7" coef="0.57735"/>

<ao aoid="8" coef="-0.348518"/>

<ao aoid="10" coef="0.738378"/>

</oes>

<oes oesid="3" num_orb="6">

<ao aoid="2" coef="0.57735"/>

<ao aoid="3" coef="0.348518"/>

<ao aoid="5" coef="-0.738378"/>

<ao aoid="7" coef="0.57735"/>

<ao aoid="8" coef="0.348518"/>

<ao aoid="10" coef="-0.738378"/>

</oes>

</group>

<group id="2" nnmel="2" spinmult="l" noes="2">

<oes oesid="4" num_orb="l">

<ao aoid="4" coef="l"/>

</oes>

<oes oesid="5" num_orb="l">

<ao aoid="9" coef="l"/>

</oes>

</group>

<group id="3" nnmel="2" spinmult="l" noes="2">

<oes oesid="6" num_orb="4">

<ao aoid="2" coef="0.57735"/>

<ao aoid="3" coef="0.348518"/>

<ao aoid="5" coef="0.738378"/>

<ao aoid="ll" coef="0.57735"/>

</oes>

<oes oesid="7" num_orb="l">

<ao aoid="ll" coef="l"/>

</oes>

</group>

<group id="4" numel="2" spinmult="l" noes="2">

<oes oesid="8" num_orb="4">

<ao aoid="2"  coef="0.57735"/>

<ao aoid="3"  coef="-0.683263"/>

<ao aoid="5"  coef="-0.447011"/>

<ao aoid="12"  coef="0.57735"/>

</oes>

<oes oesid="9" num_orb="l">

<ao aoid="12"  coef="l"/>

</oes>

</group>

<group id="5" numel="2"  spinmult="l" noes="2">

<oes oesid="10" num_orb="4">

<ao aoid="7"  coef="0.57735"/>

<ao aoid="8"  coef="0.477641"/>

<ao aoid="10"  coef="-0.662213"/>

<ao aoid="13"  coef="0.57735"/>

</oes>

<oes oesid="ll" num_orb="l">

<ao aoid="13"  coef="l"/>

</oes>

</group>

<group id="6" nnmel="2"  spinmult="l" noes="2">

<oes oesid="12" num_orb="2">

<ao aoid="7"  coef="0.57735"/>

<ao aoid="14"  coef="0.57735"/>

</oes>

<oes oesid="13" num_orb="l">

<ao aoid="14"  coef="l"/>

</oes>

</group>

</groups>

</structure>

</molecule>

 WriteVRMLO

Как было сказано выше, формат языка VRML может служить для визуализации молекулярных данных по координатам атомов и связям в молекуле. Вывод методом WriteVRMLO происходит в стиле Balls and Sticks (шары и "палочки"). Если данные по связям отсутствуют, то выводятся только шары. Все данные записываются в файл с расширением wrl,

который затем обрабатывается VRML-браузером (VRML Browser) для создания в своем окне трехмерной модели молекулы. Полный текст метода приводится ниже:

void WriteVRML()

{

string CurrentGroupTreatment;

atom CurrentAtom;

point CurrentPoint;

node CurrentNode;

group CurrentGroup;

arc CurrentArc;

vector<cao> AtomBasis;

vector<atom*> CurrentTouches;

vector<oes*> subspace;

group* pCurrentGroup = NULL;

atom* pAtom = NULL;

element* pElement = NULL;

node* pNode = NULL;

point* pPoint = NULL;

point* pCurrentPoint = NULL;

atom* pCurrentAtom = NULL;

node* pLe;

node* pRe;

cao* pCAO;

oes* pOES;

char buffer[80];

int AtNum=0;

int NumAt=0;

int i;

double minX,minY,maxX,maxY,minZ,maxZ;

double dx,dy,dz,d,dl,d2;

double hx,hy,hz,h,cosphi,ex,cy,cz,phi,hi,h2,h3;

// Min Max search

minX=100000;

minY=100000;

maxX=-100000;

maxY=-100000;

minZ=100000;

maxZ=-100000;

double pGPRx=0.0;

double pGPRy=0.0;

double pGPRz=0.0;

for(int p=0;p<=this->Geometry.pPoints.

pGPRx=this->Geometry.pPoints[p]->R[0]; pGPRy=this->Geometry.pPoints[p]->R[1] ; pGPRz=this->Geometry.pPoints[p]->R[2]; if (pGPRx < minX) minX = pGPRx; if (pGPRy < minY) minY = pGPRy; if (pGPRz < minZ) minZ = pGPRz; if (pGPRx > maxX) maxX = pGPRx; if (pGPRy > maxY) maxY = pGPRy; if (pGPRz > maxZ) maxZ = pGPRz;

dx=(maxX-minX); dy=(maxY-minY); dz=(maxZ-minZ); dx=minX+dx/2.0; dy=minY+dy/2.0; dz=minZ+dz/2.0; for(int p=0;p<=this->Geometry.pPoints.size()-l;p++)

pGPRx=this->Geometry.pPoints[p]->R[0]; pGPRy=this->Geometry.pPoints[p]->R[1]; pGPRz=this->Geometry.pPoints[p]->R[2]; pGPRx = pGPRx - dx; pGPRy = pGPRy - dy; pGPRz = pGPRz  - dz;

// Save atoms

cout « "#VRML V2.0 utf8" « endl; for(int p=0;p<=this->Geometry.pPoints.size()-l;p++) {

sprintf (buff er, "°/of" ,this->Geometry. pPoints [p] ->R[0] ); cout « "Transform { translation " « buffer « " ";

sprintf (buffer, "%f",this->Geometry. pPoints [p]->R[l]); cout « buffer « " "; sprintf (buff er, "°/of" ,this->Geometry. pPoints [p] ->R[2] );

cout << buffer « endl;

cout « "children [ Shape { appearance Appearance { material DEF \ _DefMat Material {" « endl;

AtNum=this->Composition.pAtoms[p]->pElement->AtomicNumber; sprintf (buffer, "°/,f" ,\ periodic::MendeleevPeriodicTable[AtNum].Render.R);

cout « "diffuseColor " « buffer « " ";

sprintf (buffer, "°/,f" ,\ periodic::MendeleevPeriodicTable[AtNum].Render.G);

cout « buffer « " ";

sprintf (buff er, "°/.f" , \ periodic::MendeleevPeriodicTable[AtNum].Render.B);

cout << buffer « endl; cout « "} } geometry Sphere {" << endl; sprintf (buffer, "°/,f ",\ periodic::MendeleevPeriodicTable[AtNum].Render.Radius/10.0);

cout « "radius " « buffer « endl; cout «"}}]}"« endl; }

// Save bonds

if (MolGraph.pArcs.sizeO !=0) { for(int n=0;n<=this->MolGraph.pArcs.si

int pReId=0; int pLeId=0;

pReld = this->MolGraph.pArcs[n]->pRe->Id; pLeld = this->MolGraph.pArcs[n]->pLe->Id; hx =  (this->Geometry.pPoints[pReId]->R[0])   - \ (this->Geometry.pPoints[pLeld]->R[0]); hy =  (this->Geometry.pPoints[pReId]->R[l])   - \ (this->Geometry.pPoints[pLeld]->R[1]); hz =  (this->Geometry.pPoints[pReId]->R[2])   - \ (this->Geometry.pPoints[pLeld]->R[2]);

sprintf (buffer, "%f",this->Geometry.pPoints[pLeId]->R[0]+hx/2); cout «  "Transform { translation "  « buffer «  "  "; sprintf (buffer, "°/,f",this->Geometry. pPoints [pLeld]->R[l]+hy/2); cout  « buffer «  "   ";

sprintf (buffer, "°/,f",this->Geometry. pPoints [pLeld]->R[2]+hz/2); cout « buffer << endl; h=sqrt(hx*hx+hy*hy+hz*hz);

cosphi=hy/h;

cx=-hz;

cy=O.O;

cz=hx;

phi=-acos(cosphi);

sprintf (buffer, "°/»f" , ex);

cout « " rotation " « buffer « " ";

sprintf (buffer, "°/,f",cy);

cout « buffer « " ";

sprintf (buffer, "°/,f",cz);

cout « buffer « " ";

sprintf (buffer, "°/,f",phi);

cout « buffer << endl;

cout « "children [ Shape { appearance Appearance { material DEF\

_DefMat Material {" « endl; cout « "diffuseColor  0.5 0.5 1" « endl; cout « "} } geometry Cylinder {" « endl; cx=0.05;

sprintf (buffer, "°/,f", ex);

cout « "radius " « buffer « " height "; sprintf (buffer, "°/,f",h); cout « buffer << endl; cout «"}}]}"« endl;

// Zabalov

©Забалов Максим, 2004. Выходной файл для молекулы этилена:

#VRML V2.0 utf8

Transform { translation -0.667250 0.000000 0.000000

children [ Shape { appearance Appearance { material DEF _DefMat Material {

diffuseColor 0.500000 0.000000 0.000000

} } geometry Sphere {.

radius 0.195000

} } ] }

Transform { translation 0.667250 0.000000 0.000000

children [ Shape { appearance Appearance { material DEF _DefMat Material {

diffuseColor 0.500000 0.000000 0.000000

} } geometry Sphere {

radius 0.195000

} } ] }

Transform { translation -1.263450 0.911300 0.000000

children [ Shape { appearance Appearance { material DEF _DefMat Material {

diffuseColor 1.000000 1.000000 1.000000

} } geometry Sphere {

radius 0.120000

} } ] }

Transform { translation -1.263450 -0.911300 0.000000

children [ Shape { appearance Appearance { material DEF _DefMat Material {

diffuseColor 1.000000 1.000000 1.000000

} } geometry Sphere {

radius 0.120000

} } ] }

Transform { translation 1.263450 0.911300 0.000000

children [ Shape { appearance Appearance { material DEF _DefMat Material {

diffuseColor 1.000000 1.000000 1.000000

} } geometry Sphere {

radius 0.120000

} } ] }

Transform { translation 1.263450 -0.911300 0.000000

children [ Shape { appearance Appearance { material DEF _DefMat Material {

diffuseColor 1.000000 1.000000 1.000000

} } geometry Sphere {

radius 0.120000

} } ] }

Transform { translation 0.000000 0.000000 0.000000

rotation -0.000000 0.000000 -1.334500 -1.570796

children [ Shape { appearance Appearance { material DEF _DefMat Material { diffuseColor  0.5 0.5 1 } } geometry Cylinder { radius 0.050000 height 1.334500 } } ] } Transform { translation -0.965350 0.455650 0.000000

rotation -0.000000 0.000000 0.596200 -2.562249

children [ Shape { appearance Appearance { material DEF _DefMat Material { diffuseColor  0.5 0.5 1 } } geometry Cylinder { radius 0.050000 height 1.089001

Transform { translation -0.965350  -0.455650 0.000000

rotation -0.000000 0.000000  0.596200  -0.579343

children   [ Shape { appearance Appearance { material DEF _DefMat Material { diffuseColor      0.5 0.5  1 } } geometry Cylinder { radius 0.050000 height  1.089001 } } ]   } Transform { translation 0.965350 0.455650  0.000000

rotation -0.000000 0.000000  -0.596200  -2.562249

children   [ Shape { appearance Appearance { material DEF _DefMat Material { diffuseColor      0.5 0.5  1 } } geometry Cylinder { radius 0.050000 height  1.089001 } } ]   } Transform { translation 0.965350  -0.455650 0.000000

rotation -0.000000 0.000000  -0.596200  -0.579343

children   [ Shape { appearance Appearance { material DEF _DefMat Material { diffuseColor      0.5 0.5  1 } } geometry Cylinder { radius 0.050000 height  1.089001