1 /**********************************************************************
2 Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
3 Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
4 Some portions Copyright (C) 2004 by Chris Morley
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 ***********************************************************************/
15 
16 /* contributed by Walter Scott (wscott@igc.phys.chem.ethz.ch)
17 
18    (Actually the routine was copied from write_xyz and and write_pdb and
19    then modified...)
20 
21    This is a small routine to write a GROMOS96 formatted
22    "position coordinate block" (POSITION) or a
23    "reduced position coordinate block" (POSITIONRED)
24    The former has name information (atom and residue names) while
25    the latter only has coordinates.
26    This version does not support the writing of binary
27    GROMOS files.
28 
29    NOTE 1: the actual formats used in writing out the coordinates
30    do not matter, as GROMOS96 uses free formatted reads.
31    Each line may not be longer than 80 characters.
32 
33    (Note, however, in the POSITION block, the first 24 (twenty four)
34    character on each line are ignored when the line is read in by GROMOS)
35    Comments lines, beginning with hash (#) may occur within a block and are
36    used as delimiters for easier reading.
37 
38    NOTE 2: Many programs specify the units of the coordinates (e.g. Angstrom).
39    GROMOS96 does NOT, as all physical constants, from K_B to EPS are
40    NOT hardwired into the code, but specified by the user.
41    This allows some (mostly Americans) to use GROMOS96 in KCal and
42    Angstrom and the rest of us to use kJoule and nm.
43    It also makes it easy to use reduced units.
44 
45    We get around this by supplying a routine, wr_sco_gr96, which
46    will scale the coordinates by a factor before writing.
47    This routine is then called with the factor set to 1.0 in
48    write_gr96A, or to 0.1 in write_gr96N depending on the users choice.
49    Thus, we always assume that we have read coordinates in Angstrom.
50 	 *** But now handled by a command line option in new framework.
51 */
52 
53 #include <openbabel/babelconfig.h>
54 #include <openbabel/obmolecformat.h>
55 #include <openbabel/mol.h>
56 #include <openbabel/atom.h>
57 #include <openbabel/elements.h>
58 
59 
60 using namespace std;
61 namespace OpenBabel
62 {
63 
64   class GROMOS96Format : public OBMoleculeFormat
65   {
66   public:
67     //Register this format type ID
GROMOS96Format()68     GROMOS96Format()
69     {
70       OBConversion::RegisterFormat("gr96",this);
71     }
72 
Description()73     virtual const char* Description() //required
74     {
75       return
76         "GROMOS96 format\n"
77         "Write Options e.g. -xn\n"
78         " n output nm (not Angstroms)\n";
79     };
80 
SpecificationURL()81     virtual const char* SpecificationURL()
82     {
83       return "http://manual.gromacs.org/documentation/current/reference-manual/file-formats.html#g96";
84     }
85 
86     //Flags() can return be any the following combined by | or be omitted if none apply
87     // NOTREADABLE  READONEONLY  NOTWRITABLE  WRITEONEONLY
Flags()88     virtual unsigned int Flags()
89     {
90       return NOTREADABLE | WRITEONEONLY;
91     };
92 
93     ////////////////////////////////////////////////////
94     /// The "API" interface functions
95     virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
96 
97   };
98 
99   //Make an instance of the format class
100   GROMOS96Format theGROMOS96Format;
101 
102   ////////////////////////////////////////////////////////////////
103 
WriteMolecule(OBBase * pOb,OBConversion * pConv)104   bool GROMOS96Format::WriteMolecule(OBBase* pOb, OBConversion* pConv)
105   {
106     OBMol* pmol = dynamic_cast<OBMol*>(pOb);
107     if (pmol == nullptr)
108       return false;
109 
110     //Define some references so we can use the old parameter names
111     ostream &ofs = *pConv->GetOutStream();
112     OBMol &mol = *pmol;
113     double fac = pConv->IsOption("n") ? 0.1 : 1.0; //new framework
114 
115     char type_name[16];
116     char res_name[16];
117     char buffer[BUFF_SIZE];
118     string res_num;
119 
120     snprintf(buffer, BUFF_SIZE, "#GENERATED BY OPEN BABEL %s\n",BABEL_VERSION);
121     ofs << buffer;
122 
123     /* GROMOS wants a TITLE block, so let's write one*/
124     ofs << "TITLE\n" << mol.GetTitle() << "\nEND\n";
125     ofs << "POSITION\n";
126 
127     OBAtom *atom;
128     OBResidue *res;
129     vector<OBAtom*>::iterator i;
130 
131     for(atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
132       {
133         if ( (res = atom->GetResidue()) )
134           {
135             // 16 = sizeof(res_name) and sizeof(type_name)
136             strncpy(res_name,(char*)res->GetName().c_str(), 16);
137             res_name[15] = '\0';
138             strncpy(type_name,(char*)res->GetAtomID(atom).c_str(), 16);
139             type_name[15] = '\0';
140             res_num = res->GetNumString();
141           }
142         else
143           {
144             strncpy(type_name,OBElements::GetSymbol(atom->GetAtomicNum()), 16);
145             strcpy(res_name,"UNK");
146             res_num = "1";
147           }
148 
149         snprintf(buffer, BUFF_SIZE, "%5s %5s %5s %6d %15.5f %15.5f %15.5f\n",
150                 res_num.c_str(),res_name,type_name,atom->GetIdx(),
151                 atom->x()*fac,atom->y()*fac,atom->z()*fac);
152         ofs << buffer;
153 
154         if (!(atom->GetIdx()%10))
155           {
156             snprintf(buffer, BUFF_SIZE, "# %d\n",atom->GetIdx());
157             ofs << buffer;
158           }
159       }
160 
161     ofs << "END\n";
162 
163     return(true);
164   }
165 
166 } //namespace OpenBabel
167