CS4 (Gumbo) Molfile Molecule Viewer Sem#4

Intro

This is seminar #4, of a series of free seminars given this semester at NKU on Papervision3D and CS4. It demonstrates how to create a molfile molecule viewer in CS4 (Gumbo). Click the image below to see a demo.

CS4 Molecule for a Molfile

CS4 Molecule from a Molfile

Source

Demo

YouTube

Discussion

This is now my second version of a 3D molecule viewer. The first version was written in Papervision3D and was about 1400 lines of code and required that you rewrite the molfile into xml, and didn’t show bonds. This version is in CS4 (Gumbo or Flex 4) and is only about 350 lines of code, has bonds (single, double, triple, aromatic) and parses the molfile directly.

It took me a day to write this application(from 4 to 11), and that was with breaks: playing with the kids, gym, Shakespeare club, an ice cream float party, and several episodes of Hawaii-5-0 and Enterprise. Yeah, this is the life!

Molfile Parser

Parsing the Molefile was much easier than I thought it was going to be. Here is how you do it:

  • You just bring the molfile into Flex 4 using http services command (just as you would an XML file but with no e4x format)

<mx:HTTPService id=”molService” url=”assets/0420.mol”
result=”initMoleFile(event)” />

  • Then you convert it to a string, take out the special characters, split the contents, stuff it into an array, and remove all empty array elements.

// Convert to string
myString=molService.lastResult.toString();

//Remove special characters
myString = myString.split(“\n”).join(” “);
myString = myString.split(“\r”).join(” “);

//Stuff into an Array
myArray = myString.split(/ /);

//Filter out bland array elements
myArray = myArray.filter(filterMe);
function filterMe(element:String, index:int, array:Array):Boolean{
return (element != “” ); }

  • After you’ve stuffed your molefile into an array, you need to know where to go in that array so you can start counting off the data elements.Where do you go? Go to the version number of the molfile. So run a forEach and grab it’s index value.

myArray.forEach(myStart);

function myStart(element:String, index:int, array:Array):void{
if(element == “V2000″||element == “V3000″){
myStartVert=index;}

The index value of the version number is the heart of your molfile parser. Above we allow for versions V2000 or V3000. This index value will take you to any piece of data that you need in order to display your molecule. From this point on, its just a big counting game, everything is referenced to your version index value.

Atom File

To display your model you need an atom shape that can change size, color, and fill based upon the atom type.

The atom color, type, and radius were previously handled in an earlier version of the molecule viewer, created in Papervision3D (video, source).

And the atom shape and fill were handled in a previous post in this blog on 3D Lines in CS4 using drawPath.

By combining these two programs you can come up with a suitable atom. To do this:

  • Place the atom switch case from the PV3D Viewer into the Ball class created in the 3D Lines post, then change the ball class to Atom along with its constructor and class names.
  • In the switch case change the myColor value from grabbing a jpg to equaling a color value for all possible atoms:

case “H”:
//myColor = “colors/white.jpg”;
myColor = 0xffffff;
radius = 25;

  • In the Constructor function change it to receive only one parameter type, which is the letter of your atom: H, C, O…

public function init(type:String):void{…

  • Finally, change the fill method to gradient fill so your atoms looks cool.

graphics.beginGradientFill(myType, [myColor, 0x000022],[1,1], [1, 40]);

Now that your atom subclass is completed, it’s time to start building molecules.

Creating Molecules and Bonds

There are two parts to creating molecules: placing atoms in 3D, and creating their bonds. The first part of a molfile gives you the atom position values, and the second part give the bond relationships (which atoms are connected to which) and types.

Placing Atoms

Essentially all you have to do is replace the random placement of circles from the post on drawPaths to the atomic positions found in your molfile.

atom.xpos = myArray[myStartVert+1 +j*16] * myScale – offsetx;
atom.ypos = myArray[myStartVert+2 +j*16] * myScale – offsety;
atom.zpos = myArray[myStartVert+3 +j*16] * myScale – offsetz;

myHolder.addChild(atom);

You get to those positions by counting 1 position forward for x, 2 for y, and 3 for z, from the version number index, as shown above.

The offset is just an average of the molecular positions and gives you the ability to spin your molecule around its center. Everything else pretty much follows what was done in the drawPaths post.

Creating Bonds

Creating bonds is easy as well, with one big conceptual change from the drawPaths post. Double processing is eliminated by just duplicating the atom and placing it into a marks array. The lines follow the duplicated atom in the marks array and the other atom which exist in the atoms array are used for sorting.

atoms.push(atom);
marks.push(atom);

The big problem (in creating bonds) was figuring out how to create double, triple, and aromatic bonds. And it turns out to be just a big counting game, coupled with offsetting lines. It starts with figuring out what type of bond you have and using that information in a switch case.

The information for what type of bond you have is carried in the second part of your molfile which starts at

startBondArray=myStartVert+myNumAtoms*16+1

Adding 2 to this number gives you the bond type location (OK once again it’s a big counting game – check out the molfile description under the read more button to see the molfile structure – I know it well).

So, each time you create a double, triple, or aromatic bond you have to keep track of where all the data is in your array. This was accomplished by adding the following counting tracker to your command and data arrays:

commands[2*k+2*dB+4*tB+2*aB]

mydata[4*k+4*dB+8*tB+4*aB]

which are needed to for the drawPath command shown below

myHolder.graphics.drawPath(commands, mydata);

The variables dB, tB, and aB are iterated (by one) each time you create a double, triple, or aromatic bond respectively. These values are then zeroed after each molecular drawing iteration and the process is restarted on each onEnterFrame tick.

Creating the bond offsets was not very sophisticated as shown below:

mydata[4*k+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x-bond2Sep;
mydata[4*k+1+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y-bond2Sep;

mydata[4*k+4+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x+bond2Sep;
mydata[4*k+5+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y+bond2Sep;

You just subtract or add an offset value (bond2Sep) as shown above for the double bond case.

Which Way Should We Go!

In going through this, I found some molfiles on the web that were not well formed and would not work with this parser. That’s always the problem with parsers. The errors were easy to fix and many times just meant adding or subtracting an extra zero. But your end user can’t do that…

I really think XML is the best way to go. That way you can target nodes and forget about counting. You can go even a step farther with XML and include chemical bonding information which would enable you to run chemical simulations. Wouldn’t that be cool!

To see all the code, download it from the source link above or click the button below:

Wrapper Code

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml&#8221;
layout=”absolute” creationComplete=”molService.send()” backgroundGradientAlphas=”[1.0, 1.0]” backgroundGradientColors=”[#A7B1FD, #7EFE87]“>
<mx:HTTPService id=”molService” url=”assets/0420.mol”
result=”initMoleFile(event)” />

<mx:Script>
<![CDATA[

import mx.rpc.events.ResultEvent;

//import flash.display.*;
//import flash.events.*;
//import flash.geom.*;

import __AS3__.vec.Vector;

import flash.display.GraphicsPathCommand;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display.Stage;
import flash.events.Event;
import objects.*;

private var myString:String;

private var myArray:Array;
private var myStartVert:int;
private var myNumAtoms:int;
private var myNumBonds:int;
private var startBondArray:int;

private var myScale:Number=50;
private var offsetx:Number=0;
private var offsety:Number=0;
private var offsetz:Number=0;

//Bond Parameters
private var dB:int=0;
private var tB:int=0;
private var aB:int=0;

//3D Parameters
private var atoms:Array = new Array();
private var marks:Array = new Array();

private var fl:Number=250;

private var commands:Vector.<int> = new Vector.<int>();
private var mydata:Vector.<Number> = new Vector.<Number>();

private var myHolder:Sprite = new Sprite();

//initiate molfile

private function initMoleFile(event:ResultEvent):void{

myString=molService.lastResult.toString();

myString = myString.split(“\n”).join(” “);
myString = myString.split(“\r”).join(” “);

myArray = myString.split(/ /);

myArray = myArray.filter(filterMe);

//output.text+=myArray.toString();

function filterMe(element:String, index:int, array:Array):Boolean{

return (element != “” );

}

myArray.forEach(myStart);

function myStart(element:String, index:int, array:Array):void{

if(element == “V2000″||element == “V3000″){

myStartVert=index;

//output_txt.text+=myArray[index];

}}

//Get number of atoms and bonds

myNumAtoms=myArray[myStartVert-10];
myNumBonds=myArray[myStartVert-9];
startBondArray=myStartVert+myNumAtoms*16+1;

//output_txt.text+=myStartVert+” myindex “+myNumAtoms+”,”+myNumBonds;

buildAtoms();

//buildBonds();

}

private function buildAtoms():void{

for(var i:int = 0; i < myNumAtoms; i++)
{

offsetx += myArray[myStartVert+1 +i*16] * myScale;
offsety += myArray[myStartVert+2 +i*16] * myScale;
offsetz += myArray[myStartVert+3 +i*16] * myScale;

}

var divby:Number=myNumAtoms;

offsetx=offsetx/divby;
offsety=offsety/divby;
offsetz=offsetz/divby;

for(var j:int = 0; j < myNumAtoms; j++)
{

var atom:Atom = new Atom(myArray[myStartVert+4 +j*16]);
//var mark:MarkCS4 = new MarkCS4(0, 0);

//output_txt.text += myArray[myStartVert+4 +j*16];

atoms.push(atom);
marks.push(atom);

atom.xpos = myArray[myStartVert+1 +j*16] * myScale – offsetx;
atom.ypos = myArray[myStartVert+2 +j*16] * myScale – offsety;
atom.zpos = myArray[myStartVert+3 +j*16] * myScale – offsetz;

myHolder.addChild(atom);

}

lv3d.rawChildren.addChild(myHolder);

myHolder.x=400;
myHolder.y=300;
myHolder.z=10;

addEventListener(Event.ENTER_FRAME, onEnterFrame);

}

private function onEnterFrame(event:Event):void
{
sortZ();

var angleX:Number = (mouseY-myHolder.y ) * .0007;
var angleY:Number = (mouseX-myHolder.x) * .0007;
for(var i:uint = 0; i < myNumAtoms; i++)
{
var atom:Atom = atoms[i];
rotateX(atom, angleX);
rotateY(atom, angleY);

doPerspective(atom);

}

for(var k:int = 0; k < myNumBonds; k++)
{
//output.text+=myArray[startBondArray+7*k+2];

var intrSwtich:int=myArray[startBondArray+7*k+2]

switch(intrSwtich)
{
case 1:
commands[2*k+2*dB+4*tB+2*aB] = GraphicsPathCommand.MOVE_TO;
mydata[4*k+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x;
mydata[4*k+1+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y;

commands[2*k+1+2*dB+4*tB+2*aB] = GraphicsPathCommand.LINE_TO;
mydata[4*k+2+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].x;
mydata[4*k+3+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].y;
break;
case 2:

var bond2Sep:int=2;

commands[2*k+2*dB+4*tB+2*aB] = GraphicsPathCommand.MOVE_TO;
mydata[4*k+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x-bond2Sep;
mydata[4*k+1+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y-bond2Sep;

commands[2*k+1+2*dB+4*tB+2*aB] = GraphicsPathCommand.LINE_TO;
mydata[4*k+2+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].x-bond2Sep;
mydata[4*k+3+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].y-bond2Sep;

commands[2*k+2+2*dB+4*tB+2*aB] = GraphicsPathCommand.MOVE_TO;
mydata[4*k+4+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x+bond2Sep;
mydata[4*k+5+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y+bond2Sep;

commands[2*k+3+2*dB+4*tB+2*aB] = GraphicsPathCommand.LINE_TO;
mydata[4*k+6+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].x+bond2Sep;
mydata[4*k+7+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].y+bond2Sep;

dB++;

break;
case 3:
var bond3Sep:int=3;

commands[2*k+2*dB+4*tB+2*aB] = GraphicsPathCommand.MOVE_TO;
mydata[4*k+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x-bond3Sep;
mydata[4*k+1+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y-bond3Sep;

commands[2*k+1+2*dB+4*tB+2*aB] = GraphicsPathCommand.LINE_TO;
mydata[4*k+2+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].x-bond3Sep;
mydata[4*k+3+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].y-bond3Sep;

commands[2*k+2*dB+4*tB+2*aB] = GraphicsPathCommand.MOVE_TO;
mydata[4*k+4+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x;
mydata[4*k+5+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y;

commands[2*k+1+2*dB+4*tB+2*aB] = GraphicsPathCommand.LINE_TO;
mydata[4*k+6+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].x;
mydata[4*k+7+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].y;

commands[2*k+2*dB+4*tB+2*aB] = GraphicsPathCommand.MOVE_TO;
mydata[4*k+8+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x+bond3Sep;
mydata[4*k+9+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y+bond3Sep;

commands[2*k+1+2*dB+4*tB+2*aB] = GraphicsPathCommand.LINE_TO;
mydata[4*k+10+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].x+bond3Sep;
mydata[4*k+11+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].y+bond3Sep;

tB++;

break;
case 4:
var bondArSep:int=2;

commands[2*k+2*dB+4*tB+2*aB] = GraphicsPathCommand.MOVE_TO;
mydata[4*k+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x-bondArSep;
mydata[4*k+1+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y-bondArSep;

commands[2*k+1+2*dB+4*tB+2*aB] = GraphicsPathCommand.LINE_TO;
mydata[4*k+2+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].x-bondArSep;
mydata[4*k+3+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].y-bondArSep;

commands[2*k+2*dB+4*tB+2*aB] = GraphicsPathCommand.MOVE_TO;
mydata[4*k+4+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x+bondArSep;
mydata[4*k+5+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y+bondArSep;

commands[2*k+1+2*dB+4*tB+2*aB] = GraphicsPathCommand.LINE_TO;
mydata[4*k+6+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].x+bondArSep;
mydata[4*k+7+4*dB+8*tB+4*aB]=marks[myArray[startBondArray+7*k+1]-1].y+bondArSep;

aB++;

break;

default:
//Not in my arsenal
break;
}

}

myHolder.graphics.clear();

dB=0;
tB=0;
aB=0;

myHolder.graphics.lineStyle(0);
myHolder.graphics.drawPath(commands, mydata);

}

private function rotateX(atom:Atom, angleX:Number):void
{
var cosX:Number = Math.cos(angleX);
var sinX:Number = Math.sin(angleX);

var y1:Number = atom.ypos * cosX – atom.zpos * sinX;
var z1:Number = atom.zpos * cosX + atom.ypos * sinX;

atom.ypos = y1;
atom.zpos = z1;

}
private function rotateY(atom:Atom, angleY:Number):void
{
var cosY:Number = Math.cos(angleY);
var sinY:Number = Math.sin(angleY);

var x1:Number = atom.xpos * cosY – atom.zpos * sinY;
var z1:Number = atom.zpos * cosY + atom.xpos * sinY;

atom.xpos = x1;
atom.zpos = z1;
}

private function doPerspective(atom:Atom):void
{

if(atom.zpos > -fl)
{

var scale:Number = fl / (fl + atom.zpos);

atom.scaleX = atom.scaleY = scale;
atom.x = atom.xpos*scale;
atom.y = atom.ypos*scale;

}
else
{
atom.visible = false;
}

}

private function sortZ():void
{
atoms.sortOn(“zpos”, Array.NUMERIC | Array.DESCENDING );
for(var i:uint = 0; i < myNumAtoms; i++)
{
var atom:Atom = atoms[i];
myHolder.addChild(atom as Sprite);
}

}

//Search me, O God, and know my heart: try me, and know my thoughts: And see if there be any wicked way in me, and lead me in the way everlasting.
]]>
</mx:Script>
<mx:Canvas x=”10″ y=”10″ width=”31″ height=”42″ id=”lv3d”>
</mx:Canvas>
</mx:Application>

Atom Code

package objects{
import __AS3__.vec.Vector;

import flash.display.GraphicsPathCommand;
import flash.display.Sprite;
import flash.display.GradientType;
import flash.geom.Matrix;

public class Atom extends Sprite {

private var commands:Vector.<int> = new Vector.<int>();
private var data:Vector.<Number> = new Vector.<Number>();

private var type:String;
private var radius:Number;
private var myColor:Number;

public var xpos:Number = 0;
public var ypos:Number = 0;
public var zpos:Number = 0;
public var vx:Number = 0;
public var vy:Number = 0;
public var vz:Number = 0;
public var mass:Number = 1;

private var myType:String = GradientType.RADIAL;
private var alphas:Array = [1, 1];
private var ratios:Array = [1, 100];

private var matrix:Matrix = new Matrix();

//var colors:Array = [0x00FF00, 0x000088];

public function Atom(type:String) {
this.type = type;
init(type);
}
public function init(type:String):void {

matrix.createGradientBox(200, 40, 0, 0, 0);

switch(type)
{
case “H”:
//myColor = “colors/white.jpg”;
myColor = 0xffffff;
radius = 25;

break;
case “C”:
//myColor = “colors/grey.jpg”;
myColor = 0xbfbfbf;
radius = 70;
break;
case “O”:
//myColor = “colors/red.jpg”;
myColor = 0xe60501;
radius = 60;
break;
case “N”:
//myColor = “colors/lightblue.jpg”;
myColor = 0x8F8FFF;
radius = 65;
break;
case “S”:
//myColor = “colors/sulphuryellow.jpg”;
myColor = 0xFCC932;
radius = 100;
break;
case “B”:
//myColor = “colors/green.jpg”;
myColor = 0x08FB01;
radius = 85;
break;
case “Cl”:
//myColor = “colors/green.jpg”;
myColor = 0x08FB01;
radius = 100;
break;

case “P”:
//myColor = “colors/orange.jpg”;
myColor = 0xffffff;
radius = 100;
break;
case “Fe”:
//myColor = “colors/orange.jpg”;
myColor = 0xFA9D00;
radius = 140;
break;
case “Ba”:
//myColor = “colors/orange.jpg”;
myColor = 0xFA9D00;
radius = 215;
break;

case “Na”:
//myColor = “colors/blue.jpg”;
myColor = 0x0100FE;
radius = 215;
break;

case “Mg”:
//myColor = “colors/forestgreen.jpg”;
myColor = 0x258A22;
radius = 215;
break;

case “Zn”:
//myColor = “colors/brown.jpg”;
myColor = 0xA22C2A;
radius = 135;
break;
case “Cu”:
//myColor = “colors/brown.jpg”;
myColor = 0xA22C2A;
radius = 135;
break;
case “Ni”:
//myColor = “colors/brown.jpg”;
myColor = 0xA22C2A;
radius = 135;
break;
case “Br”:
//myColor = “colors/brown.jpg”;
myColor = 0xA22C2A;
radius = 115;
break;

case “Ca”:
//myColor = “colors/darkgrey.jpg”;
myColor = 0×818090;
radius = 180;
break;
case “Mn”:
//myColor = “colors/darkgrey.jpg”;
myColor = 0×818090;
radius = 140;
break;
case “Al”:
//myColor = “colors/darkgrey.jpg”;
myColor = 0×818090;
radius = 125;
break;
case “Ti”:
//myColor = “colors/darkgrey.jpg”;
myColor = 0×818090;
radius = 140;
break;
case “Cr”:
//myColor = “colors/darkgrey.jpg”;
myColor = 0×818090;
radius = 140;
break;
case “Ag”:
//myColor = “colors/darkgrey.jpg”;
myColor = 0×818090;
radius = 160;
break;

case “F”:
//myColor = “colors/goldenrod.jpg”;
myColor = 0xD7A721;
radius = 50;
break;
case “Si”:
//myColor = “colors/goldenrod.jpg”;
myColor = 0xD7A721;
radius = 110;
break;
case “Au”:
//myColor = “colors/goldenrod.jpg”;
myColor = 0xD7A721;
radius = 135;
break;

case “I”:
//myColor = “colors/purple.jpg”;
myColor = 0x9D22EF;
radius = 140;
break;

case “Li”:
//myColor = “colors/firebrick.jpg”;
myColor = 0xAC2522;
radius = 145;
break;

case “He”:
//myColor = “colors/pink.jpg”;
myColor = 0xFDC1CB;
radius = 28;
break;

default:
//myColor = “colors/deeppink.jpg”;
myColor = 0xF71994;
radius = 120;
break;
}

radius=radius/5;

commands.push(GraphicsPathCommand.MOVE_TO);
data.push(-radius/1.9, radius/1.9);

data.push(0, radius);
data.push(radius/1.9, radius/1.9);

data.push(radius, 0);
data.push(radius/1.9, -radius/1.9);

data.push(0, -radius);
data.push(-radius/1.9, -radius/1.9);

data.push(-radius, 0);
data.push(-radius/1.9, radius/1.9);

commands.push(GraphicsPathCommand.CURVE_TO);
commands.push(GraphicsPathCommand.CURVE_TO);
commands.push(GraphicsPathCommand.CURVE_TO);
commands.push(GraphicsPathCommand.CURVE_TO);

//graphics.lineStyle(0);
//graphics.beginFill(myColor);
this.graphics.beginGradientFill(myType, [myColor, 0x000022],[1,1], [1, 40]);
graphics.drawPath(commands, data);

//Delight thyself also in the LORD; and he shall give thee the desires of thine heart.

}
}
}

Sample molfile (Reference Material)

A molfile for 2-butanone

looks like:

ChemWindow
  5  4  0  0  0  0  0  0  0  0  1 V2000
    2.2994    2.0277    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
    3.2617    0.3611    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    2.2994    0.9166    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    1.3372    0.3611    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.3750    0.9166    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
  3  1  2  0
  3  2  1  0
  4  3  1  0
  5  4  1  0
M  END
benzene
 ACD/Labs0812062058

  6  6  0  0  0  0  0  0  0  0  1 V2000
    1.9050   -0.7932    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    1.9050   -2.1232    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.7531   -0.1282    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.7531   -2.7882    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
   -0.3987   -0.7932    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
   -0.3987   -2.1232    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
  2  1  1  0  0  0  0
  3  1  2  0  0  0  0
  4  2  2  0  0  0  0
  5  3  1  0  0  0  0
  6  4  1  0  0  0  0
  6  5  2  0  0  0  0
 M  END
 $$$$

1: header
2: comment
3: general information: 6 atoms, 6 bonds, ..., V2000 standard
4-9: x, y, z, element, extra information
10-15: bonding information (each bond listed): 1st atom, 2nd atom, type, extra information

The first 2 lines are unimportant for our purposes. The next 5 lines are the atom table, one line per atom. The first 4 columns are the atom’s x, y and z coordinates and atom type. Because this was generated from a 2D drawing program (ChemWindow), all z coordinates are zero.

The next 4 lines comprise the bond table, 1 bond per line. The first 2 columns list which 2 atoms are connected by the bond. The third column indicates whether the bond is single (1), double (2), triple (3) or aromatic (4).

Details of the MolFile format

First line of table is the “Counts Line”:

aaa bbb lll fff ccc sss xxx rrr ppp jjj mmm vvvvv
aaa = number of atoms
bbb = number of bonds
lll = number of atom lists
fff = obsolete
ccc = chiral flag: 0=not chiral, 1=chiral
sss = number of stext entries
xxx = obsolete
rrr = obsolete
ppp = obsolete
jjj = obsolete
mmm = number of lines of additional properties,including the M END line.
No longer supported, the default is set to 999.
vvvvvv is the version number - this software accepts V2000 or V3000

The next block of lines is the Atom Block:

xx.xx yy.yy zz.zz aa dd cc ss hh bb vv HH rr ii mm nn ee
x = x atom coordinate
y = y atom coordinate
z = z atom coordinate
a = atom symbol ( this software supports strings less than 10 in length
d = mass difference
c = charge
s = atom stereo parity - 0=not stereo, 1=odd, 2=even, 3=either
h = hydrogen count
b = stereo care box
v = valence
H = H0 designator - 0=not specified, 1=no H atoms allowed
r = Not Used
i = Not Used
m = atom-atom mapping number
n = inversion/retention flag
e = exact change flag - 0=property not applied,
1=change on atom must be exactly as shown

The next block of lines is the Bond Block:

11 22 tt ss xx rr cc
1 = First atom number
2 = Second atom number
t = Bond type - 1=Single, 2=Double, 3=Triple, 4=Aromatic
s = Bond Stereo - 0=Not Stereo, 1=Up, 4=Either, 6=Down
x = Not Used
r = Bond Topology - 0=Either, 1=Ring, 2=Chain
c = reacting center status
About these ads

One Response to CS4 (Gumbo) Molfile Molecule Viewer Sem#4

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: