summaryrefslogtreecommitdiff
path: root/mmdb2
diff options
context:
space:
mode:
authorPicca Frédéric-Emmanuel <picca@debian.org>2014-09-10 21:39:50 +0200
committerPicca Frédéric-Emmanuel <picca@debian.org>2014-09-10 21:39:50 +0200
commitf3af8fbe7a5ae3222c781b26bad4c548b6166e65 (patch)
treedcb6fe70a09b76399814c43c8814a97c7d290a86 /mmdb2
parent54c5247855a4da37b72d54b7c32e21d7a57daea3 (diff)
Imported Upstream version 2.0.1
Diffstat (limited to 'mmdb2')
-rw-r--r--mmdb2/hybrid_36.cpp320
-rw-r--r--mmdb2/hybrid_36.h21
-rw-r--r--mmdb2/mmdb_atom.cpp3486
-rw-r--r--mmdb2/mmdb_atom.h732
-rw-r--r--mmdb2/mmdb_bondmngr.cpp121
-rw-r--r--mmdb2/mmdb_bondmngr.h73
-rw-r--r--mmdb2/mmdb_chain.cpp2575
-rw-r--r--mmdb2/mmdb_chain.h662
-rw-r--r--mmdb2/mmdb_cifdefs.cpp369
-rw-r--r--mmdb2/mmdb_cifdefs.h329
-rw-r--r--mmdb2/mmdb_coormngr.cpp4347
-rw-r--r--mmdb2/mmdb_coormngr.h959
-rw-r--r--mmdb2/mmdb_cryst.cpp2312
-rw-r--r--mmdb2/mmdb_cryst.h458
-rw-r--r--mmdb2/mmdb_defs.h271
-rw-r--r--mmdb2/mmdb_ficif.cpp519
-rw-r--r--mmdb2/mmdb_ficif.h287
-rw-r--r--mmdb2/mmdb_io_file.cpp1873
-rw-r--r--mmdb2/mmdb_io_file.h301
-rw-r--r--mmdb2/mmdb_io_stream.cpp112
-rw-r--r--mmdb2/mmdb_io_stream.h193
-rw-r--r--mmdb2/mmdb_machine_.cpp155
-rw-r--r--mmdb2/mmdb_machine_.h477
-rw-r--r--mmdb2/mmdb_manager.cpp389
-rw-r--r--mmdb2/mmdb_manager.h124
-rw-r--r--mmdb2/mmdb_mask.cpp240
-rw-r--r--mmdb2/mmdb_mask.h95
-rw-r--r--mmdb2/mmdb_math_.cpp203
-rw-r--r--mmdb2/mmdb_math_.h77
-rw-r--r--mmdb2/mmdb_math_align.cpp1226
-rw-r--r--mmdb2/mmdb_math_align.h195
-rw-r--r--mmdb2/mmdb_math_bfgsmin.cpp938
-rw-r--r--mmdb2/mmdb_math_bfgsmin.h260
-rwxr-xr-xmmdb2/mmdb_math_fft.cpp338
-rwxr-xr-xmmdb2/mmdb_math_fft.h93
-rw-r--r--mmdb2/mmdb_math_graph.cpp2461
-rw-r--r--mmdb2/mmdb_math_graph.h494
-rw-r--r--mmdb2/mmdb_math_linalg.cpp990
-rw-r--r--mmdb2/mmdb_math_linalg.h236
-rw-r--r--mmdb2/mmdb_math_rand.cpp241
-rw-r--r--mmdb2/mmdb_math_rand.h80
-rw-r--r--mmdb2/mmdb_mattype.cpp2087
-rw-r--r--mmdb2/mmdb_mattype.h652
-rw-r--r--mmdb2/mmdb_mmcif_.cpp3666
-rw-r--r--mmdb2/mmdb_mmcif_.h2146
-rw-r--r--mmdb2/mmdb_model.cpp5332
-rw-r--r--mmdb2/mmdb_model.h1073
-rw-r--r--mmdb2/mmdb_root.cpp3054
-rw-r--r--mmdb2/mmdb_root.h639
-rw-r--r--mmdb2/mmdb_rwbrook.cpp3082
-rw-r--r--mmdb2/mmdb_rwbrook.h1600
-rw-r--r--mmdb2/mmdb_selmngr.cpp3421
-rw-r--r--mmdb2/mmdb_selmngr.h634
-rwxr-xr-xmmdb2/mmdb_seqsuperpose.cpp366
-rwxr-xr-xmmdb2/mmdb_seqsuperpose.h134
-rw-r--r--mmdb2/mmdb_symop.cpp1001
-rw-r--r--mmdb2/mmdb_symop.h168
-rw-r--r--mmdb2/mmdb_tables.cpp748
-rw-r--r--mmdb2/mmdb_tables.h127
-rw-r--r--mmdb2/mmdb_title.cpp2662
-rw-r--r--mmdb2/mmdb_title.h696
-rw-r--r--mmdb2/mmdb_uddata.cpp534
-rw-r--r--mmdb2/mmdb_uddata.h154
-rw-r--r--mmdb2/mmdb_utils.cpp1994
-rw-r--r--mmdb2/mmdb_utils.h633
-rw-r--r--mmdb2/mmdb_xml_.cpp986
-rw-r--r--mmdb2/mmdb_xml_.h162
67 files changed, 67383 insertions, 0 deletions
diff --git a/mmdb2/hybrid_36.cpp b/mmdb2/hybrid_36.cpp
new file mode 100644
index 0000000..243f660
--- /dev/null
+++ b/mmdb2/hybrid_36.cpp
@@ -0,0 +1,320 @@
+
+//
+// This is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+
+/*! C port of the hy36encode() and hy36decode() functions in the
+ hybrid_36.py Python prototype/reference implementation.
+ See the Python script for more information.
+
+ This file has no external dependencies, NOT even standard C headers.
+ Optionally, use hybrid_36_c.h, or simply copy the declarations
+ into your code.
+
+ This file is unrestricted Open Source (cctbx.sf.net).
+ Please send corrections and enhancements to cctbx@cci.lbl.gov .
+
+ See also: http://cci.lbl.gov/hybrid_36/
+
+ Ralf W. Grosse-Kunstleve, Feb 2007.
+ */
+
+/* The following #include may be commented out.
+ It is here only to enforce consistency of the declarations
+ and the definitions.
+ */
+#ifndef IOTBX_PDB_HYBRID_36_C_H
+#include "hybrid_36.h"
+#endif
+
+/* All static functions below are implementation details
+ (and not accessible from other translation units).
+ */
+
+static
+const char*
+digits_upper() { return "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; }
+
+static
+const char*
+digits_lower() { return "0123456789abcdefghijklmnopqrstuvwxyz"; }
+
+static
+const char*
+value_out_of_range() { return "value out of range."; }
+
+static
+const char* invalid_number_literal() { return "invalid number literal."; }
+
+static
+const char* unsupported_width() { return "unsupported width."; }
+
+static
+void
+fill_with_stars(unsigned width, char* result)
+{
+ while (width) {
+ *result++ = '*';
+ width--;
+ }
+ *result = '\0';
+}
+
+static
+void
+encode_pure(
+ const char* digits,
+ unsigned digits_size,
+ unsigned width,
+ int value,
+ char* result)
+{
+ char buf[16];
+ int rest;
+ unsigned i, j;
+ i = 0;
+ j = 0;
+ if (value < 0) {
+ j = 1;
+ value = -value;
+ }
+ while (1) {
+ rest = value / digits_size;
+ buf[i++] = digits[value - rest * digits_size];
+ if (rest == 0) break;
+ value = rest;
+ }
+ if (j) buf[i++] = '-';
+ for(j=i;j<width;j++) *result++ = ' ';
+ while (i != 0) *result++ = buf[--i];
+ *result = '\0';
+}
+
+static
+const char*
+decode_pure(
+ const int* digits_values,
+ unsigned digits_size,
+ const char* s,
+ unsigned s_size,
+ int* result)
+{
+ int si, dv;
+ int have_minus = 0;
+ int have_non_blank = 0;
+ int value = 0;
+ unsigned i = 0;
+ for(;i<s_size;i++) {
+ si = s[i];
+ if (si < 0 || si > 127) {
+ *result = 0;
+ return invalid_number_literal();
+ }
+ if (si == ' ') {
+ if (!have_non_blank) continue;
+ value *= digits_size;
+ }
+ else if (si == '-') {
+ if (have_non_blank) {
+ *result = 0;
+ return invalid_number_literal();
+ }
+ have_non_blank = 1;
+ have_minus = 1;
+ continue;
+ }
+ else {
+ have_non_blank = 1;
+ dv = digits_values[si];
+ if (dv < 0 || dv >= (int)digits_size) {
+ *result = 0;
+ return invalid_number_literal();
+ }
+ value *= digits_size;
+ value += dv;
+ }
+ }
+ if (have_minus) value = -value;
+ *result = value;
+ return 0;
+}
+
+/*! hybrid-36 encoder: converts integer value to string result
+
+ width: must be 4 (e.g. for residue sequence numbers)
+ or 5 (e.g. for atom serial numbers)
+
+ value: integer value to be converted
+
+ result: pointer to char array of size width+1 or greater
+ on return result is null-terminated
+
+ return value: pointer to error message, if any,
+ or 0 on success
+
+ Example usage (from C++):
+ char result[4+1];
+ const char* errmsg = hy36encode(4, 12345, result);
+ if (errmsg) throw std::runtime_error(errmsg);
+ */
+const char*
+hy36encode(unsigned width, int value, char* result)
+{
+ int i = value;
+ if (width == 4U) {
+ if (i >= -999) {
+ if (i < 10000) {
+ encode_pure(digits_upper(), 10U, 4U, i, result);
+ return 0;
+ }
+ i -= 10000;
+ if (i < 1213056 /* 26*36**3 */) {
+ i += 466560 /* 10*36**3 */;
+ encode_pure(digits_upper(), 36U, 0U, i, result);
+ return 0;
+ }
+ i -= 1213056;
+ if (i < 1213056) {
+ i += 466560;
+ encode_pure(digits_lower(), 36U, 0U, i, result);
+ return 0;
+ }
+ }
+ }
+ else if (width == 5U) {
+ if (i >= -9999) {
+ if (i < 100000) {
+ encode_pure(digits_upper(), 10U, 5U, i, result);
+ return 0;
+ }
+ i -= 100000;
+ if (i < 43670016 /* 26*36**4 */) {
+ i += 16796160 /* 10*36**4 */;
+ encode_pure(digits_upper(), 36U, 0U, i, result);
+ return 0;
+ }
+ i -= 43670016;
+ if (i < 43670016) {
+ i += 16796160;
+ encode_pure(digits_lower(), 36U, 0U, i, result);
+ return 0;
+ }
+ }
+ }
+ else {
+ fill_with_stars(width, result);
+ return unsupported_width();
+ }
+ fill_with_stars(width, result);
+ return value_out_of_range();
+}
+
+/*! hybrid-36 decoder: converts string s to integer result
+
+ width: must be 4 (e.g. for residue sequence numbers)
+ or 5 (e.g. for atom serial numbers)
+
+ s: string to be converted
+ does not have to be null-terminated
+
+ s_size: size of s
+ must be equal to width, or an error message is
+ returned otherwise
+
+ result: integer holding the conversion result
+
+ return value: pointer to error message, if any,
+ or 0 on success
+
+ Example usage (from C++):
+ int result;
+ const char* errmsg = hy36decode(width, "A1T5", 4, &result);
+ if (errmsg) throw std::runtime_error(errmsg);
+ */
+const char*
+hy36decode(unsigned width, const char* s, unsigned s_size, int* result)
+{
+ static int first_call = 1;
+ static int digits_values_upper[128U];
+ static int digits_values_lower[128U];
+ static const char*
+ ie_range = "internal error hy36decode: integer value out of range.";
+ unsigned i;
+ int di;
+ const char* errmsg;
+ if (first_call) {
+ first_call = 0;
+ for(i=0;i<128U;i++) digits_values_upper[i] = -1;
+ for(i=0;i<128U;i++) digits_values_lower[i] = -1;
+ for(i=0;i<36U;i++) {
+ di = digits_upper()[i];
+ if (di < 0 || di > 127) {
+ *result = 0;
+ return ie_range;
+ }
+ digits_values_upper[di] = i;
+ }
+ for(i=0;i<36U;i++) {
+ di = digits_lower()[i];
+ if (di < 0 || di > 127) {
+ *result = 0;
+ return ie_range;
+ }
+ digits_values_lower[di] = i;
+ }
+ }
+ if (s_size == width) {
+ di = s[0];
+ if (di >= 0 && di <= 127) {
+ if (digits_values_upper[di] >= 10) {
+ errmsg = decode_pure(digits_values_upper, 36U, s, s_size, result);
+ if (errmsg == 0) {
+ /* result - 10*36**(width-1) + 10**width */
+ if (width == 4U) (*result) -= 456560;
+ else if (width == 5U) (*result) -= 16696160;
+ else {
+ *result = 0;
+ return unsupported_width();
+ }
+ return 0;
+ }
+ }
+ else if (digits_values_lower[di] >= 10) {
+ errmsg = decode_pure(digits_values_lower, 36U, s, s_size, result);
+ if (errmsg == 0) {
+ /* result + 16*36**(width-1) + 10**width */
+ if (width == 4U) (*result) += 756496;
+ else if (width == 5U) (*result) += 26973856;
+ else {
+ *result = 0;
+ return unsupported_width();
+ }
+ return 0;
+ }
+ }
+ else {
+ errmsg = decode_pure(digits_values_upper, 10U, s, s_size, result);
+ if (errmsg) return errmsg;
+ if (!(width == 4U || width == 5U)) {
+ *result = 0;
+ return unsupported_width();
+ }
+ return 0;
+ }
+ }
+ }
+ *result = 0;
+ return invalid_number_literal();
+}
diff --git a/mmdb2/hybrid_36.h b/mmdb2/hybrid_36.h
new file mode 100644
index 0000000..4811b00
--- /dev/null
+++ b/mmdb2/hybrid_36.h
@@ -0,0 +1,21 @@
+/* If you change the include guards, please be sure to also rename the
+ functions below. Otherwise your project will clash with the original
+ iotbx declarations and definitions.
+ */
+#ifndef IOTBX_PDB_HYBRID_36_C_H
+#define IOTBX_PDB_HYBRID_36_C_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char*
+hy36encode(unsigned width, int value, char* result);
+
+const char*
+hy36decode(unsigned width, const char* s, unsigned s_size, int* result);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* IOTBX_PDB_HYBRID_36_C_H */
diff --git a/mmdb2/mmdb_atom.cpp b/mmdb2/mmdb_atom.cpp
new file mode 100644
index 0000000..0dcc986
--- /dev/null
+++ b/mmdb2/mmdb_atom.cpp
@@ -0,0 +1,3486 @@
+// $Id: mmdb_atom.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 18.10.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Atom <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Atom ( atom class )
+// ~~~~~~~~~ mmdb::Residue ( residue class )
+// **** Functions: mmdb::BondAngle
+// ~~~~~~~~~~
+//
+// Copyright (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "mmdb_chain.h"
+#include "mmdb_model.h"
+#include "mmdb_root.h"
+#include "mmdb_tables.h"
+#include "mmdb_cifdefs.h"
+#include "hybrid_36.h"
+
+
+namespace mmdb {
+
+ // ================================================================
+
+ #define ASET_ShortBinary 0x10000000
+ #define ASET_ShortTer 0x20000000
+ #define ASET_ShortHet 0x40000000
+
+ bool ignoreSegID = false;
+ bool ignoreElement = false;
+ bool ignoreCharge = false;
+ bool ignoreNonCoorPDBErrors = false;
+ bool ignoreUnmatch = false;
+
+
+ // ========================== Atom =============================
+
+ Atom::Atom() : UDData() {
+ InitAtom();
+ }
+
+ Atom::Atom ( PResidue res ) : UDData() {
+ InitAtom();
+ if (res)
+ res->AddAtom ( this );
+ }
+
+ Atom::Atom ( io::RPStream Object ) : UDData(Object) {
+ InitAtom();
+ }
+
+ Atom::~Atom() {
+ PPAtom A;
+ int nA;
+ FreeMemory();
+ if (residue) {
+ A = NULL;
+ nA = 0;
+ if (residue->chain) {
+ if (residue->chain->model) {
+ A = residue->chain->model->GetAllAtoms();
+ nA = residue->chain->model->GetNumberOfAllAtoms();
+ }
+ }
+ residue->_ExcludeAtom ( index );
+ if ((0<index) && (index<=nA)) A[index-1] = NULL;
+ }
+ }
+
+ void Atom::InitAtom() {
+ serNum = -1; // serial number
+ index = -1; // index in the file
+ name[0] = char(0); // atom name
+ label_atom_id[0] = char(0); // assigned atom name (not aligned)
+ altLoc[0] = char(0); // alternate location indicator
+ residue = NULL; // reference to residue
+ x = 0.0; // orthogonal x-coordinate in angstroms
+ y = 0.0; // orthogonal y-coordinate in angstroms
+ z = 0.0; // orthogonal z-coordinate in angstroms
+ occupancy = 0.0; // occupancy
+ tempFactor = 0.0; // temperature factor
+ segID[0] = char(0); // segment identifier
+ strcpy ( element," " ); // chemical element symbol - RIGHT JUSTIFIED
+ energyType[0] = char(0); // chemical element symbol - RIGHT JUSTIFIED
+ charge = 0.0; // charge on the atom
+ sigX = 0.0; // standard deviation of the stored x-coord
+ sigY = 0.0; // standard deviation of the stored y-coord
+ sigZ = 0.0; // standard deviation of the stored z-coord
+ sigOcc = 0.0; // standard deviation of occupancy
+ sigTemp = 0.0; // standard deviation of temperature factor
+ u11 = 0.0; //
+ u22 = 0.0; // anisotropic
+ u33 = 0.0; //
+ u12 = 0.0; // temperature
+ u13 = 0.0; //
+ u23 = 0.0; // factors
+ su11 = 0.0; //
+ su22 = 0.0; // standard
+ su33 = 0.0; // deviations of
+ su12 = 0.0; // anisotropic
+ su13 = 0.0; // temperature
+ su23 = 0.0; // factors
+ Het = false; // indicator of atom in non-standard groups
+ Ter = false; // chain terminator
+ WhatIsSet = 0x00000000; // nothing is set
+ nBonds = 0; // no bonds
+ Bond = NULL; // empty array of bonds
+ }
+
+ void Atom::FreeMemory() {
+ FreeBonds();
+ }
+
+ void Atom::FreeBonds() {
+ if (Bond) delete[] Bond;
+ Bond = NULL;
+ nBonds = 0;
+ }
+
+ int Atom::GetNBonds() {
+ return nBonds & 0x000000FF;
+ }
+
+ void Atom::GetBonds ( RPAtomBond atomBond, int & nAtomBonds ) {
+ // This GetBonds(..) returns pointer to the Atom's
+ // internal Bond structure, IT MUST NOT BE DISPOSED.
+ nAtomBonds = nBonds & 0x000000FF;
+ atomBond = Bond;
+ }
+
+ void Atom::GetBonds ( RPAtomBondI atomBondI, int & nAtomBonds ) {
+ // This GetBonds(..) disposes AtomBondI, if it was not set
+ // to NULL, allocates AtomBondI[nAtomBonds] and returns its
+ // pointer. AtomBondI MUST BE DISPOSED BY APPLICATION.
+ int i;
+
+ if (atomBondI) delete[] atomBondI;
+
+ nAtomBonds = nBonds & 0x000000FF;
+
+ if (nAtomBonds<=0)
+ atomBondI = NULL;
+ else {
+ atomBondI = new AtomBondI[nAtomBonds];
+ for (i=0;i<nAtomBonds;i++) {
+ if (Bond[i].atom)
+ atomBondI[i].index = Bond[i].atom->index;
+ else atomBondI[i].index = -1;
+ atomBondI[i].order = Bond[i].order;
+ }
+
+ }
+
+ }
+
+ void Atom::GetBonds ( PAtomBondI AtomBondI, int & nAtomBonds,
+ int maxlength ) {
+ // This GetBonds(..) does not dispose or allocate AtomBond.
+ // It is assumed that length of AtomBond is sufficient to
+ // accomodate all bonded atoms.
+ int i;
+
+ nAtomBonds = IMin(maxlength,nBonds & 0x000000FF);
+
+ for (i=0;i<nAtomBonds;i++) {
+ if (Bond[i].atom)
+ AtomBondI[i].index = Bond[i].atom->index;
+ else AtomBondI[i].index = -1;
+ AtomBondI[i].order = Bond[i].order;
+ }
+
+ }
+
+
+ int Atom::AddBond ( PAtom bond_atom, int bond_order,
+ int nAdd_bonds ) {
+ PAtomBond B1;
+ int i,k,nb,nballoc;
+
+ nb = nBonds & 0x000000FF;
+ k = -1;
+ for (i=0;(i<nb) && (k<0);i++)
+ if (Bond[i].atom==bond_atom) k = i;
+ if (k>=0) return -k;
+
+ nballoc = (nBonds >> 8) & 0x000000FF;
+ if (nBonds>=nballoc) {
+ nballoc += nAdd_bonds;
+ B1 = new AtomBond[nballoc];
+ for (i=0;i<nb;i++) {
+ B1[i].atom = Bond[i].atom;
+ B1[i].order = Bond[i].order;
+ }
+ if (Bond) delete[] Bond;
+ Bond = B1;
+ }
+ Bond[nb].atom = bond_atom;
+ Bond[nb].order = bond_order;
+ nb++;
+
+ nBonds = nb | (nballoc << 8);
+
+ return nb;
+
+ }
+
+ void Atom::SetResidue ( PResidue res ) {
+ residue = res;
+ }
+
+ void Atom::StandardPDBOut ( cpstr Record, pstr S ) {
+ char N[10];
+ strcpy ( S,Record );
+ PadSpaces ( S,80 );
+ if (serNum>99999) {
+ hy36encode ( 5,serNum,N );
+ strcpy_n ( &(S[6]),N,5 );
+ } else if (serNum>0)
+ PutInteger ( &(S[6]),serNum,5 );
+ else if (index<=99999)
+ PutInteger ( &(S[6]),index,5 );
+ else {
+ hy36encode ( 5,index,N );
+ strcpy_n ( &(S[6]),N,5 );
+ }
+ if (!Ter) {
+ if (altLoc[0]) S[16] = altLoc[0];
+ strcpy_n ( &(S[12]),name ,4 );
+ strcpy_n ( &(S[72]),segID ,4 );
+ strcpy_nr ( &(S[76]),element,2 );
+ if (WhatIsSet & ASET_Charge) {
+ if (charge>0) sprintf ( N,"%1i+",mround(charge) );
+ else if (charge<0) sprintf ( N,"%1i-",mround(-charge) );
+ else strcpy ( N," " );
+ strcpy_n ( &(S[78]),N,2 );
+ } else
+ strcpy_n ( &(S[78])," ",2 );
+ }
+ strcpy_nr ( &(S[17]),residue->name,3 );
+ strcpy_nr ( &(S[20]),residue->chain->chainID,2 );
+ if (residue->seqNum>MinInt4) {
+ if ((-999<=residue->seqNum) && (residue->seqNum<=9999))
+ PutIntIns ( &(S[22]),residue->seqNum,4,residue->insCode );
+ else {
+ hy36encode ( 4,residue->seqNum,N );
+ strcpy_n ( &(S[22]),N,4 );
+ }
+ }
+ }
+
+ void Atom::PDBASCIIDump ( io::RFile f ) {
+ // makes the ASCII PDB ATOM, HETATM, SIGATOM, ANISOU
+ // SIGUIJ and TER lines from the class' data
+ char S[100];
+ if (Ter) {
+ if (WhatIsSet & ASET_Coordinates) {
+ StandardPDBOut ( pstr("TER"),S );
+ f.WriteLine ( S );
+ }
+ } else {
+ if (WhatIsSet & ASET_Coordinates) {
+ if (Het) StandardPDBOut ( pstr("HETATM"),S );
+ else StandardPDBOut ( pstr("ATOM") ,S );
+ PutRealF ( &(S[30]),x,8,3 );
+ PutRealF ( &(S[38]),y,8,3 );
+ PutRealF ( &(S[46]),z,8,3 );
+ if (WhatIsSet & ASET_Occupancy)
+ PutRealF ( &(S[54]),occupancy ,6,2 );
+ if (WhatIsSet & ASET_tempFactor)
+ PutRealF ( &(S[60]),tempFactor,6,2 );
+ f.WriteLine ( S );
+ }
+ if (WhatIsSet & ASET_CoordSigma) {
+ StandardPDBOut ( pstr("SIGATM"),S );
+ PutRealF ( &(S[30]),sigX,8,3 );
+ PutRealF ( &(S[38]),sigY,8,3 );
+ PutRealF ( &(S[46]),sigZ,8,3 );
+ if ((WhatIsSet & ASET_OccSigma) &&
+ (WhatIsSet & ASET_Occupancy))
+ PutRealF ( &(S[54]),sigOcc,6,2 );
+ if ((WhatIsSet & ASET_tFacSigma) &&
+ (WhatIsSet & ASET_tempFactor))
+ PutRealF ( &(S[60]),sigTemp,6,2 );
+ f.WriteLine ( S );
+ }
+ if (WhatIsSet & ASET_Anis_tFac) {
+ StandardPDBOut ( pstr("ANISOU"),S );
+ PutInteger ( &(S[28]),mround(u11*1.0e4),7 );
+ PutInteger ( &(S[35]),mround(u22*1.0e4),7 );
+ PutInteger ( &(S[42]),mround(u33*1.0e4),7 );
+ PutInteger ( &(S[49]),mround(u12*1.0e4),7 );
+ PutInteger ( &(S[56]),mround(u13*1.0e4),7 );
+ PutInteger ( &(S[63]),mround(u23*1.0e4),7 );
+ f.WriteLine ( S );
+ if (WhatIsSet & ASET_Anis_tFSigma) {
+ StandardPDBOut ( pstr("SIGUIJ"),S );
+ PutInteger ( &(S[28]),mround(su11*1.0e4),7 );
+ PutInteger ( &(S[35]),mround(su22*1.0e4),7 );
+ PutInteger ( &(S[42]),mround(su33*1.0e4),7 );
+ PutInteger ( &(S[49]),mround(su12*1.0e4),7 );
+ PutInteger ( &(S[56]),mround(su13*1.0e4),7 );
+ PutInteger ( &(S[63]),mround(su23*1.0e4),7 );
+ f.WriteLine ( S );
+ }
+ }
+ }
+ }
+
+ void Atom::MakeCIF ( mmcif::PData CIF ) {
+ mmcif::PLoop Loop;
+ AtomName AtName;
+ Element el;
+ char N[10];
+ int i,j,RC;
+ PChain chain = NULL;
+ PModel model = NULL;
+ //bool singleModel = true;
+
+ if (residue) chain = residue->chain;
+ if (chain) model = PModel(chain->model);
+ // if (model) {
+ // if (model->manager)
+ // singleModel = PRoot(model->manager)->nModels<=1;
+ // }
+
+ /*
+
+ loop_
+ *0 _atom_site.group_PDB
+ *1 _atom_site.id
+ *2 _atom_site.type_symbol <- chem elem
+ -3 _atom_site.label_atom_id <- atom name
+ *4 _atom_site.label_alt_id <- alt code
+ =5 _atom_site.label_comp_id <- res name ???
+ =6 _atom_site.label_asym_id <- chain id ???
+ =7 _atom_site.label_entity_id < ???
+ =8 _atom_site.label_seq_id <- poly seq id
+ +9 _atom_site.pdbx_PDB_ins_code <- ins code
+ -10 _atom_site.segment_id <- segment id
+ *11 _atom_site.Cartn_x
+ *12 _atom_site.Cartn_y
+ *13 _atom_site.Cartn_z
+ *14 _atom_site.occupancy
+ *15 _atom_site.B_iso_or_equiv
+ *16 _atom_site.Cartn_x_esd
+ *17 _atom_site.Cartn_y_esd
+ *18 _atom_site.Cartn_z_esd
+ *19 _atom_site.occupancy_esd
+ *20 _atom_site.B_iso_or_equiv_esd
+ *21 _atom_site.pdbx_formal_charge
+ +22 _atom_site.auth_seq_id <- seq id we want
+ +23 _atom_site.auth_comp_id <- res name we want
+ +24 _atom_site.auth_asym_id <- ch id we want ?
+ *25 _atom_site.auth_atom_id <- atom name we want ?
+ +26 _atom_site.pdbx_PDB_model_num <- model no
+
+ '+' is read in Root::CheckAtomPlace()
+ '=' new in residue
+ '-' new in atom
+
+
+ */
+
+ RC = CIF->AddLoop ( CIFCAT_ATOM_SITE,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+
+ Loop->AddLoopTag ( CIFTAG_GROUP_PDB ); // ATOM, TER etc.
+ Loop->AddLoopTag ( CIFTAG_ID ); // serial number
+
+ Loop->AddLoopTag ( CIFTAG_TYPE_SYMBOL ); // element symbol
+ Loop->AddLoopTag ( CIFTAG_LABEL_ATOM_ID ); // atom name
+ Loop->AddLoopTag ( CIFTAG_LABEL_ALT_ID ); // alt location
+ Loop->AddLoopTag ( CIFTAG_LABEL_COMP_ID ); // residue name
+ Loop->AddLoopTag ( CIFTAG_LABEL_ASYM_ID ); // chain ID
+ Loop->AddLoopTag ( CIFTAG_LABEL_ENTITY_ID ); // entity ID
+ Loop->AddLoopTag ( CIFTAG_LABEL_SEQ_ID ); // res seq number
+ Loop->AddLoopTag ( CIFTAG_PDBX_PDB_INS_CODE ); // insertion code
+ Loop->AddLoopTag ( CIFTAG_SEGMENT_ID ); // segment ID
+
+ Loop->AddLoopTag ( CIFTAG_CARTN_X ); // x-coordinate
+ Loop->AddLoopTag ( CIFTAG_CARTN_Y ); // y-coordinate
+ Loop->AddLoopTag ( CIFTAG_CARTN_Z ); // z-coordinate
+ Loop->AddLoopTag ( CIFTAG_OCCUPANCY ); // occupancy
+ Loop->AddLoopTag ( CIFTAG_B_ISO_OR_EQUIV ); // temp factor
+
+ Loop->AddLoopTag ( CIFTAG_CARTN_X_ESD ); // x-sigma
+ Loop->AddLoopTag ( CIFTAG_CARTN_Y_ESD ); // y-sigma
+ Loop->AddLoopTag ( CIFTAG_CARTN_Z_ESD ); // z-sigma
+ Loop->AddLoopTag ( CIFTAG_OCCUPANCY_ESD ); // occupancy-sigma
+ Loop->AddLoopTag ( CIFTAG_B_ISO_OR_EQUIV_ESD ); // t-factor-sigma
+
+ Loop->AddLoopTag ( CIFTAG_PDBX_FORMAL_CHARGE ); // charge on atom
+
+ Loop->AddLoopTag ( CIFTAG_AUTH_SEQ_ID ); // res seq number
+ Loop->AddLoopTag ( CIFTAG_AUTH_COMP_ID ); // residue name
+ Loop->AddLoopTag ( CIFTAG_AUTH_ASYM_ID ); // chain id
+ Loop->AddLoopTag ( CIFTAG_AUTH_ATOM_ID ); // atom name
+
+ Loop->AddLoopTag ( CIFTAG_PDBX_PDB_MODEL_NUM ); // model number
+
+ }
+
+ if (Ter) { // ter record
+
+ if (!(WhatIsSet & ASET_Coordinates))
+ return;
+
+ // (0)
+ Loop->AddString ( pstr("TER") );
+ // (1)
+ if (serNum>0) Loop->AddInteger ( serNum );
+ else Loop->AddInteger ( index );
+ // (2,3,4)
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION ); // no element symbol
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION ); // no atom name
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION ); // no alt code
+ if (residue) {
+ // (5)
+ Loop->AddString ( residue->label_comp_id );
+ // (6)
+ Loop->AddString ( residue->label_asym_id );
+ // (7)
+ if (residue->label_entity_id>0)
+ Loop->AddInteger ( residue->label_entity_id );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ // (8)
+ if (residue->label_seq_id>MinInt4)
+ Loop->AddInteger ( residue->label_seq_id );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ // (9)
+ Loop->AddString ( residue->insCode,true );
+ } else {
+ // (5,6,7,8,9)
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ }
+
+ // (10-21)
+ for (i=10;i<=21;i++)
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+ // (22,23)
+ if (residue) {
+ if (residue->seqNum>MinInt4)
+ Loop->AddInteger ( residue->seqNum );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ Loop->AddString ( residue->name );
+ } else {
+ Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ Loop->AddString ( NULL );
+ }
+
+ // (24)
+ if (chain) Loop->AddString ( chain->chainID,true );
+ else Loop->AddString ( NULL );
+
+ // (25)
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION ); // no atom name
+
+ } else if (WhatIsSet & (ASET_Coordinates | ASET_CoordSigma)) {
+ // normal atom record
+
+ if (!WhatIsSet) return;
+
+ // (0)
+ if (Het) Loop->AddString ( pstr("HETATM") );
+ else Loop->AddString ( pstr("ATOM") );
+ // (1)
+ if (serNum>0) Loop->AddInteger ( serNum );
+ else Loop->AddInteger ( index );
+
+
+ if (WhatIsSet & ASET_Coordinates) {
+
+ // (2)
+ strcpy_css ( el,element );
+ Loop->AddString ( el,true );
+ // (3)
+ Loop->AddString ( label_atom_id ); // assigned atom name
+ // (4)
+ Loop->AddString ( altLoc,true ); // alt code
+
+ if (residue) {
+ // (5)
+ Loop->AddString ( residue->label_comp_id );
+ // (6)
+ Loop->AddString ( residue->label_asym_id );
+ // (7)
+ if (residue->label_entity_id>0)
+ Loop->AddInteger ( residue->label_entity_id );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ // (8)
+ if (residue->label_seq_id>MinInt4)
+ Loop->AddInteger ( residue->label_seq_id );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ // (9)
+ Loop->AddString ( residue->insCode,true );
+ } else {
+ // (5,6,7,8,9)
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ }
+
+ // (10)
+ Loop->AddString ( segID ,true );
+ // (11,12,13)
+ Loop->AddReal ( x );
+ Loop->AddReal ( y );
+ Loop->AddReal ( z );
+ // (14)
+ if (WhatIsSet & ASET_Occupancy)
+ Loop->AddReal ( occupancy );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+ // (15)
+ if (WhatIsSet & ASET_tempFactor)
+ Loop->AddReal ( tempFactor );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+ // (16,17,18)
+ if (WhatIsSet & ASET_CoordSigma) {
+ Loop->AddReal ( sigX );
+ Loop->AddReal ( sigY );
+ Loop->AddReal ( sigZ );
+ } else {
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+ }
+ // (19)
+ if ((WhatIsSet & ASET_OccSigma) && (WhatIsSet & ASET_Occupancy))
+ Loop->AddReal ( sigOcc );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+ // (20)
+ if ((WhatIsSet & ASET_tFacSigma) && (WhatIsSet & ASET_tempFactor))
+ Loop->AddReal ( sigTemp );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+ } else
+ for (i=0;i<18;i++)
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+ // (21)
+ if (WhatIsSet & ASET_Charge) {
+ sprintf ( N,"%+2i",mround(charge) );
+ Loop->AddString ( N,true );
+ } else
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+ if (residue) {
+ // (22)
+ if (residue->seqNum>MinInt4)
+ Loop->AddInteger ( residue->seqNum );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ // (23)
+ Loop->AddString ( residue->name );
+ } else {
+ Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ }
+
+ // (24)
+ if (chain) Loop->AddString ( chain->chainID,true );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ // (25)
+ strcpy_css ( AtName,name );
+ Loop->AddString ( AtName ); // atom name
+
+ }
+
+ // (26)
+ if (!model) Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+ else if (model->serNum>0) Loop->AddInteger ( model->serNum );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+
+ if (WhatIsSet & ASET_Anis_tFac) {
+
+ RC = CIF->AddLoop ( CIFCAT_ATOM_SITE_ANISOTROP,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_ID ); // serial number
+ Loop->AddLoopTag ( CIFTAG_U11 ); // component u11
+ Loop->AddLoopTag ( CIFTAG_U22 ); // component u22
+ Loop->AddLoopTag ( CIFTAG_U33 ); // component u33
+ Loop->AddLoopTag ( CIFTAG_U12 ); // component u12
+ Loop->AddLoopTag ( CIFTAG_U13 ); // component u13
+ Loop->AddLoopTag ( CIFTAG_U23 ); // component u23
+ Loop->AddLoopTag ( CIFTAG_U11_ESD ); // component u11 sigma
+ Loop->AddLoopTag ( CIFTAG_U22_ESD ); // component u22 sigma
+ Loop->AddLoopTag ( CIFTAG_U33_ESD ); // component u33 sigma
+ Loop->AddLoopTag ( CIFTAG_U12_ESD ); // component u12 sigma
+ Loop->AddLoopTag ( CIFTAG_U13_ESD ); // component u13 sigma
+ Loop->AddLoopTag ( CIFTAG_U23_ESD ); // component u23 sigma
+ for (i=1;i<index;i++) {
+ Loop->AddInteger ( i );
+ for (j=0;j<12;j++)
+ Loop->AddString ( NULL );
+ }
+ }
+
+ if (serNum>0) Loop->AddInteger ( serNum );
+ else Loop->AddInteger ( index );
+
+ Loop->AddReal ( u11 );
+ Loop->AddReal ( u22 );
+ Loop->AddReal ( u33 );
+ Loop->AddReal ( u12 );
+ Loop->AddReal ( u13 );
+ Loop->AddReal ( u23 );
+ if (WhatIsSet & ASET_Anis_tFSigma) {
+ Loop->AddReal ( su11 );
+ Loop->AddReal ( su22 );
+ Loop->AddReal ( su33 );
+ Loop->AddReal ( su12 );
+ Loop->AddReal ( su13 );
+ Loop->AddReal ( su23 );
+ }
+
+ }
+
+ }
+
+ ERROR_CODE Atom::ConvertPDBATOM ( int ix, cpstr S ) {
+ // Gets data from the PDB ASCII ATOM record.
+ // This function DOES NOT check the "ATOM" keyword and
+ // does not decode the chain and residue parameters! These
+ // must be treated by calling process, see
+ // Chain::ConvertPDBASCII().
+
+ index = ix;
+
+ if (WhatIsSet & ASET_Coordinates)
+ return Error_ATOM_AlreadySet;
+
+ if (!(GetReal(x,&(S[30]),8) &&
+ GetReal(y,&(S[38]),8) &&
+ GetReal(z,&(S[46]),8)))
+ return Error_ATOM_Unrecognized;
+
+ WhatIsSet |= ASET_Coordinates;
+ Het = false;
+ Ter = false;
+
+ if (GetReal(occupancy ,&(S[54]),6)) WhatIsSet |= ASET_Occupancy;
+ if (GetReal(tempFactor,&(S[60]),6)) WhatIsSet |= ASET_tempFactor;
+
+ if (WhatIsSet & (ASET_CoordSigma | ASET_Anis_tFac |
+ ASET_Anis_tFSigma))
+ // something was already submitted. check complience
+ return CheckData ( S );
+ else
+ // first data submission. just take the data
+ GetData ( S );
+
+ return Error_NoError;
+
+ }
+
+ void Atom::SetAtomName ( int ix,
+ int sN,
+ const AtomName aName,
+ const AltLoc aLoc,
+ const SegID sID,
+ const Element eName ) {
+ index = ix;
+ serNum = sN;
+ strcpy ( name ,aName );
+ strcpy ( label_atom_id,aName );
+ strcpy_css ( altLoc ,pstr(aLoc) );
+ strcpy_css ( segID ,pstr(sID) );
+ if (!eName[0]) element[0] = char(0);
+ else if (!eName[1]) {
+ element[0] = ' ';
+ strcpy ( &(element[1]),eName );
+ } else
+ strcpy ( element,eName );
+ WhatIsSet = 0;
+ }
+
+ ERROR_CODE Atom::ConvertPDBSIGATM ( int ix, cpstr S ) {
+ // Gets data from the PDB ASCII SIGATM record.
+ // This function DOES NOT check the "SIGATM" keyword and
+ // does not decode the chain and residue parameters! These
+ // must be treated by the calling process, see
+ // Chain::ConvertPDBASCII().
+
+ index = ix;
+
+ if (WhatIsSet & ASET_CoordSigma)
+ return Error_ATOM_AlreadySet;
+
+ if (!(GetReal(sigX,&(S[30]),8) &&
+ GetReal(sigY,&(S[38]),8) &&
+ GetReal(sigZ,&(S[46]),8)))
+ return Error_ATOM_Unrecognized;
+
+ WhatIsSet |= ASET_CoordSigma;
+
+ if (GetReal(sigOcc ,&(S[54]),6)) WhatIsSet |= ASET_OccSigma;
+ if (GetReal(sigTemp,&(S[60]),6)) WhatIsSet |= ASET_tFacSigma;
+
+ if (WhatIsSet & (ASET_Coordinates | ASET_Anis_tFac |
+ ASET_Anis_tFSigma))
+ // something was already submitted. check complience
+ return CheckData ( S );
+ else
+ // first data submission. just take the data
+ GetData ( S );
+
+ return Error_NoError;
+
+ }
+
+ ERROR_CODE Atom::ConvertPDBANISOU ( int ix, cpstr S ) {
+ // Gets data from the PDB ASCII ANISOU record.
+ // This function DOES NOT check the "ANISOU" keyword and
+ // does not decode chain and residue parameters! These must
+ // be treated by the calling process, see
+ // Chain::ConvertPDBASCII().
+
+ index = ix;
+
+ if (WhatIsSet & ASET_Anis_tFac)
+ return Error_ATOM_AlreadySet;
+
+ if (!(GetReal(u11,&(S[28]),7) &&
+ GetReal(u22,&(S[35]),7) &&
+ GetReal(u33,&(S[42]),7) &&
+ GetReal(u12,&(S[49]),7) &&
+ GetReal(u13,&(S[56]),7) &&
+ GetReal(u23,&(S[63]),7)))
+ return Error_ATOM_Unrecognized;
+
+ u11 /= 1.0e4;
+ u22 /= 1.0e4;
+ u33 /= 1.0e4;
+ u12 /= 1.0e4;
+ u13 /= 1.0e4;
+ u23 /= 1.0e4;
+
+ WhatIsSet |= ASET_Anis_tFac;
+
+ if (WhatIsSet & (ASET_Coordinates | ASET_CoordSigma |
+ ASET_Anis_tFSigma))
+ // something was already submitted. check complience
+ return CheckData ( S );
+ else
+ // first data submission. just take the data
+ GetData ( S );
+
+ return Error_NoError;
+
+ }
+
+ ERROR_CODE Atom::ConvertPDBSIGUIJ ( int ix, cpstr S ) {
+ // Gets data from the PDB ASCII SIGUIJ record.
+ // This function DOES NOT check the "SIGUIJ" keyword and
+ // does not decode the chain and residue parameters! These
+ // must be treated by the calling process, see
+ // Chain::ConvertPDBASCII().
+
+ index = ix;
+
+ if (WhatIsSet & ASET_Anis_tFSigma)
+ return Error_ATOM_AlreadySet;
+
+ if (!(GetReal(su11,&(S[28]),7) &&
+ GetReal(su22,&(S[35]),7) &&
+ GetReal(su33,&(S[42]),7) &&
+ GetReal(su12,&(S[49]),7) &&
+ GetReal(su13,&(S[56]),7) &&
+ GetReal(su23,&(S[63]),7)))
+ return Error_ATOM_Unrecognized;
+
+ su11 /= 1.0e4;
+ su22 /= 1.0e4;
+ su33 /= 1.0e4;
+ su12 /= 1.0e4;
+ su13 /= 1.0e4;
+ su23 /= 1.0e4;
+
+ WhatIsSet |= ASET_Anis_tFSigma;
+
+ if (WhatIsSet & (ASET_Coordinates | ASET_CoordSigma |
+ ASET_Anis_tFac))
+ // something was already submitted. check complience
+ return CheckData ( S );
+ else
+ // first data submission. just take the data
+ GetData ( S );
+
+ return Error_NoError;
+
+ }
+
+ ERROR_CODE Atom::ConvertPDBTER ( int ix, cpstr S ) {
+ // Gets data from the PDB ASCII TER record.
+ // This function DOES NOT check the "TER" keyword and
+ // does not decode the chain and residue parameters! These
+ // must be treated by the calling process, see
+ // Chain::ConvertPDBASCII().
+
+ index = ix;
+
+ if (((S[6]>='0') && (S[6]<='9')) || (S[6]==' ')) {
+ // Although against strict PDB format, 'TER' is
+ // actually allowed not to have a serial number.
+ // This negative value implies that the number is
+ // not set.
+ if (!(GetInteger(serNum,&(S[6]),5))) serNum = -1;
+ } else
+ hy36decode ( 5,&(S[6]),5,&serNum );
+
+ // if (!(GetInteger(serNum,&(S[6]),5))) serNum = -1;
+
+ if (WhatIsSet & ASET_Coordinates)
+ return Error_ATOM_AlreadySet;
+
+ WhatIsSet |= ASET_Coordinates;
+ Het = false;
+ Ter = true;
+ name[0] = char(0);
+ label_atom_id[0] = char(0);
+ element[0] = char(0);
+
+ return Error_NoError;
+
+ }
+
+
+ int Atom::GetModelNum() {
+ if (residue) {
+ if (residue->chain)
+ if (residue->chain->model)
+ return residue->chain->model->GetSerNum();
+ }
+ return 0;
+ }
+
+ pstr Atom::GetChainID() {
+ if (residue) {
+ if (residue->chain) return residue->chain->chainID;
+ }
+ return pstr("");
+ }
+
+ pstr Atom::GetLabelAsymID() {
+ if (residue) return residue->label_asym_id;
+ else return pstr("");
+ }
+
+ pstr Atom::GetResName() {
+ if (residue) return residue->name;
+ else return pstr("");
+ }
+
+ pstr Atom::GetLabelCompID() {
+ if (residue) return residue->label_comp_id;
+ else return pstr("");
+ }
+
+ int Atom::GetAASimilarity ( const ResName resName ) {
+ if (residue)
+ return mmdb::GetAASimilarity ( pstr(residue->name),
+ pstr(resName) );
+ else return -3;
+ }
+
+ int Atom::GetAASimilarity ( PAtom A ) {
+ if (residue) {
+ if (A->residue)
+ return mmdb::GetAASimilarity ( pstr(residue->name),
+ pstr(A->residue->name) );
+ else return -4;
+ } else
+ return -3;
+ }
+
+ realtype Atom::GetAAHydropathy() {
+ if (residue)
+ return mmdb::GetAAHydropathy ( pstr(residue->name) );
+ else return MaxReal;
+ }
+
+ realtype Atom::GetOccupancy() {
+ if (WhatIsSet & ASET_Occupancy) return occupancy;
+ else return 0.0;
+ }
+
+ int Atom::GetSeqNum() {
+ if (residue) return residue->seqNum;
+ else return ATOM_NoSeqNum;
+ }
+
+ int Atom::GetLabelSeqID() {
+ if (residue) return residue->label_seq_id;
+ else return ATOM_NoSeqNum;
+ }
+
+ int Atom::GetLabelEntityID() {
+ if (residue) return residue->label_entity_id;
+ else return -1;
+ }
+
+ pstr Atom::GetInsCode() {
+ if (residue) return residue->insCode;
+ else return pstr("");
+ }
+
+ int Atom::GetSSEType() {
+ // works only after SSE calculations
+ if (residue) return residue->SSE;
+ else return SSE_None;
+ }
+
+ pstr Atom::GetAtomCharge ( pstr chrg ) {
+ if (WhatIsSet & ASET_Charge) sprintf ( chrg,"%+2i",mround(charge) );
+ else strcpy ( chrg," " );
+ return chrg;
+ }
+
+ PResidue Atom::GetResidue() {
+ return residue;
+ }
+
+ PChain Atom::GetChain() {
+ if (residue) return residue->chain;
+ else return NULL;
+ }
+
+ PModel Atom::GetModel() {
+ if (residue) {
+ if (residue->chain) return (PModel)residue->chain->model;
+ }
+ return NULL;
+ }
+
+ int Atom::GetResidueNo() {
+ if (residue) {
+ if (residue->chain)
+ return residue->chain->GetResidueNo (
+ residue->seqNum,residue->insCode );
+ else return -2;
+ } else
+ return -1;
+ }
+
+
+ void * Atom::GetCoordHierarchy() {
+ if (residue) return residue->GetCoordHierarchy();
+ return NULL;
+ }
+
+
+ void Atom::GetStat ( realtype v,
+ realtype & v_min, realtype & v_max,
+ realtype & v_m, realtype & v_m2 ) {
+ if (v<v_min) v_min = v;
+ if (v>v_max) v_max = v;
+ v_m += v;
+ v_m2 += v*v;
+ }
+
+
+
+ void Atom::GetChainCalphas ( PPAtom & Calphas, int & nCalphas,
+ cpstr altLoc ) {
+ // GetChainCalphas(...) is a specialized function for quick
+ // access to C-alphas of chain which includes given atom.
+ // This function works faster than an equivalent implementation
+ // through MMDB's selection procedures.
+ // Parameters:
+ // Calphas - array to accept pointers on C-alpha atoms
+ // If Calphas!=NULL, then the function will
+ // delete and re-allocate it. When the array
+ // is no longer needed, the application MUST
+ // delete it: delete[] Calphas; Deleting
+ // Calphas does not delete atoms from MMDB.
+ // nCalphas - integer to accept number of C-alpha atoms
+ // and the length of Calphas array.
+ // altLoc - alternative location indicator. By default
+ // (""), maximum-occupancy locations are taken.
+ PChain chain;
+ PPResidue res;
+ PPAtom atom;
+ int nResidues, nAtoms, i,j,k;
+
+ if (Calphas) {
+ delete[] Calphas;
+ Calphas = NULL;
+ }
+ nCalphas = 0;
+
+ if (residue) chain = residue->chain;
+ else chain = NULL;
+
+ if (chain) {
+
+ chain->GetResidueTable ( res,nResidues );
+
+ if (nResidues>0) {
+
+ Calphas = new PAtom[nResidues];
+
+ if ((!altLoc[0]) || (altLoc[0]==' ')) { // main conformation
+
+ for (i=0;i<nResidues;i++) {
+ nAtoms = res[i]->nAtoms;
+ atom = res[i]->atom;
+ for (j=0;j<nAtoms;j++)
+ if (!strcmp(atom[j]->name," CA ")) {
+ Calphas[nCalphas++] = atom[j];
+ break;
+ }
+ }
+
+ } else { // specific conformation
+
+ for (i=0;i<nResidues;i++) {
+ nAtoms = res[i]->nAtoms;
+ atom = res[i]->atom;
+ k = 0;
+ for (j=0;j<nAtoms;j++)
+ if (!strcmp(atom[j]->name," CA ")) {
+ k = 1;
+ if (!atom[j]->altLoc[0]) {
+ // take main conformation now as we do not know if
+ // the specific one is in the file
+ Calphas[nCalphas] = atom[j];
+ k = 2;
+ } else if (atom[j]->altLoc[0]==altLoc[0]) {
+ // get specific conformation and quit
+ Calphas[nCalphas] = atom[j];
+ k = 2;
+ break;
+ }
+ } else if (k)
+ break;
+ if (k==2) nCalphas++;
+ }
+
+ }
+
+ }
+
+ } else if (residue) { // check just this atom's residue
+
+ Calphas = new PAtom[1]; // can't be more than 1 C-alpha!
+
+ nAtoms = residue->nAtoms;
+ atom = residue->atom;
+
+ if ((!altLoc[0]) || (altLoc[0]==' ')) { // main conformation
+
+ for (j=0;j<nAtoms;j++)
+ if (!strcmp(atom[j]->name," CA ")) {
+ Calphas[nCalphas++] = atom[j];
+ break;
+ }
+
+ } else { // specific conformation
+
+ k = 0;
+ for (j=0;j<nAtoms;j++)
+ if (!strcmp(atom[j]->name," CA ")) {
+ k = 1;
+ if (!atom[j]->altLoc[0]) {
+ Calphas[nCalphas] = atom[j];
+ k = 2;
+ } else if (atom[j]->altLoc[0]==altLoc[0]) {
+ Calphas[nCalphas] = atom[j];
+ k = 2;
+ break;
+ }
+ } else if (k)
+ break;
+ if (k==2) nCalphas++;
+
+ }
+
+ }
+
+ if (Calphas && (!nCalphas)) {
+ delete[] Calphas;
+ Calphas = NULL;
+ }
+
+ }
+
+ bool Atom::isMetal() {
+ return mmdb::isMetal ( element );
+ }
+
+ bool Atom::isSolvent() {
+ if (residue) return residue->isSolvent();
+ return false;
+ }
+
+ bool Atom::isInSelection ( int selHnd ) {
+ PRoot manager = (PRoot)GetCoordHierarchy();
+ PMask mask;
+ if (manager) {
+ mask = manager->GetSelMask ( selHnd );
+ if (mask) return CheckMask ( mask );
+ }
+ return false;
+ }
+
+ bool Atom::isNTerminus() {
+ if (residue) return residue->isNTerminus();
+ return false;
+ }
+
+ bool Atom::isCTerminus() {
+ if (residue) return residue->isCTerminus();
+ return false;
+ }
+
+ void Atom::CalAtomStatistics ( RAtomStat AS ) {
+ // AS must be initialized. The function only accumulates
+ // the statistics.
+
+ if (!Ter) {
+
+ AS.nAtoms++;
+
+ if (AS.WhatIsSet & WhatIsSet & ASET_Coordinates) {
+ GetStat ( x,AS.xmin,AS.xmax,AS.xm,AS.xm2 );
+ GetStat ( y,AS.ymin,AS.ymax,AS.ym,AS.ym2 );
+ GetStat ( z,AS.zmin,AS.zmax,AS.zm,AS.zm2 );
+ } else
+ AS.WhatIsSet &= ~ASET_Coordinates;
+
+ if (AS.WhatIsSet & WhatIsSet & ASET_Occupancy)
+ GetStat(occupancy,AS.occ_min,AS.occ_max,AS.occ_m,AS.occ_m2);
+ else AS.WhatIsSet &= ~ASET_Occupancy;
+
+ if (AS.WhatIsSet & WhatIsSet & ASET_tempFactor)
+ GetStat ( tempFactor,AS.tFmin,AS.tFmax,AS.tFm,AS.tFm2 );
+ else AS.WhatIsSet &= ~ASET_tempFactor;
+
+ if (AS.WhatIsSet & WhatIsSet & ASET_Anis_tFac) {
+ GetStat ( u11,AS.u11_min,AS.u11_max,AS.u11_m,AS.u11_m2 );
+ GetStat ( u22,AS.u22_min,AS.u22_max,AS.u22_m,AS.u22_m2 );
+ GetStat ( u33,AS.u33_min,AS.u33_max,AS.u33_m,AS.u33_m2 );
+ GetStat ( u12,AS.u12_min,AS.u12_max,AS.u12_m,AS.u12_m2 );
+ GetStat ( u13,AS.u13_min,AS.u13_max,AS.u13_m,AS.u13_m2 );
+ GetStat ( u23,AS.u23_min,AS.u23_max,AS.u23_m,AS.u23_m2 );
+ } else
+ AS.WhatIsSet &= ~ASET_Anis_tFac;
+
+ }
+
+ }
+
+
+ realtype Atom::GetDist2 ( PAtom a ) {
+ realtype dx,dy,dz;
+ dx = a->x - x;
+ dy = a->y - y;
+ dz = a->z - z;
+ return dx*dx + dy*dy + dz*dz;
+ }
+
+ realtype Atom::GetDist2 ( PAtom a, mat44 & tm ) {
+ realtype dx,dy,dz;
+ dx = tm[0][0]*a->x + tm[0][1]*a->y + tm[0][2]*a->z + tm[0][3] - x;
+ dy = tm[1][0]*a->x + tm[1][1]*a->y + tm[1][2]*a->z + tm[1][3] - y;
+ dz = tm[2][0]*a->x + tm[2][1]*a->y + tm[2][2]*a->z + tm[2][3] - z;
+ return dx*dx + dy*dy + dz*dz;
+ }
+
+ realtype Atom::GetDist2 ( PAtom a, mat33 & r, vect3 & t ) {
+ realtype dx,dy,dz;
+ dx = r[0][0]*a->x + r[0][1]*a->y + r[0][2]*a->z + t[0] - x;
+ dy = r[1][0]*a->x + r[1][1]*a->y + r[1][2]*a->z + t[1] - y;
+ dz = r[2][0]*a->x + r[2][1]*a->y + r[2][2]*a->z + t[2] - z;
+ return dx*dx + dy*dy + dz*dz;
+ }
+
+ realtype Atom::GetDist2 ( realtype ax, realtype ay, realtype az ) {
+ realtype dx,dy,dz;
+ dx = ax - x;
+ dy = ay - y;
+ dz = az - z;
+ return dx*dx + dy*dy + dz*dz;
+ }
+
+ realtype Atom::GetCosine ( PAtom a1, PAtom a2 ) {
+ // Calculates cosing of angle a1-this-a2, i.e. that between
+ // bond [a1,this] and [this,a2].
+ realtype dx1,dy1,dz1, dx2,dy2,dz2,r;
+
+ dx1 = a1->x - x;
+ dy1 = a1->y - y;
+ dz1 = a1->z - z;
+ r = dx1*dx1 + dy1*dy1 + dz1*dz1;
+
+ dx2 = a2->x - x;
+ dy2 = a2->y - y;
+ dz2 = a2->z - z;
+ r *= dx2*dx2 + dy2*dy2 + dz2*dz2;
+
+ if (r>0.0) return (dx1*dx2 + dy1*dy2 + dz1*dz2)/sqrt(r);
+ else return 0.0;
+
+ }
+
+
+ void Atom::MakeTer() {
+ WhatIsSet |= ASET_Coordinates;
+ Het = false;
+ Ter = true;
+ }
+
+
+ void Atom::SetAtomName ( const AtomName atomName ) {
+ strcpy ( name,atomName );
+ }
+
+
+ void Atom::SetElementName ( const Element elName ) {
+ strcpy ( element,elName );
+ if (!element[0]) strcpy ( element," " );
+ else if ((!element[1]) || (element[1]==' ')) {
+ element[2] = char(0);
+ element[1] = element[0];
+ element[0] = ' ';
+ }
+ }
+
+ void Atom::SetCharge ( cpstr chrg ) {
+ pstr p;
+ charge = strtod ( chrg,&p );
+ if (p!=chrg) {
+ WhatIsSet |= ASET_Charge;
+ if ((charge>0.0) && (*p=='-'))
+ charge = -charge;
+ }
+ }
+
+ void Atom::SetCharge ( realtype chrg ) {
+ if (chrg<MaxReal) {
+ charge = chrg;
+ WhatIsSet |= ASET_Charge;
+ }
+ }
+
+ void Atom::SetAtomIndex ( int ix ) {
+ // don't use in your applications!
+ index = ix;
+ }
+
+ pstr Atom::GetAtomID ( pstr AtomID ) {
+ char S[50];
+ AtomID[0] = char(0);
+ if (residue) {
+ if (residue->chain) {
+ if (residue->chain->model)
+ sprintf (AtomID,"/%i/",residue->chain->model->GetSerNum());
+ else strcpy ( AtomID,"/-/" );
+ strcat ( AtomID,residue->chain->chainID );
+ } else
+ strcpy ( AtomID,"/-/-" );
+ ParamStr ( AtomID,pstr("/"),residue->seqNum );
+ if (residue->name[0]) {
+ strcat ( AtomID,"(" );
+ strcat ( AtomID,residue->name );
+ strcat ( AtomID,")" );
+ }
+ if (residue->insCode[0]) {
+ strcat ( AtomID,"." );
+ strcat ( AtomID,residue->insCode );
+ }
+ strcat ( AtomID,"/" );
+ } else
+ strcpy ( AtomID,"/-/-/-/" );
+ strcpy_css ( S,name );
+ if (!S[0]) strcpy ( S,"-" );
+ strcat ( AtomID,S );
+ strcpy_css ( S,element );
+ if (S[0]) {
+ strcat ( AtomID,"[" );
+ strcat ( AtomID,S );
+ strcat ( AtomID,"]" );
+ }
+ if (altLoc[0]) {
+ strcat ( AtomID,":" );
+ strcat ( AtomID,altLoc );
+ }
+ return AtomID;
+ }
+
+ pstr Atom::GetAtomIDfmt ( pstr AtomID ) {
+ int n;
+ char S[50];
+ AtomID[0] = char(0);
+ if (residue) {
+ if (residue->chain) {
+ if (residue->chain->model) {
+ n = residue->chain->model->GetNumberOfModels();
+ if (n<10) strcpy ( S,"/%1i/" );
+ else if (n<100) strcpy ( S,"/%2i/" );
+ else if (n<1000) strcpy ( S,"/%3i/" );
+ else strcpy ( S,"/%i/" );
+ sprintf ( AtomID,S,residue->chain->model->GetSerNum() );
+ } else
+ strcpy ( AtomID,"/-/" );
+ strcat ( AtomID,residue->chain->chainID );
+ } else
+ strcpy ( AtomID,"/-/-" );
+ if ((-999<=residue->seqNum) && (residue->seqNum<=9999))
+ sprintf ( S,"/%4i",residue->seqNum );
+ else sprintf ( S,"/%i" ,residue->seqNum );
+ strcat ( AtomID,S );
+ sprintf ( S,"(%3s).%1s/",residue->name,residue->insCode );
+ strcat ( AtomID,S );
+ } else
+ strcpy ( AtomID,"/-/-/----(---).-/" );
+ sprintf ( S,"%4s[%2s]:%1s",name,element,altLoc );
+ strcat ( AtomID,S );
+ return AtomID;
+ }
+
+
+
+ ERROR_CODE Atom::ConvertPDBHETATM ( int ix, cpstr S ) {
+ // Gets data from the PDB ASCII HETATM record.
+ // This function DOES NOT check the "HETATM" keyword and
+ // does not decode the chain and residue parameters! These
+ // must be treated by the calling process, see
+ // Chain::ConvertPDBASCII().
+ ERROR_CODE RC;
+ RC = ConvertPDBATOM ( ix,S );
+ Het = true;
+ return RC;
+ }
+
+ void Atom::GetData ( cpstr S ) {
+ pstr p;
+
+ if (((S[6]>='0') && (S[6]<='9')) || (S[6]==' ')) {
+ // Here we forgive cards with unreadable serial numbers
+ // as we always have index (ix) for the card. For the sake
+ // of strict PDB syntax we would have to return
+ // Error_UnrecognizedInteger here.
+ if (!(GetInteger(serNum,&(S[6]),5))) serNum = -1;
+ } else
+ hy36decode ( 5,&(S[6]),5,&serNum );
+
+ // if (!(GetInteger(serNum,&(S[6]),5))) serNum = index;
+
+ altLoc[0] = S[16];
+ if (altLoc[0]==' ') altLoc[0] = char(0);
+ else altLoc[1] = char(0);
+ GetString ( name ,&(S[12]),4 );
+ strcpy_ncss ( segID ,&(S[72]),4 );
+ GetString ( element,&(S[76]),2 );
+ charge = strtod ( &(S[78]),&p );
+ if ((charge!=0.0) && (p!=&(S[78]))) {
+ WhatIsSet |= ASET_Charge;
+ if ((charge>0.0) && (*p=='-'))
+ charge = -charge;
+ }
+
+ RestoreElementName();
+ strcpy ( label_atom_id,name );
+
+ }
+
+ ERROR_CODE Atom::CheckData ( cpstr S ) {
+ int sN;
+ AltLoc aloc;
+ SegID sID;
+ Element elmnt;
+ pstr p;
+ realtype achrg;
+
+ aloc[0] = S[16];
+ if (aloc[0]==' ') aloc[0] = char(0);
+ else aloc[1] = char(0);
+
+ strcpy_ncss ( sID ,&(S[72]),4 );
+ GetString ( elmnt,&(S[76]),2 );
+
+ if (ignoreCharge)
+ achrg = charge;
+ else {
+ achrg = strtod ( &(S[78]),&p );
+ if ((achrg!=0.0) && (p!=&(S[78]))) {
+ if ((achrg>0.0) && (*p=='-'))
+ achrg = -achrg;
+ }
+ }
+
+ // if (!(GetInteger(sN,&(S[6]),5)))
+ // sN = index;
+
+ if (hy36decode(5,&(S[6]),5,&sN))
+ sN = index;
+
+ if (ignoreSegID) {
+ if (segID[0]) strcpy ( sID,segID );
+ else strcpy ( segID,sID );
+ }
+
+ if (ignoreElement) {
+ if (element[0]) strcpy ( elmnt,element );
+ else strcpy ( element,elmnt );
+ }
+
+ if (ignoreUnmatch) return Error_NoError;
+
+ // Here we forgive cards with unreadable serial numbers
+ // as we always have index (ix) for the card. For the sake
+ // of strict PDB syntax we would have to return
+ // Error_UnrecognizedInteger .
+ if ((sN!=serNum) ||
+ (strcmp (altLoc ,aloc )) ||
+ (strncmp(name ,&(S[12]),4)) ||
+ (strcmp (segID ,sID )) ||
+ (strcmp (element,elmnt )) ||
+ (charge!=achrg)) {
+ /*
+ char name1[100];
+ strncpy ( name1,&(S[12]),4 ); name1[4] = char(0);
+ printf ( "\n serNum %5i %5i\n"
+ " residue '%s' '%s'\n"
+ " altLoc '%s' '%s'\n"
+ " name '%s' '%s'\n"
+ " segId '%s' '%s'\n"
+ " element '%s' '%s'\n"
+ " charge '%s' '%s'\n",
+ sN,serNum, res->name,residue->name,
+ altLoc ,aloc, name,name1,
+ segID ,sID,
+ element,elmnt,
+ charge ,achrg );
+ if (res!=residue) printf (" it's a residue\n" );
+ */
+ return Error_ATOM_Unmatch;
+ }
+
+ return Error_NoError;
+
+ }
+
+
+ ERROR_CODE Atom::GetCIF ( int ix, mmcif::PLoop Loop,
+ mmcif::PLoop LoopAnis ) {
+ char PDBGroup[30];
+ int k;
+ ERROR_CODE RC;
+
+ index = ix;
+
+ if (WhatIsSet & ASET_Coordinates)
+ return Error_ATOM_AlreadySet;
+
+ /*
+
+ loop_
+ *0 _atom_site.group_PDB
+ *1 _atom_site.id
+ *2 _atom_site.type_symbol <- chem elem
+ -3 _atom_site.label_atom_id <- atom name
+ *4 _atom_site.label_alt_id <- alt code
+ =5 _atom_site.label_comp_id <- res name ???
+ =6 _atom_site.label_asym_id <- chain id ???
+ =7 _atom_site.label_entity_id < ???
+ =8 _atom_site.label_seq_id <- poly seq id
+ +9 _atom_site.pdbx_PDB_ins_code <- ins code
+ -10 _atom_site.segment_id <- segment id
+ *11 _atom_site.Cartn_x
+ *12 _atom_site.Cartn_y
+ *13 _atom_site.Cartn_z
+ *14 _atom_site.occupancy
+ *15 _atom_site.B_iso_or_equiv
+ *16 _atom_site.Cartn_x_esd
+ *17 _atom_site.Cartn_y_esd
+ *18 _atom_site.Cartn_z_esd
+ *19 _atom_site.occupancy_esd
+ *20 _atom_site.B_iso_or_equiv_esd
+ *21 _atom_site.pdbx_formal_charge
+ +22 _atom_site.auth_seq_id <- seq id we want
+ +23 _atom_site.auth_comp_id <- res name we want
+ +24 _atom_site.auth_asym_id <- ch id we want ?
+ *25 _atom_site.auth_atom_id <- atom name we want ?
+ +26 _atom_site.pdbx_PDB_model_num <- model no
+
+ '+' read in Root::CheckAtomPlace()
+ '=' new in residue, read in Root::CheckAtomPlace()
+ '-' new in atom
+
+ */
+
+
+ // (0)
+ k = ix-1;
+ CIFGetString ( PDBGroup,Loop,CIFTAG_GROUP_PDB,k,
+ sizeof(PDBGroup),pstr("") );
+
+ Ter = !strcmp(PDBGroup,pstr("TER") );
+ Het = !strcmp(PDBGroup,pstr("HETATM"));
+
+ // (1)
+ RC = CIFGetInteger1 ( serNum,Loop,CIFTAG_ID,k );
+ if (RC) {
+ if (Ter) serNum = -1;
+ else if (RC==Error_NoData) serNum = index;
+ else
+ return RC;
+ }
+
+ if (Ter) {
+ Loop->DeleteRow ( k );
+ WhatIsSet |= ASET_Coordinates;
+ return Error_NoError;
+ }
+
+ // (25)
+ CIFGetString ( name,Loop,CIFTAG_AUTH_ATOM_ID,k,
+ sizeof(name) ,pstr("") );
+ // (3)
+ CIFGetString ( label_atom_id,Loop,CIFTAG_LABEL_ATOM_ID,k,
+ sizeof(label_atom_id),pstr("") );
+ if (!name[0])
+ strcpy ( name,label_atom_id );
+ // (4)
+ CIFGetString ( altLoc,Loop,CIFTAG_LABEL_ALT_ID ,k,
+ sizeof(altLoc),pstr("") );
+
+ // (11,12,13)
+ RC = CIFGetReal1 ( x,Loop,CIFTAG_CARTN_X,k );
+ if (!RC) RC = CIFGetReal1 ( y,Loop,CIFTAG_CARTN_Y,k );
+ if (!RC) RC = CIFGetReal1 ( z,Loop,CIFTAG_CARTN_Z,k );
+ if (RC) return Error_ATOM_Unrecognized;
+ WhatIsSet |= ASET_Coordinates;
+
+ // (14)
+ if (!CIFGetReal1(occupancy,Loop,CIFTAG_OCCUPANCY,k))
+ WhatIsSet |= ASET_Occupancy;
+ // (15)
+ if (!CIFGetReal1(tempFactor,Loop,CIFTAG_B_ISO_OR_EQUIV,k))
+ WhatIsSet |= ASET_tempFactor;
+
+ // (10)
+ CIFGetString ( segID,Loop,CIFTAG_SEGMENT_ID,k,
+ sizeof(segID) ,pstr("") );
+ // (21)
+ if (!CIFGetReal1(charge,Loop,CIFTAG_PDBX_FORMAL_CHARGE,k))
+ WhatIsSet |= ASET_Charge;
+ // (2)
+ RC = CIFGetString ( element,Loop,CIFTAG_TYPE_SYMBOL,k,
+ sizeof(element),pstr("") );
+ if (RC)
+ CIFGetString ( element,Loop,CIFTAG_ATOM_TYPE_SYMBOL,k,
+ sizeof(element),pstr("") );
+
+ RestoreElementName();
+ MakePDBAtomName();
+
+ // (16,17,18)
+ RC = CIFGetReal1 ( sigX,Loop,CIFTAG_CARTN_X_ESD,k );
+ if (!RC) RC = CIFGetReal1 ( sigY,Loop,CIFTAG_CARTN_Y_ESD,k );
+ if (!RC) RC = CIFGetReal1 ( sigZ,Loop,CIFTAG_CARTN_Z_ESD,k );
+ if (RC==Error_UnrecognizedReal)
+ return RC;
+ if (!RC) WhatIsSet |= ASET_CoordSigma;
+
+ // (19)
+ if (!CIFGetReal1(sigOcc,Loop,CIFTAG_OCCUPANCY_ESD,k))
+ WhatIsSet |= ASET_OccSigma;
+ // (20)
+ if (!CIFGetReal1(sigTemp,Loop,CIFTAG_B_ISO_OR_EQUIV_ESD,k))
+ WhatIsSet |= ASET_tFacSigma;
+
+ Loop->DeleteRow ( k );
+
+ if (LoopAnis) {
+
+ RC = CIFGetReal1 ( u11,LoopAnis,CIFTAG_U11,k );
+ if (!RC) RC = CIFGetReal1 ( u22,LoopAnis,CIFTAG_U22,k );
+ if (!RC) RC = CIFGetReal1 ( u33,LoopAnis,CIFTAG_U33,k );
+ if (!RC) RC = CIFGetReal1 ( u13,LoopAnis,CIFTAG_U13,k );
+ if (!RC) RC = CIFGetReal1 ( u12,LoopAnis,CIFTAG_U12,k );
+ if (!RC) RC = CIFGetReal1 ( u23,LoopAnis,CIFTAG_U23,k );
+ if (RC==Error_UnrecognizedReal)
+ return RC;
+ if (!RC) WhatIsSet |= ASET_Anis_tFac;
+
+ RC = CIFGetReal1 ( su11,LoopAnis,CIFTAG_U11_ESD,k );
+ if (!RC) RC = CIFGetReal1 ( su22,LoopAnis,CIFTAG_U22_ESD,k );
+ if (!RC) RC = CIFGetReal1 ( su33,LoopAnis,CIFTAG_U33_ESD,k );
+ if (!RC) RC = CIFGetReal1 ( su13,LoopAnis,CIFTAG_U13_ESD,k );
+ if (!RC) RC = CIFGetReal1 ( su12,LoopAnis,CIFTAG_U12_ESD,k );
+ if (!RC) RC = CIFGetReal1 ( su23,LoopAnis,CIFTAG_U23_ESD,k );
+ if (RC==Error_UnrecognizedReal)
+ return RC;
+ if (!RC) WhatIsSet |= ASET_Anis_tFSigma;
+
+ LoopAnis->DeleteRow ( k );
+
+ }
+
+ return Error_NoError;
+
+ }
+
+ bool Atom::RestoreElementName() {
+ // This function works only if element name is not given.
+
+ if (Ter) {
+ name[0] = char(0);
+ element[0] = char(0);
+ return false;
+ }
+ if ((!element[0]) ||
+ ((element[0]==' ') && ((!element[1]) || (element[1]==' ')))) {
+ if (strlen(name)==4) {
+ if ((name[0]>='A') && (name[0]<='Z')) {
+ element[0] = name[0];
+ element[1] = name[1];
+ } else {
+ element[0] = ' ';
+ element[1] = name[1];
+ }
+ } else { // nasty hack for mmcif files without element column
+ element[0] = ' ';
+ element[1] = name[0];
+ }
+ element[2] = char(0);
+ return false;
+ } else if (!element[1]) {
+ // not aligned element name, possibly coming from mmCIF
+ element[1] = element[0];
+ element[0] = ' ';
+ element[2] = char(0);
+ return false;
+ }
+ return true;
+ }
+
+ bool Atom::MakePDBAtomName() {
+ int i,k;
+
+ if (Ter) {
+ name [0] = char(0);
+ element[0] = char(0);
+ return false;
+ }
+ UpperCase ( name );
+ UpperCase ( element );
+ if ((element[0]==' ') && (element[1]==' ')) {
+ // element name not given, make one from the atom name
+ if ((name[0]>='A') && (name[0]<='Z')) {
+ if (!name[1]) {
+ name[4] = char(0);
+ name[3] = ' ';
+ name[2] = ' ';
+ name[1] = name[0];
+ name[0] = ' ';
+ }
+ /* the commented part looks like a wrong inheritance
+ from FORTRAN RWBrook. Commented on 04.03.2004,
+ to be removed.
+ else if ((name[0]=='C') && (name[1]=='A')) {
+ name[4] = char(0);
+ name[3] = name[2];
+ name[2] = name[1];
+ name[1] = name[0];
+ name[0] = ' ';
+ }
+ */
+ element[0] = name[0];
+ element[1] = name[1];
+ } else {
+ element[0] = ' ';
+ element[1] = name[1];
+ }
+ element[2] = char(0);
+ return false;
+ } else if ((name[0]>='A') && (name[0]<='Z')) {
+ if (!element[1]) {
+ element[2] = char(0);
+ element[1] = element[0];
+ element[0] = ' ';
+ k = strlen(name);
+ if (k<4) {
+ for (i=3;i>0;i--)
+ name[i] = name[i-1];
+ name[0] = ' ';
+ k++;
+ while (k<4)
+ name[k++] = ' ';
+ name[k] = char(0);
+ }
+ } else if ((element[0]==' ') && (element[1]!=name[1])) {
+ for (i=3;i>0;i--)
+ name[i] = name[i-1];
+ name[0] = ' ';
+ name[4] = char(0);
+ k = strlen(name);
+ while (k<4)
+ name[k++] = ' ';
+ name[k] = char(0);
+ } else {
+ k = strlen(name);
+ while (k<4)
+ name[k++] = ' ';
+ name[k] = char(0);
+ }
+ }
+ return true;
+ }
+
+ void Atom::SetCoordinates ( realtype xx, realtype yy, realtype zz,
+ realtype occ, realtype tFac ) {
+ x = xx;
+ y = yy;
+ z = zz;
+ occupancy = occ;
+ tempFactor = tFac;
+ WhatIsSet |= ASET_Coordinates | ASET_Occupancy | ASET_tempFactor;
+ }
+
+ void Atom::Transform ( mat33 & tm, vect3 & v ) {
+ realtype x1,y1,z1;
+ x1 = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + v[0];
+ y1 = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + v[1];
+ z1 = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + v[2];
+ x = x1;
+ y = y1;
+ z = z1;
+ }
+
+ void Atom::Transform ( mat44 & tm ) {
+ realtype x1,y1,z1;
+ x1 = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + tm[0][3];
+ y1 = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + tm[1][3];
+ z1 = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + tm[2][3];
+ x = x1;
+ y = y1;
+ z = z1;
+ }
+
+ void Atom::TransformCopy ( mat44 & tm,
+ realtype & xx,
+ realtype & yy,
+ realtype & zz ) {
+ xx = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + tm[0][3];
+ yy = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + tm[1][3];
+ zz = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + tm[2][3];
+ }
+
+ void Atom::TransformSet ( mat44 & tm,
+ realtype xx,
+ realtype yy,
+ realtype zz ) {
+ x = tm[0][0]*xx + tm[0][1]*yy + tm[0][2]*zz + tm[0][3];
+ y = tm[1][0]*xx + tm[1][1]*yy + tm[1][2]*zz + tm[1][3];
+ z = tm[2][0]*xx + tm[2][1]*yy + tm[2][2]*zz + tm[2][3];
+ }
+
+
+ // ------- user-defined data handlers
+
+ int Atom::PutUDData ( int UDDhandle, int iudd ) {
+ if (UDDhandle & UDRF_ATOM)
+ return UDData::putUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Atom::PutUDData ( int UDDhandle, realtype rudd ) {
+ if (UDDhandle & UDRF_ATOM)
+ return UDData::putUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Atom::PutUDData ( int UDDhandle, cpstr sudd ) {
+ if (UDDhandle & UDRF_ATOM)
+ return UDData::putUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Atom::GetUDData ( int UDDhandle, int & iudd ) {
+ if (UDDhandle & UDRF_ATOM)
+ return UDData::getUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Atom::GetUDData ( int UDDhandle, realtype & rudd ) {
+ if (UDDhandle & UDRF_ATOM)
+ return UDData::getUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Atom::GetUDData ( int UDDhandle, pstr sudd, int maxLen ) {
+ if (UDDhandle & UDRF_ATOM)
+ return UDData::getUDData ( UDDhandle,sudd,maxLen );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Atom::GetUDData ( int UDDhandle, pstr & sudd ) {
+ if (UDDhandle & UDRF_ATOM)
+ return UDData::getUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+
+ void Atom::Copy ( PAtom atom ) {
+ // this does not make any references in residues and does
+ // not change indices!! it does change serial numbers, though.
+
+ serNum = atom->serNum;
+ x = atom->x;
+ y = atom->y;
+ z = atom->z;
+ occupancy = atom->occupancy;
+ tempFactor = atom->tempFactor;
+ sigX = atom->sigX;
+ sigY = atom->sigY;
+ sigZ = atom->sigZ;
+ sigOcc = atom->sigOcc;
+ sigTemp = atom->sigTemp;
+ u11 = atom->u11;
+ u22 = atom->u22;
+ u33 = atom->u33;
+ u12 = atom->u12;
+ u13 = atom->u13;
+ u23 = atom->u23;
+ su11 = atom->su11;
+ su22 = atom->su22;
+ su33 = atom->su33;
+ su12 = atom->su12;
+ su13 = atom->su13;
+ su23 = atom->su23;
+ Het = atom->Het;
+ Ter = atom->Ter;
+ WhatIsSet = atom->WhatIsSet;
+
+ strcpy ( name ,atom->name );
+ strcpy ( label_atom_id,atom->label_atom_id );
+ strcpy ( altLoc ,atom->altLoc );
+ strcpy ( segID ,atom->segID );
+ strcpy ( element ,atom->element );
+ strcpy ( energyType ,atom->energyType );
+ charge = atom->charge;
+
+ }
+
+ int Atom::CheckID ( const AtomName aname, const Element elname,
+ const AltLoc aloc ) {
+ pstr p1,p2;
+ if (aname) {
+ if (aname[0]!='*') {
+ p1 = name;
+ while (*p1==' ') p1++;
+ p2 = pstr(aname);
+ while (*p2==' ') p2++;
+ while ((*p2) && (*p1) && (*p1!=' ') && (*p2!=' ')) {
+ if (*p1!=*p2) return 0;
+ p1++;
+ p2++;
+ }
+ if (*p1!=*p2) {
+ if (((*p1) && (*p1!=' ')) ||
+ ((*p2) && (*p2!=' '))) return 0;
+ }
+ }
+ }
+ if (elname) {
+ if (elname[0]!='*') {
+ p1 = element;
+ while (*p1==' ') p1++;
+ p2 = pstr(elname);
+ while (*p2==' ') p2++;
+ while ((*p2) && (*p1) && (*p1!=' ') && (*p2!=' ')) {
+ if (*p1!=*p2) return 0;
+ p1++;
+ p2++;
+ }
+ if (*p1!=*p2) return 0;
+ }
+ }
+ if (aloc) {
+ if ((aloc[0]!='*') && (strcmp(aloc,altLoc))) return 0;
+ }
+ return 1;
+ }
+
+ int Atom::CheckIDS ( cpstr ID ) {
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+ pstr p;
+ p = strrchr ( ID,'/' );
+ if (p) p++;
+ else p = pstr(ID);
+ ParseAtomID ( p,aname,elname,aloc );
+ return CheckID ( aname,elname,aloc );
+ }
+
+ void Atom::SetShortBinary() {
+ WhatIsSet |= ASET_ShortBinary;
+ }
+
+ void Atom::write ( io::RFile f ) {
+ int i,k;
+ byte Version=2;
+ byte nb;
+
+ f.WriteWord ( &WhatIsSet );
+ if (WhatIsSet & ASET_ShortBinary) {
+ if (Ter) WhatIsSet |= ASET_ShortTer;
+ if (Het) WhatIsSet |= ASET_ShortHet;
+ f.WriteInt ( &index );
+ f.WriteTerLine ( name ,false );
+ f.WriteTerLine ( altLoc ,false );
+ f.WriteTerLine ( element,false );
+ if (WhatIsSet & ASET_Coordinates) {
+ f.WriteFloat ( &x );
+ f.WriteFloat ( &y );
+ f.WriteFloat ( &z );
+ }
+ return;
+ }
+
+ f.WriteByte ( &Version );
+
+ UDData::write ( f );
+
+ f.WriteInt ( &serNum );
+ f.WriteInt ( &index );
+ f.WriteTerLine ( name ,false );
+ f.WriteTerLine ( label_atom_id,false );
+ f.WriteTerLine ( altLoc ,false );
+ f.WriteTerLine ( segID ,false );
+ f.WriteTerLine ( element ,false );
+ f.WriteTerLine ( energyType ,false );
+ f.WriteFloat ( &charge );
+ f.WriteBool ( &Het );
+ f.WriteBool ( &Ter );
+
+ if (WhatIsSet & ASET_Coordinates) {
+ f.WriteFloat ( &x );
+ f.WriteFloat ( &y );
+ f.WriteFloat ( &z );
+ if (WhatIsSet & ASET_Occupancy)
+ f.WriteFloat ( &occupancy );
+ if (WhatIsSet & ASET_tempFactor)
+ f.WriteFloat ( &tempFactor );
+ }
+
+ if (WhatIsSet & ASET_CoordSigma) {
+ f.WriteFloat ( &sigX );
+ f.WriteFloat ( &sigY );
+ f.WriteFloat ( &sigZ );
+ if ((WhatIsSet & ASET_Occupancy) &&
+ (WhatIsSet & ASET_OccSigma))
+ f.WriteFloat ( &sigOcc );
+ if ((WhatIsSet & ASET_tempFactor) &&
+ (WhatIsSet & ASET_tFacSigma))
+ f.WriteFloat ( &sigTemp );
+ }
+
+ if (WhatIsSet & ASET_Anis_tFac) {
+ f.WriteFloat ( &u11 );
+ f.WriteFloat ( &u22 );
+ f.WriteFloat ( &u33 );
+ f.WriteFloat ( &u12 );
+ f.WriteFloat ( &u13 );
+ f.WriteFloat ( &u23 );
+ if (WhatIsSet & ASET_Anis_tFSigma) {
+ f.WriteFloat ( &su11 );
+ f.WriteFloat ( &su22 );
+ f.WriteFloat ( &su33 );
+ f.WriteFloat ( &su12 );
+ f.WriteFloat ( &su13 );
+ f.WriteFloat ( &su23 );
+ }
+ }
+
+ nb = byte(nBonds & 0x000000FF);
+ f.WriteByte ( &nb );
+ for (i=0;i<nb;i++)
+ if (Bond[i].atom) {
+ f.WriteInt ( &(Bond[i].atom->index) );
+ f.WriteByte ( &(Bond[i].order) );
+ } else {
+ k = -1;
+ f.WriteInt ( &k );
+ }
+
+ }
+
+ void Atom::read ( io::RFile f ) {
+ int i,k;
+ byte nb,Version;
+
+ FreeMemory();
+
+ f.ReadWord ( &WhatIsSet );
+ if (WhatIsSet & ASET_ShortBinary) {
+ f.ReadInt ( &index );
+ f.ReadTerLine ( name ,false );
+ f.ReadTerLine ( altLoc ,false );
+ f.ReadTerLine ( element,false );
+ if (WhatIsSet & ASET_Coordinates) {
+ f.ReadFloat ( &x );
+ f.ReadFloat ( &y );
+ f.ReadFloat ( &z );
+ }
+ serNum = index;
+ Ter = WhatIsSet & ASET_ShortTer;
+ Het = WhatIsSet & ASET_ShortHet;
+ name [4] = char(0);
+ altLoc [1] = char(0);
+ element[2] = char(0);
+ segID [0] = char(0);
+ charge = 0.0;
+ WhatIsSet &= ASET_All;
+ return;
+ }
+
+ f.ReadByte ( &Version );
+
+ UDData::read ( f );
+
+ f.ReadInt ( &serNum );
+ f.ReadInt ( &index );
+ f.ReadTerLine ( name ,false );
+ if (Version>1)
+ f.ReadTerLine ( label_atom_id,false );
+ f.ReadTerLine ( altLoc ,false );
+ f.ReadTerLine ( segID ,false );
+ f.ReadTerLine ( element ,false );
+ f.ReadTerLine ( energyType,false );
+ f.ReadFloat ( &charge );
+ f.ReadBool ( &Het );
+ f.ReadBool ( &Ter );
+
+ if (WhatIsSet & ASET_Coordinates) {
+ f.ReadFloat ( &x );
+ f.ReadFloat ( &y );
+ f.ReadFloat ( &z );
+ if (WhatIsSet & ASET_Occupancy) f.ReadFloat ( &occupancy );
+ else occupancy = 0.0;
+ if (WhatIsSet & ASET_tempFactor) f.ReadFloat ( &tempFactor );
+ else tempFactor = 0.0;
+ } else {
+ x = 0.0;
+ y = 0.0;
+ z = 0.0;
+ occupancy = 0.0;
+ tempFactor = 0.0;
+ }
+
+ if (WhatIsSet & ASET_CoordSigma) {
+ f.ReadFloat ( &sigX );
+ f.ReadFloat ( &sigY );
+ f.ReadFloat ( &sigZ );
+ if ((WhatIsSet & ASET_Occupancy) &&
+ (WhatIsSet & ASET_OccSigma))
+ f.ReadFloat ( &sigOcc );
+ else sigOcc = 0.0;
+ if ((WhatIsSet & ASET_tempFactor) &&
+ (WhatIsSet & ASET_tFacSigma))
+ f.ReadFloat ( &sigTemp );
+ else sigTemp = 0.0;
+ } else {
+ sigX = 0.0;
+ sigY = 0.0;
+ sigZ = 0.0;
+ sigOcc = 0.0;
+ sigTemp = 0.0;
+ }
+
+ if (WhatIsSet & ASET_Anis_tFac) {
+ f.ReadFloat ( &u11 );
+ f.ReadFloat ( &u22 );
+ f.ReadFloat ( &u33 );
+ f.ReadFloat ( &u12 );
+ f.ReadFloat ( &u13 );
+ f.ReadFloat ( &u23 );
+ if (WhatIsSet & ASET_Anis_tFSigma) {
+ f.ReadFloat ( &su11 );
+ f.ReadFloat ( &su22 );
+ f.ReadFloat ( &su33 );
+ f.ReadFloat ( &su12 );
+ f.ReadFloat ( &su13 );
+ f.ReadFloat ( &su23 );
+ } else {
+ su11 = 0.0;
+ su22 = 0.0;
+ su33 = 0.0;
+ su12 = 0.0;
+ su13 = 0.0;
+ su23 = 0.0;
+ }
+ } else {
+ u11 = 0.0;
+ u22 = 0.0;
+ u33 = 0.0;
+ u12 = 0.0;
+ u13 = 0.0;
+ u23 = 0.0;
+ su11 = 0.0;
+ su22 = 0.0;
+ su33 = 0.0;
+ su12 = 0.0;
+ su13 = 0.0;
+ su23 = 0.0;
+ }
+
+ f.ReadByte ( &nb );
+ if (nb>0) {
+ Bond = new AtomBond[nb];
+ for (i=0;i<nb;i++) {
+ f.ReadInt ( &k );
+ if (k>0) f.ReadByte ( &(Bond[i].order) );
+ else Bond[i].order = 0;
+ // we place *index* of bonded atom temporary on the place
+ // of its pointer, and the pointer will be calculated
+ // after Residue::read calls _setBonds(..).
+ memcpy ( &(Bond[i].atom),&k,4 );
+ }
+ }
+ nBonds = nb;
+ nBonds = nBonds | (nBonds << 8);
+
+ }
+
+ void Atom::_setBonds ( PPAtom A ) {
+ int i,k,nb;
+ nb = nBonds & 0x000000FF;
+ for (i=0;i<nb;i++) {
+ memcpy ( &k,&(Bond[i].atom),4 );
+ if (k>0) Bond[i].atom = A[k];
+ else Bond[i].atom = NULL;
+ }
+ }
+
+
+ MakeFactoryFunctions(Atom)
+
+
+
+ // =========================== Residue ===========================
+
+
+ void AtomStat::Init() {
+
+ nAtoms = 0;
+
+ xmin = MaxReal; xmax = MinReal; xm = 0.0; xm2 = 0.0;
+ ymin = MaxReal; ymax = MinReal; ym = 0.0; ym2 = 0.0;
+ zmin = MaxReal; zmax = MinReal; zm = 0.0; zm2 = 0.0;
+
+ occ_min = MaxReal; occ_max = MinReal; occ_m = 0.0; occ_m2 = 0.0;
+ tFmin = MaxReal; tFmax = MinReal; tFm = 0.0; tFm2 = 0.0;
+
+ u11_min = MaxReal; u11_max = MinReal; u11_m = 0.0; u11_m2 = 0.0;
+ u22_min = MaxReal; u22_max = MinReal; u22_m = 0.0; u22_m2 = 0.0;
+ u33_min = MaxReal; u33_max = MinReal; u33_m = 0.0; u33_m2 = 0.0;
+ u12_min = MaxReal; u12_max = MinReal; u12_m = 0.0; u12_m2 = 0.0;
+ u13_min = MaxReal; u13_max = MinReal; u13_m = 0.0; u13_m2 = 0.0;
+ u23_min = MaxReal; u23_max = MinReal; u23_m = 0.0; u23_m2 = 0.0;
+
+ WhatIsSet = ASET_All;
+
+ finished = false;
+
+ }
+
+ void AtomStat::Finish() {
+ realtype v;
+
+ if (!finished) {
+
+ finished = true;
+
+ if (nAtoms>0) {
+
+ v = nAtoms;
+
+ xm /= v; xm2 /= v;
+ ym /= v; ym2 /= v;
+ zm /= v; zm2 /= v;
+
+ occ_m /= v; occ_m2 /= v;
+ tFm /= v; tFm2 /= v;
+
+ u11_m /= v; u11_m2 /= v;
+ u22_m /= v; u22_m2 /= v;
+ u33_m /= v; u33_m2 /= v;
+ u12_m /= v; u12_m2 /= v;
+ u13_m /= v; u13_m2 /= v;
+ u23_m /= v; u23_m2 /= v;
+ }
+ }
+
+ }
+
+ realtype AtomStat::GetMaxSize() {
+ realtype r;
+ r = RMax(xmax-xmin,ymax-ymin);
+ r = RMax(r,zmax-zmin);
+ return RMax(r,0.0);
+ }
+
+
+ // ----------------------------------------------------------------
+
+
+ Residue::Residue() : UDData() {
+ InitResidue();
+ }
+
+ Residue::Residue ( PChain Chain_Owner ) : UDData() {
+ InitResidue();
+ if (Chain_Owner)
+ Chain_Owner->AddResidue ( this );
+ }
+
+ Residue::Residue ( PChain Chain_Owner,
+ const ResName resName,
+ int sqNum,
+ const InsCode ins ) : UDData() {
+ InitResidue();
+ seqNum = sqNum;
+ strcpy_css ( name,pstr(resName) );
+ strcpy_css ( insCode,pstr(ins) );
+ if (Chain_Owner)
+ Chain_Owner->AddResidue ( this );
+ }
+
+ Residue::Residue ( io::RPStream Object ) : UDData(Object) {
+ InitResidue();
+ }
+
+ Residue::~Residue() {
+ FreeMemory();
+ if (chain) chain->_ExcludeResidue ( name,seqNum,insCode );
+ }
+
+
+ void Residue::InitResidue() {
+ strcpy ( name ,"---" ); // residue name
+ strcpy ( label_comp_id,"---" ); // assigned residue name
+ label_asym_id[0] = char(0); // assigned chain Id
+ seqNum = -MaxInt; // residue sequence number
+ label_seq_id = -MaxInt; // assigned residue sequence number
+ label_entity_id = 1; // assigned entity id
+ strcpy ( insCode,"" ); // residue insertion code
+ chain = NULL; // reference to chain
+ index = -1; // undefined index in chain
+ nAtoms = 0; // number of atoms in the residue
+ AtmLen = 0; // length of atom array
+ atom = NULL; // array of atoms
+ Exclude = true;
+ SSE = SSE_None;
+ }
+
+ void Residue::SetChain ( PChain Chain_Owner ) {
+ chain = Chain_Owner;
+ }
+
+
+ int Residue::GetResidueNo() {
+ if (chain) return chain->GetResidueNo ( seqNum,insCode );
+ else return -1;
+ }
+
+ void Residue::SetChainID ( const ChainID chID ) {
+ if (chain)
+ chain->SetChainID ( chID );
+ }
+
+
+ int Residue::GetCenter ( realtype & x, realtype & y,
+ realtype & z ) {
+ int i,k;
+ x = 0.0;
+ y = 0.0;
+ z = 0.0;
+ k = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter) {
+ x += atom[i]->x;
+ y += atom[i]->y;
+ z += atom[i]->z;
+ k++;
+ }
+ }
+ if (k>0) {
+ x /= k;
+ y /= k;
+ z /= k;
+ return 0;
+ }
+ return 1;
+ }
+
+ void * Residue::GetCoordHierarchy() {
+ if (chain) return chain->GetCoordHierarchy();
+ return NULL;
+ }
+
+ void Residue::GetAltLocations ( int & nAltLocs,
+ PAltLoc & aLoc,
+ rvector & occupancy,
+ int & alflag ) {
+ int i,j,k, nal,nal1;
+ realtype occ1;
+ bool B;
+ PAltLoc aL;
+ rvector occ;
+ bvector alv;
+
+ aLoc = NULL;
+ occupancy = NULL;
+ nAltLocs = 0;
+ alflag = ALF_NoAltCodes;
+
+ if (nAtoms>0) {
+
+ // temporary array for altcodes
+ aL = new AltLoc[nAtoms];
+ // temporary array for occupancies
+ GetVectorMemory ( occ,nAtoms,0 );
+ // temporary array for checking altcodes
+ GetVectorMemory ( alv,nAtoms,0 );
+ for (i=0;i<nAtoms;i++)
+ alv[i] = false;
+
+ k = 0; // counts unique alternation codes
+ nal = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter) {
+ // Find if the alternation code of ith atom is
+ // a new one.
+ B = false;
+ for (j=0;(j<k) && (!B);j++)
+ B = !strcmp(atom[i]->altLoc,aL[j]);
+ if (!B) {
+ // that's a new altcode, get its occupancy
+ if (atom[i]->WhatIsSet & ASET_Occupancy)
+ occ[k] = atom[i]->occupancy;
+ else occ[k] = -1.0;
+ // store new altcode in temporary array
+ strcpy ( aL[k],atom[i]->altLoc );
+ // check consistency of the altcode data if:
+ // a) the data was not found wrong so far
+ // b) this atom name has not been checked before
+ // c) altcode is not the "empty"-altcode
+ if ((!(alflag & ALF_Mess)) && (!alv[i]) &&
+ (atom[i]->altLoc[0])) {
+ B = false; // will be set true if "empty"-altcode
+ // is found for current atom name
+ nal1 = 0; // counts the number of different altcodes
+ // for current atom name
+ occ1 = 0.0; // will count the sum of occupancies for
+ // current atom name
+ for (j=0;j<nAtoms;j++)
+ if (atom[j]) {
+ if ((!atom[j]->Ter) &&
+ (!strcmp(atom[j]->name,atom[i]->name))) {
+ if (atom[j]->WhatIsSet & ASET_Occupancy)
+ occ1 += atom[j]->occupancy;
+ if (!atom[j]->altLoc[0]) B = true;
+ alv[j] = true; // mark it as "checked"
+ nal1++;
+ }
+ }
+ if (!(alflag & (ALF_EmptyAltLoc | ALF_NoEmptyAltLoc))) {
+ if (B) alflag |= ALF_EmptyAltLoc;
+ else alflag |= ALF_NoEmptyAltLoc;
+ } else if (((alflag & ALF_EmptyAltLoc) && (!B)) ||
+ ((alflag & ALF_NoEmptyAltLoc) && (B)))
+ alflag |= ALF_Mess;
+ if ((occ[k]>=0) && (fabs(1.0-occ1)>0.01))
+ alflag |= ALF_Occupancy;
+ if (nal==0) // first time just remember the number
+ nal = nal1; // of different altcodes
+ else if (nal!=nal1) // check if number of different altcodes
+ alflag |= ALF_Mess; // is not the same through the residue
+ }
+ k++;
+ }
+ }
+ }
+ if (k>0) {
+ aLoc = new AltLoc[k];
+ GetVectorMemory ( occupancy,k,0 );
+ for (i=0;i<k;i++) {
+ strcpy ( aLoc[i],aL[i] );
+ occupancy[i] = occ[i];
+ }
+ nAltLocs = k;
+ }
+
+ delete[] aL;
+ FreeVectorMemory ( occ,0 );
+ FreeVectorMemory ( alv,0 );
+
+ }
+
+ }
+
+ int Residue::GetNofAltLocations() {
+ int i,j,k;
+ bool B;
+ k = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter) {
+ B = false;
+ for (j=0;(j<i) && (!B);j++)
+ if (atom[j]) {
+ if (!atom[j]->Ter)
+ B = !strcmp(atom[i]->altLoc,atom[j]->altLoc);
+ }
+ if (!B) k++;
+ }
+ }
+ return k;
+ }
+
+ void Residue::SetResID ( const ResName resName, int sqNum,
+ const InsCode ins ) {
+ strcpy_css ( name,pstr(resName) );
+ seqNum = sqNum;
+ strcpy_css ( insCode,pstr(ins) );
+ strcpy (label_comp_id,name );
+ }
+
+ void Residue::FreeMemory() {
+ // NOTE: individual atoms are disposed here as well!
+ DeleteAllAtoms();
+ if (atom) delete[] atom;
+ atom = NULL;
+ nAtoms = 0;
+ AtmLen = 0;
+ }
+
+ void Residue::ExpandAtomArray ( int nAdd ) {
+ int i;
+ PPAtom atom1;
+ AtmLen += abs(nAdd);
+ atom1 = new PAtom[AtmLen];
+ for (i=0;i<nAtoms;i++)
+ atom1[i] = atom[i];
+ for (i=nAtoms;i<AtmLen;i++)
+ atom1[i] = NULL;
+ if (atom) delete[] atom;
+ atom = atom1;
+ }
+
+ int Residue::_AddAtom ( PAtom atm ) {
+ // Adds atom to the residue
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]==atm) return -i; // this atom is already there
+ if (nAtoms>=AtmLen)
+ ExpandAtomArray ( nAtoms+10-AtmLen );
+ atom[nAtoms] = atm;
+ atom[nAtoms]->residue = this;
+ nAtoms++;
+ return 0;
+ }
+
+ int Residue::AddAtom ( PAtom atm ) {
+ // AddAtom(..) adds atom to the residue. If residue is associated
+ // with a coordinate hierarchy, and atom 'atm' is not, the latter
+ // is checked in automatically. If atom 'atm' belongs to any
+ // coordinate hierarchy (even though that of the residue), it is
+ // *copied* rather than simply taken over, and is checked in.
+ // If residue is not associated with a coordinate hierarchy, all
+ // added atoms will be checked in automatically once the residue
+ // is checked in.
+ PRoot manager;
+ PResidue res;
+ int i;
+
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]==atm) return -i; // this atom is already there
+
+ if (nAtoms>=AtmLen)
+ ExpandAtomArray ( nAtoms+10-AtmLen );
+
+ if (atm->GetCoordHierarchy()) {
+ atom[nAtoms] = newAtom();
+ atom[nAtoms]->Copy ( atm );
+ } else {
+ res = atm->GetResidue();
+ if (res)
+ for (i=0;i<res->nAtoms;i++)
+ if (res->atom[i]==atm) {
+ res->atom[i] = NULL;
+ break;
+ }
+ atom[nAtoms] = atm;
+ }
+
+ atom[nAtoms]->residue = this;
+ manager = PRoot(GetCoordHierarchy());
+ if (manager)
+ manager->CheckInAtom ( 0,atom[nAtoms] );
+
+ nAtoms++;
+
+ return nAtoms;
+
+ }
+
+ int Residue::InsertAtom ( PAtom atm, int position ) {
+ // InsertAtom(..) inserts atom into the specified position of
+ // the residue. If residue is associated with a coordinate hierarchy,
+ // and atom 'atm' is not, the latter is checked in automatically.
+ // If atom 'atm' belongs to any coordinate hierarchy (even though
+ // that of the residue), it is *copied* rather than simply taken
+ // over, and is checked in.
+ // If residue is not associated with a coordinate hierarchy, all
+ // added atoms will be checked in automatically once the residue
+ // is checked in.
+ PRoot manager;
+ PResidue res;
+ int i,pos;
+
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]==atm) return -i; // this atom is already there
+
+ if (nAtoms>=AtmLen)
+ ExpandAtomArray ( nAtoms+10-AtmLen );
+
+ pos = IMin(position,nAtoms);
+ for (i=nAtoms;i>pos;i--)
+ atom[i] = atom[i-1];
+
+ if (atm->GetCoordHierarchy()) {
+ atom[pos] = newAtom();
+ atom[pos]->Copy ( atm );
+ } else {
+ res = atm->GetResidue();
+ if (res)
+ for (i=0;i<res->nAtoms;i++)
+ if (res->atom[i]==atm) {
+ res->atom[i] = NULL;
+ break;
+ }
+ atom[pos] = atm;
+ }
+
+ atom[pos]->residue = this;
+ manager = PRoot(GetCoordHierarchy());
+ if (manager)
+ manager->CheckInAtom ( 0,atom[pos] );
+
+ nAtoms++;
+
+ return nAtoms;
+
+ }
+
+ int Residue::InsertAtom ( PAtom atm, const AtomName aname ) {
+ // This version inserts before the atom with given name. If such
+ // name is not found, the atom is appended to the end.
+ int i;
+ i = 0;
+ while (i<nAtoms)
+ if (!atom[i]) i++;
+ else if (!strcmp(aname,atom[i]->name)) break;
+ else i++;
+ return InsertAtom ( atm,i );
+ }
+
+
+ void Residue::CheckInAtoms() {
+ PRoot manager;
+ int i;
+ manager = PRoot(GetCoordHierarchy());
+ if (manager)
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (atom[i]->index<0)
+ manager->CheckInAtom ( 0,atom[i] );
+ }
+ }
+
+
+ int Residue::_ExcludeAtom ( int kndex ) {
+ // deletes atom from the residue
+ int i,k;
+
+ if (!Exclude) return 0;
+
+ k = -1;
+ for (i=0;(i<nAtoms) && (k<0);i++)
+ if (atom[i]) {
+ if (atom[i]->index==kndex) k = i;
+ }
+
+ if (k>=0) {
+ for (i=k+1;i<nAtoms;i++)
+ atom[i-1] = atom[i];
+ nAtoms--;
+ }
+
+ if (nAtoms<=0) return 1;
+ else return 0;
+
+ }
+
+
+ void Residue::PDBASCIIAtomDump ( io::RFile f ) {
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i])
+ atom[i]->PDBASCIIDump ( f );
+ }
+
+ void Residue::MakeAtomCIF ( mmcif::PData CIF ) {
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i])
+ atom[i]->MakeCIF ( CIF );
+ }
+
+
+ void Residue::Copy ( PResidue res ) {
+ //
+ // Modify Residue::Copy and both Residues::_copy methods
+ // simultaneously!
+ //
+ // This function will nake a copy of residue res in 'this' one.
+ // All atoms are copied, none is moved regardless to the association
+ // with coordinate hierarchy. If 'this' residue is associated with
+ // a coordinate hierarchy, all atoms are checked in.
+ PRoot manager;
+ int i;
+
+ FreeMemory();
+
+ seqNum = res->seqNum;
+ label_seq_id = res->label_seq_id;
+ label_entity_id = res->label_entity_id;
+ index = res->index;
+ AtmLen = res->nAtoms;
+ SSE = res->SSE;
+ strcpy ( name ,res->name );
+ strcpy ( label_comp_id,res->label_comp_id );
+ strcpy ( label_asym_id,res->label_asym_id );
+ strcpy ( insCode ,res->insCode );
+
+ if (AtmLen>0) {
+ atom = new PAtom[AtmLen];
+ nAtoms = 0;
+ for (i=0;i<res->nAtoms;i++)
+ if (res->atom[i]) {
+ atom[nAtoms] = newAtom();
+ atom[nAtoms]->Copy ( res->atom[i] );
+ atom[nAtoms]->SetResidue ( this );
+ nAtoms++;
+ }
+ for (i=nAtoms;i<AtmLen;i++)
+ atom[i] = NULL;
+ manager = PRoot(GetCoordHierarchy());
+ if (manager)
+ manager->CheckInAtoms ( 0,atom,nAtoms );
+ }
+
+ }
+
+
+ void Residue::_copy ( PResidue res ) {
+ // Modify both Residue::_copy and Residue::Copy methods
+ // simultaneously!
+ //
+ // will work properly only if atomic arrays
+ // this->chain->model->GetAtom() and
+ // res->chain->model->GetAtom() are identical
+ //
+ int i;
+ PPAtom A;
+
+ FreeMemory();
+
+ seqNum = res->seqNum;
+ label_seq_id = res->label_seq_id;
+ label_entity_id = res->label_entity_id;
+ index = res->index;
+ nAtoms = res->nAtoms;
+ SSE = res->SSE;
+ strcpy ( name ,res->name );
+ strcpy ( label_comp_id,res->label_comp_id );
+ strcpy ( label_asym_id,res->label_asym_id );
+ strcpy ( insCode ,res->insCode );
+
+ AtmLen = nAtoms;
+ A = NULL;
+ if (chain) {
+ if (chain->model)
+ A = chain->model->GetAllAtoms();
+ }
+ if ((nAtoms>0) && (A)) {
+ atom = new PAtom[nAtoms];
+ for (i=0;i<nAtoms;i++) {
+ atom[i] = A[res->atom[i]->index-1];
+ atom[i]->SetResidue ( this );
+ }
+ } else {
+ nAtoms = 0;
+ AtmLen = 0;
+ }
+
+ }
+
+ void Residue::_copy ( PResidue res, PPAtom atm,
+ int & atom_index ) {
+ // modify both Residue::_copy and Residue::Copy methods
+ // simultaneously!
+ //
+ // This function physically copies the atoms, creating new atom
+ // instances and putting them into array 'atm' sequentially from
+ // 'atom_index' position. 'atom_index' is modified (advanced).
+ //
+ int i;
+
+ FreeMemory();
+
+ seqNum = res->seqNum;
+ label_seq_id = res->label_seq_id;
+ label_entity_id = res->label_entity_id;
+ index = res->index;
+ nAtoms = res->nAtoms;
+ SSE = res->SSE;
+ strcpy ( name ,res->name );
+ strcpy ( label_comp_id,res->label_comp_id );
+ strcpy ( label_asym_id,res->label_asym_id );
+ strcpy ( insCode ,res->insCode );
+
+ AtmLen = nAtoms;
+ if (AtmLen>0) {
+ atom = new PAtom[AtmLen];
+ for (i=0;i<nAtoms;i++)
+ if (res->atom[i]) {
+ if (!atm[atom_index]) atm[atom_index] = newAtom();
+ atm[atom_index]->Copy ( res->atom[i] );
+ atm[atom_index]->residue = this;
+ atm[atom_index]->index = atom_index+1;
+ atom[i] = atm[atom_index];
+ atom_index++;
+ } else
+ atom[i] = NULL;
+ }
+
+ }
+
+
+ void Residue::GetAtomStatistics ( RAtomStat AS ) {
+ AS.Init();
+ CalAtomStatistics ( AS );
+ AS.Finish();
+ }
+
+ void Residue::CalAtomStatistics ( RAtomStat AS ) {
+ // AS must be initialized. The function only accumulates
+ // the statistics.
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i])
+ atom[i]->CalAtomStatistics ( AS );
+ }
+
+
+ PChain Residue::GetChain() {
+ return chain;
+ }
+
+ PModel Residue::GetModel() {
+ if (chain) return (PModel)chain->model;
+ else return NULL;
+ }
+
+
+ int Residue::GetModelNum() {
+ if (chain) {
+ if (chain->model)
+ return chain->model->GetSerNum();
+ }
+ return 0;
+ }
+
+ pstr Residue::GetChainID() {
+ if (chain) return chain->chainID;
+ return pstr("");
+ }
+
+ pstr Residue::GetLabelAsymID() {
+ return label_asym_id;
+ }
+
+ pstr Residue::GetResName() {
+ return name;
+ }
+
+ pstr Residue::GetLabelCompID() {
+ return label_comp_id;
+ }
+
+ int Residue::GetAASimilarity ( const ResName resName ) {
+ return mmdb::GetAASimilarity ( pstr(name),pstr(resName) );
+ }
+
+ int Residue::GetAASimilarity ( PResidue res ) {
+ return mmdb::GetAASimilarity ( name,res->name );
+ }
+
+ realtype Residue::GetAAHydropathy() {
+ return mmdb::GetAAHydropathy ( name );
+ }
+
+ void Residue::SetResName ( const ResName resName ) {
+ strcpy ( name,resName );
+ }
+
+ int Residue::GetSeqNum() {
+ return seqNum;
+ }
+
+ int Residue::GetLabelSeqID() {
+ return label_seq_id;
+ }
+
+ int Residue::GetLabelEntityID() {
+ return label_entity_id;
+ }
+
+ pstr Residue::GetInsCode() {
+ return insCode;
+ }
+
+ bool Residue::isAminoacid () {
+ return mmdb::isAminoacid ( name );
+ }
+
+ bool Residue::isNucleotide() {
+ return mmdb::isNucleotide ( name );
+ }
+
+ int Residue::isDNARNA() {
+ return mmdb::isDNARNA ( name );
+ }
+
+ bool Residue::isSugar() {
+ return mmdb::isSugar ( name );
+ }
+
+ bool Residue::isSolvent() {
+ return mmdb::isSolvent ( name );
+ }
+
+ bool Residue::isModRes() {
+ PChain chn;
+ PModRes modRes;
+ int nModRes,i;
+ chn = GetChain();
+ if (chn) {
+ nModRes = chn->GetNofModResidues();
+ for (i=0;i<nModRes;i++) {
+ modRes = chn->GetModResidue ( i );
+ if (modRes) {
+ if ((!strcmp(modRes->resName,name)) &&
+ (modRes->seqNum==seqNum) &&
+ (!strcmp(modRes->insCode,insCode)))
+ return true;
+ }
+ }
+
+ }
+ return false;
+ }
+
+ bool Residue::isInSelection ( int selHnd ) {
+ PRoot manager = (PRoot)GetCoordHierarchy();
+ PMask mask;
+ if (manager) {
+ mask = manager->GetSelMask ( selHnd );
+ if (mask) return CheckMask ( mask );
+ }
+ return false;
+ }
+
+
+ bool Residue::isNTerminus() {
+ PPResidue Res;
+ int i,j,nRes;
+ if (chain) {
+ chain->GetResidueTable ( Res,nRes );
+ i = 0;
+ j = -1;
+ while ((i<nRes) && (j<0)) {
+ if (Res[i]) j = i;
+ i++;
+ }
+ if (j>=0)
+ return (Res[j]->index==index);
+ }
+ return false;
+ }
+
+ bool Residue::isCTerminus() {
+ PPResidue Res;
+ int i,j,nRes;
+ if (chain) {
+ chain->GetResidueTable ( Res,nRes );
+ i = nRes-1;
+ j = -1;
+ while ((i>=0) && (j<0)) {
+ if (Res[i]) j = i;
+ i--;
+ }
+ if (j>=0)
+ return (Res[j]->index==index);
+ }
+ return false;
+ }
+
+
+ pstr Residue::GetResidueID ( pstr ResidueID ) {
+ ResidueID[0] = char(0);
+ if (chain) {
+ if (chain->model)
+ sprintf ( ResidueID,"/%i/",chain->model->GetSerNum() );
+ else strcpy ( ResidueID,"/-/" );
+ strcat ( ResidueID,chain->chainID );
+ } else
+ strcpy ( ResidueID,"/-/-" );
+ ParamStr ( ResidueID,pstr("/"),seqNum );
+ strcat ( ResidueID,"(" );
+ strcat ( ResidueID,name );
+ strcat ( ResidueID,")" );
+ if (insCode[0]) {
+ strcat ( ResidueID,"." );
+ strcat ( ResidueID,insCode );
+ }
+ return ResidueID;
+ }
+
+
+ int Residue::CheckID ( int * snum,
+ const InsCode inscode,
+ const ResName resname ) {
+ if (snum) {
+ if (*snum!=seqNum) return 0;
+ }
+ if (inscode) {
+ if ((inscode[0]!='*') && (strcmp(inscode,insCode))) return 0;
+ }
+ if (!resname) return 1;
+ if ((resname[0]!='*') && (strcmp(resname,name))) return 0;
+ return 1;
+ }
+
+ int Residue::CheckIDS ( cpstr CID ) {
+ ChainID chn;
+ InsCode inscode;
+ ResName resname;
+ AtomName atm;
+ Element elm;
+ AltLoc aloc;
+ pstr p1,p2;
+ int mdl,sn,rc;
+
+ rc = ParseAtomPath ( CID,mdl,chn,sn,inscode,resname,
+ atm,elm,aloc,NULL );
+ // rc = ParseResID ( CID,sn,inscode,resname );
+
+ if (rc>=0) {
+ p1 = NULL;
+ p2 = NULL;
+ if (inscode[0]!='*') p1 = inscode;
+ if (resname[0]!='*') p2 = resname;
+ if (!rc) return CheckID ( &sn ,p1,p2 );
+ else return CheckID ( NULL,p1,p2 );
+ }
+ return 0;
+
+ }
+
+
+ // -------------------- Extracting atoms -------------------------
+
+ int Residue::GetNumberOfAtoms() {
+ return nAtoms;
+ }
+
+ int Residue::GetNumberOfAtoms ( bool countTers ) {
+ int i,na;
+ na = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (countTers || (!atom[i]->Ter)) na++;
+ }
+ return na;
+ }
+
+ PAtom Residue::GetAtom ( const AtomName aname,
+ const Element elname,
+ const AltLoc aloc ) {
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (atom[i]->CheckID(aname,elname,aloc))
+ return atom[i];
+ }
+ return NULL;
+ }
+
+ PAtom Residue::GetAtom ( int atomNo ) {
+ if ((0<=atomNo) && (atomNo<nAtoms))
+ return atom[atomNo];
+ return NULL;
+ }
+
+ void Residue::GetAtomTable ( PPAtom & atomTable, int & NumberOfAtoms ) {
+ atomTable = atom;
+ NumberOfAtoms = nAtoms;
+ }
+
+ void Residue::GetAtomTable1 ( PPAtom & atomTable, int & NumberOfAtoms ) {
+ int i,j;
+ if (atomTable) delete[] atomTable;
+ if (nAtoms>0) {
+ atomTable = new PAtom[nAtoms];
+ j = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter)
+ atomTable[j++] = atom[i];
+ }
+ NumberOfAtoms = j;
+ } else {
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void Residue::TrimAtomTable() {
+ int i,j;
+ j = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (j<i) {
+ atom[j] = atom[i];
+ atom[i] = NULL;
+ }
+ j++;
+ }
+ nAtoms = j;
+ }
+
+
+ // --------------------- Deleting atoms --------------------------
+
+ int Residue::DeleteAtom ( const AtomName aname,
+ const Element elname,
+ const AltLoc aloc ) {
+ // apply Root::FinishStructEdit() after all editings are done!
+ // returns number of deleted atoms
+ int i,k,nA,kndex;
+ PPAtom A;
+
+ A = NULL;
+ nA = 0;
+ if (chain) {
+ if (chain->model) {
+ A = chain->model->GetAllAtoms();
+ nA = chain->model->GetNumberOfAllAtoms();
+ }
+ }
+
+ k = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (atom[i]->CheckID(aname,elname,aloc)) {
+ k++;
+ kndex = atom[i]->index;
+ if ((0<kndex) && (kndex<=nA)) A[kndex-1] = NULL;
+ Exclude = false;
+ delete atom[i];
+ atom[i] = NULL;
+ Exclude = true;
+ }
+ }
+
+ return k;
+
+ }
+
+ int Residue::DeleteAtom ( int atomNo ) {
+ // apply Root::FinishStructEdit() after all editings are done!
+ // returns number of deleted atoms
+ int kndex,nA;
+ PPAtom A;
+
+ if ((0<=atomNo) && (atomNo<nAtoms)) {
+ if (atom[atomNo]) {
+ A = NULL;
+ nA = 0;
+ if (chain) {
+ if (chain->model) {
+ A = chain->model->GetAllAtoms();
+ nA = chain->model->GetNumberOfAllAtoms();
+ }
+ }
+ kndex = atom[atomNo]->index;
+ if ((0<kndex) && (kndex<=nA)) A[kndex-1] = NULL;
+ Exclude = false;
+ delete atom[atomNo];
+ atom[atomNo] = NULL;
+ Exclude = true;
+ return 1;
+ }
+ }
+
+ return 0;
+
+ }
+
+
+ int Residue::DeleteAllAtoms() {
+ int i,k,nA,kndex;
+ PPAtom A;
+
+ Exclude = false;
+
+ A = NULL;
+ nA = 0;
+ if (chain) {
+ if (chain->model) {
+ A = chain->model->GetAllAtoms();
+ nA = chain->model->GetNumberOfAllAtoms();
+ }
+ }
+
+ k = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ k++;
+ kndex = atom[i]->index;
+ if ((0<kndex) && (kndex<=nA)) A[kndex-1] = NULL;
+ delete atom[i];
+ atom[i] = NULL;
+ }
+ nAtoms = 0;
+
+ Exclude = true;
+
+ return k;
+
+ }
+
+
+ int Residue::DeleteAltLocs() {
+ // This function leaves only alternative location with maximal
+ // occupancy, if those are equal or unspecified, the one with
+ // "least" alternative location indicator.
+ // The function returns the number of deleted atoms. The atom
+ // table remains untrimmed, so that nAtoms are wrong until that
+ // is done. Tables are trimmed by FinishStructEdit() or
+ // explicitely.
+ PPAtom A;
+ AtomName aname;
+ AltLoc aLoc,aL;
+ realtype occupancy,occ;
+ int nA,i,i1,i2,j,k,n,kndex;
+
+ A = NULL;
+ nA = 0;
+ if (chain) {
+ if (chain->model) {
+ A = chain->model->GetAllAtoms();
+ nA = chain->model->GetNumberOfAllAtoms();
+ }
+ }
+ Exclude = false;
+
+ n = 0;
+ for (i=0;i<nAtoms;i++)
+
+ if (atom[i]) {
+ if (!atom[i]->Ter) {
+ occupancy = atom[i]->GetOccupancy();
+ strcpy ( aname,atom[i]->name );
+ strcpy ( aLoc ,atom[i]->altLoc );
+ i1 = -1;
+ i2 = i;
+ k = 0;
+ for (j=i+1;j<nAtoms;j++)
+ if (atom[j]) {
+ if ((!atom[j]->Ter) && (!strcmp(atom[j]->name,aname))) {
+ k++;
+ occ = atom[j]->GetOccupancy();
+ if (occ>occupancy) {
+ occupancy = occ;
+ i1 = j;
+ }
+ if (aLoc[0]) {
+ strcpy ( aL,atom[j]->altLoc );
+ if (!aL[0]) {
+ aLoc[0] = char(0);
+ i2 = j;
+ } else if (strcmp(aL,aLoc)<0) {
+ strcpy ( aLoc,aL );
+ i2 = j;
+ }
+ }
+ }
+ }
+ if (k>0) {
+ if (i1<0) {
+ if (atom[i]->WhatIsSet & ASET_Occupancy) i1 = i;
+ else i1 = i2;
+ }
+ for (j=i;j<nAtoms;j++)
+ if ((j!=i1) && atom[j]) {
+ if ((!atom[j]->Ter) && (!strcmp(atom[j]->name,aname))) {
+ n++;
+ kndex = atom[j]->index;
+ if ((0<kndex) && (kndex<=nA)) A[kndex-1] = NULL;
+ delete atom[j];
+ atom[j] = NULL;
+ }
+ }
+ }
+ }
+ }
+
+ Exclude = true;
+
+ return n;
+
+ }
+
+ void Residue::ApplyTransform ( mat44 & TMatrix ) {
+ // transforms all coordinates by multiplying with matrix TMatrix
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter)
+ atom[i]->Transform ( TMatrix );
+ }
+ }
+
+
+
+ // -----------------------------------------------------------------
+
+
+ void Residue::MaskAtoms ( PMask Mask ) {
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) atom[i]->SetMask ( Mask );
+ }
+
+ void Residue::UnmaskAtoms ( PMask Mask ) {
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) atom[i]->RemoveMask ( Mask );
+ }
+
+
+
+ // ------- user-defined data handlers
+
+ int Residue::PutUDData ( int UDDhandle, int iudd ) {
+ if (UDDhandle & UDRF_RESIDUE)
+ return UDData::putUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Residue::PutUDData ( int UDDhandle, realtype rudd ) {
+ if (UDDhandle & UDRF_RESIDUE)
+ return UDData::putUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Residue::PutUDData ( int UDDhandle, cpstr sudd ) {
+ if (UDDhandle & UDRF_RESIDUE)
+ return UDData::putUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Residue::GetUDData ( int UDDhandle, int & iudd ) {
+ if (UDDhandle & UDRF_RESIDUE)
+ return UDData::getUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Residue::GetUDData ( int UDDhandle, realtype & rudd ) {
+ if (UDDhandle & UDRF_RESIDUE)
+ return UDData::getUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Residue::GetUDData ( int UDDhandle, pstr sudd, int maxLen ) {
+ if (UDDhandle & UDRF_RESIDUE)
+ return UDData::getUDData ( UDDhandle,sudd,maxLen );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Residue::GetUDData ( int UDDhandle, pstr & sudd ) {
+ if (UDDhandle & UDRF_RESIDUE)
+ return UDData::getUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+
+ #define NOmaxdist2 12.25
+
+ bool Residue::isMainchainHBond ( PResidue res ) {
+ // Test if there is main chain Hbond between PCRes1 (donor) and
+ // PCRes2 (acceptor).
+ // As defined Kabsch & Sanders
+ // This probably needs the option of supporting alternative criteria
+ PAtom NAtom,OAtom,Atom;
+ realtype abx,aby,abz;
+ realtype acx,acy,acz;
+ realtype bcx,bcy,bcz;
+ realtype absq,acsq,bcsq;
+
+ NAtom = GetAtom ( "N" );
+ OAtom = res->GetAtom ( "O" );
+ Atom = res->GetAtom ( "C" );
+
+ if (NAtom && OAtom && Atom) {
+
+ abx = OAtom->x - NAtom->x;
+ aby = OAtom->y - NAtom->y;
+ abz = OAtom->z - NAtom->z;
+ absq = abx*abx + aby*aby + abz*abz;
+
+
+ if (absq<=NOmaxdist2) {
+
+ acx = NAtom->x - Atom->x;
+ acy = NAtom->y - Atom->y;
+ acz = NAtom->z - Atom->z;
+
+ bcx = Atom->x - OAtom->x;
+ bcy = Atom->y - OAtom->y;
+ bcz = Atom->z - OAtom->z;
+
+ acsq = acx*acx + acy*acy + acz*acz;
+ bcsq = bcx*bcx + bcy*bcy + bcz*bcz;
+
+ return (acos((bcsq+absq-acsq)/(2.0*sqrt(bcsq*absq)))>=Pi/2.0);
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+
+ void Residue::write ( io::RFile f ) {
+ int i;
+ byte Version=2;
+
+ UDData::write ( f );
+
+ f.WriteByte ( &Version );
+ f.WriteInt ( &seqNum );
+ f.WriteInt ( &label_seq_id );
+ f.WriteInt ( &label_entity_id );
+ f.WriteInt ( &index );
+ f.WriteInt ( &nAtoms );
+ f.WriteByte ( &SSE );
+ f.WriteTerLine ( name ,false );
+ f.WriteTerLine ( label_comp_id,false );
+ f.WriteTerLine ( label_asym_id,false );
+ f.WriteTerLine ( insCode ,false );
+ for (i=0;i<nAtoms;i++)
+ f.WriteInt ( &(atom[i]->index) );
+
+ }
+
+ void Residue::read ( io::RFile f ) {
+ // IMPORTANT: array Atom in Root class should be
+ // read prior calling this function!
+ PPAtom A;
+ int i,k;
+ byte Version;
+
+ FreeMemory ();
+
+ UDData::read ( f );
+
+ f.ReadByte ( &Version );
+ f.ReadInt ( &seqNum );
+ if (Version>1) {
+ f.ReadInt ( &label_seq_id );
+ f.ReadInt ( &label_entity_id );
+ }
+ f.ReadInt ( &index );
+ f.ReadInt ( &nAtoms );
+ f.ReadByte ( &SSE );
+ f.ReadTerLine ( name,false );
+ if (Version>1) {
+ f.ReadTerLine ( label_comp_id,false );
+ f.ReadTerLine ( label_asym_id,false );
+ }
+ f.ReadTerLine ( insCode,false );
+ AtmLen = nAtoms;
+ A = NULL;
+ if (chain) {
+ if (chain->model)
+ A = chain->model->GetAllAtoms();
+ }
+ if ((nAtoms>0) && (A)) {
+ atom = new PAtom[nAtoms];
+ for (i=0;i<nAtoms;i++) {
+ f.ReadInt ( &k );
+ atom[i] = A[k-1];
+ atom[i]->SetResidue ( this );
+ atom[i]->_setBonds ( A );
+ }
+ } else {
+ for (i=0;i<nAtoms;i++)
+ f.ReadInt ( &k );
+ nAtoms = 0;
+ AtmLen = 0;
+ }
+ }
+
+
+ MakeFactoryFunctions(Residue)
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_atom.h b/mmdb2/mmdb_atom.h
new file mode 100644
index 0000000..63d5cb3
--- /dev/null
+++ b/mmdb2/mmdb_atom.h
@@ -0,0 +1,732 @@
+// $Id: mmdb_atom.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Atom <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Atom ( atom class )
+// ~~~~~~~~~ mmdb::Residue ( residue class )
+// **** Functions: mmdb::BondAngle
+// ~~~~~~~~~~
+//
+// Copyright (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Atom__
+#define __MMDB_Atom__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_uddata.h"
+#include "mmdb_utils.h"
+#include "mmdb_defs.h"
+
+
+namespace mmdb {
+
+ // ====================== Atom ==========================
+
+ // constants for the WhatIsSet field
+ enum ASET_FLAG {
+ ASET_Coordinates = 0x00000001,
+ ASET_Occupancy = 0x00000002,
+ ASET_tempFactor = 0x00000004,
+ ASET_CoordSigma = 0x00000010,
+ ASET_OccSigma = 0x00000020,
+ ASET_tFacSigma = 0x00000040,
+ ASET_Anis_tFac = 0x00000100,
+ ASET_Anis_tFSigma = 0x00001000,
+ ASET_Charge = 0x00000080,
+ ASET_All = 0x000FFFFF
+ };
+
+ const int ATOM_NoSeqNum = MinInt4;
+
+ extern bool ignoreSegID;
+ extern bool ignoreElement;
+ extern bool ignoreCharge;
+ extern bool ignoreNonCoorPDBErrors;
+ extern bool ignoreUnmatch;
+
+
+ DefineStructure(AtomStat);
+
+ struct AtomStat {
+
+ public :
+ int nAtoms; // number of atoms in statistics
+
+ realtype xmin,ymin,zmin; // minimums of coordinates
+ realtype xmax,ymax,zmax; // maximums of coordinates
+ realtype xm ,ym ,zm; // mediums of coordinates
+ realtype xm2 ,ym2 ,zm2; // square mediums of coordinates
+
+ realtype occ_min,occ_max; // minimum/maximum occupancy
+ realtype occ_m ,occ_m2; // medium and square medium occupancy
+
+ realtype tFmin,tFmax; // minimum/maximum temperature factor
+ realtype tFm ,tFm2; // medium and sq. med. temp. factor
+
+ realtype u11_min,u11_max; // minimums and
+ realtype u22_min,u22_max; // maximums of
+ realtype u33_min,u33_max; // anisotropic
+ realtype u12_min,u12_max; // temperature
+ realtype u13_min,u13_max; // factors
+ realtype u23_min,u23_max;
+
+ realtype u11_m,u11_m2; // mediums and
+ realtype u22_m,u22_m2; // square mediums of
+ realtype u33_m,u33_m2; // anisotropic
+ realtype u12_m,u12_m2; // temperature
+ realtype u13_m,u13_m2; // factors
+ realtype u23_m,u23_m2;
+
+ word WhatIsSet; // mask field
+
+ void Init ();
+ void Finish();
+
+ realtype GetMaxSize();
+
+ private :
+ bool finished;
+
+ };
+
+
+ DefineStructure(AtomBondI);
+
+ struct AtomBondI {
+ int index; //!< bonded atom index
+ byte order; //!< bond order
+ };
+
+
+ DefineStructure(AtomBond);
+
+ struct AtomBond {
+ PAtom atom; //!< bonded atom pointer
+ byte order; //!< bond order
+ };
+
+
+ DefineFactoryFunctions(Atom);
+
+ class Atom : public UDData {
+
+ friend class Residue;
+ friend class Model;
+ friend class Root;
+ friend class CoorManager;
+ friend class SelManager;
+
+ public :
+ int serNum; //!< serial number
+ AtomName name; //!< atom name (ALIGNED)
+ AtomName label_atom_id; //!< assigned atom name (not aligned)
+ AltLoc altLoc; //!< alternative location indicator ("" for none)
+ SegID segID; //!< segment identifier
+ Element element; //!< element symbol (ALIGNED TO RIGHT)
+ EnergyType energyType; //!< energy type (without spaces)
+ PResidue residue; //!< reference to residue
+ realtype x,y,z; //!< orthogonal coordinates in angstroms
+ realtype occupancy; //!< occupancy
+ realtype tempFactor; //!< temperature factor
+ realtype charge; //!< charge on the atom
+ realtype sigX,sigY,sigZ; //!< standard deviations of the coords
+ realtype sigOcc; //!< standard deviation of occupancy
+ realtype sigTemp; //!< standard deviation of temp. factor
+ realtype u11,u22,u33; //!< anisotropic temperature
+ realtype u12,u13,u23; /// factors
+ realtype su11,su22,su33; //!< standard deviations of
+ realtype su12,su13,su23; /// anisotropic temperature factors
+ bool Het; //!< indicator of het atom
+ bool Ter; //!< chain terminator
+
+ word WhatIsSet; //!< mask field
+ /// 0x0001 atomic coordinates
+ /// 0x0002 occupancy
+ /// 0x0004 temperature factor
+ /// 0x0010 coordinate standard deviations
+ /// 0x0020 deviation of occupancy
+ /// 0x0040 deviation of temperature factor
+ /// 0x0100 anisotropic temperature factors
+ /// 0x1000 anis. temp. fact-s st-d deviations
+
+ Atom ();
+ Atom ( PResidue res );
+ Atom ( io::RPStream Object );
+ ~Atom();
+
+ void SetResidue ( PResidue res );
+ void PDBASCIIDump ( io::RFile f );
+ void MakeCIF ( mmcif::PData CIF );
+
+ // AddBond(...) adds a bond to the atom, that is a pointer
+ // to the bonded atom and the bond order. nAdd_bonds allows
+ // one to minimize the memory reallocations, if number of
+ // bonds is known apriori: Atom adds space for nAdd_bonds
+ // if currently allocated space is exchausted.
+ // Return: <=0 - error: bond_atom is already "bonded"
+ // >0 - Ok, returns current number of bonds
+ int AddBond ( PAtom bond_atom, int bond_order,
+ int nAdd_bonds=1 );
+ int GetNBonds();
+
+ // This GetBonds(..) returns pointer to the Atom's
+ // internal Bond structure, IT MUST NOT BE DISPOSED.
+ void GetBonds ( RPAtomBond atomBond, int & nAtomBonds );
+ void FreeBonds();
+
+ // This GetBonds(..) disposes AtomBondI, if it was not set
+ // to NULL, allocates AtomBondI[nAtomBonds] and returns its
+ // pointer. AtomBondI MUST BE DISPOSED BY APPLICATION.
+ void GetBonds ( RPAtomBondI atomBondI, int & nAtomBonds );
+
+ // This GetBonds(..) does not dispose or allocate AtomBondI.
+ // It is assumed that length of AtomBondI is sufficient to
+ // accomodate all bonded atoms.
+ void GetBonds ( PAtomBondI atomBondI, int & nAtomBonds,
+ int maxlength );
+
+
+ // ConvertPDBxxxxxx() gets data from the PDB ASCII xxxxxx
+ // record (xxxxxx stands for ATOM, SIGATM, ANISOU, SIGUIJ,
+ // TER or HETATM).
+ // These functions DO NOT check the xxxxxx keyword and
+ // do not decode the chain and residue parameters! These
+ // must be treated by the calling process, see
+ // CMMDBFile::ReadPDBAtom().
+ // The atom reference is updated in the corresponding
+ // residue.
+ ERROR_CODE ConvertPDBATOM ( int ix, cpstr S );
+ ERROR_CODE ConvertPDBSIGATM ( int ix, cpstr S );
+ ERROR_CODE ConvertPDBANISOU ( int ix, cpstr S );
+ ERROR_CODE ConvertPDBSIGUIJ ( int ix, cpstr S );
+ ERROR_CODE ConvertPDBTER ( int ix, cpstr S );
+ ERROR_CODE ConvertPDBHETATM ( int ix, cpstr S );
+
+ ERROR_CODE GetCIF ( int ix, mmcif::PLoop Loop,
+ mmcif::PLoop LoopAnis );
+
+ bool RestoreElementName();
+ bool MakePDBAtomName();
+
+ void SetAtomName ( int ix, // index
+ int sN, // serial number
+ const AtomName aName, // atom name
+ const AltLoc aLoc, // alternative location
+ const SegID sID, // segment ID
+ const Element eName ); // element name
+
+ // This only renames the atom
+ void SetAtomName ( const AtomName atomName );
+ void SetElementName ( const Element elName );
+ void SetCharge ( cpstr chrg );
+ void SetCharge ( realtype chrg );
+
+ void SetAtomIndex ( int ix ); // don't use in your applications!
+
+ void MakeTer(); // converts atom into 'ter'
+
+ void SetCoordinates ( realtype xx, realtype yy, realtype zz,
+ realtype occ, realtype tFac );
+
+ int GetModelNum ();
+ pstr GetChainID ();
+ pstr GetLabelAsymID ();
+ pstr GetResName ();
+ pstr GetLabelCompID ();
+ int GetAASimilarity ( const ResName resName );
+ int GetAASimilarity ( PAtom A );
+ realtype GetAAHydropathy();
+ realtype GetOccupancy ();
+ int GetSeqNum ();
+ int GetLabelSeqID ();
+ int GetLabelEntityID ();
+ pstr GetInsCode ();
+ int GetSSEType (); // works only after SSE calculations
+ pstr GetAtomName () { return name; }
+ pstr GetElementName () { return element; }
+ pstr GetAtomCharge ( pstr chrg );
+
+ // GetChainCalphas(...) is a specialized function for quick
+ // access to C-alphas of chain which includes given atom.
+ // This function works faster than an equivalent implementation
+ // through MMDB's selection procedures.
+ // Parameters:
+ // Calphas - array to accept pointers on C-alpha atoms
+ // If Calphas!=NULL, then the function will
+ // delete and re-allocate it. When the array
+ // is no longer needed, the application MUST
+ // delete it: delete[] Calphas; Deleting
+ // Calphas does not delete atoms from MMDB.
+ // nCalphas - integer to accept number of C-alpha atoms
+ // and the length of Calphas array.
+ // altLoc - alternative location indicator. By default
+ // (""), maximum-occupancy locations are taken.
+ void GetChainCalphas ( PPAtom & Calphas, int & nCalphas,
+ cpstr altLoc = "" );
+
+ bool isTer () { return Ter; }
+ bool isMetal ();
+ bool isSolvent (); // works only for atom in a residue!
+ bool isInSelection ( int selHnd );
+ bool isNTerminus ();
+ bool isCTerminus ();
+
+ void CalAtomStatistics ( RAtomStat AS );
+
+ realtype GetDist2 ( PAtom a );
+ realtype GetDist2 ( PAtom a, mat44 & tm ); // tm applies to A
+ realtype GetDist2 ( PAtom a, mat33 & r, vect3 & t );// tm applies to A
+ realtype GetDist2 ( realtype ax, realtype ay, realtype az );
+
+ // GetCosine(a1,a2) calculates cosine of angle a1-this-a2,
+ // i.e. that between vectors [a1,this] and [this,a2].
+ realtype GetCosine ( PAtom a1, PAtom a2 );
+
+ PResidue GetResidue ();
+ PChain GetChain ();
+ PModel GetModel ();
+ int GetResidueNo();
+ void * GetCoordHierarchy(); // PRoot
+
+ // GetAtomID(..) generates atom ID in the form
+ // /m/c/r(rn).i/n[e]:a
+ // where m - model number
+ // c - chain ID
+ // r - residue sequence number
+ // rn - residue name
+ // i - insertion code
+ // n - atom name
+ // e - chemical element specification
+ // a - alternate location indicator
+ // If any of the fields is undefined, it is replaced by
+ // hyphen '-'.
+ // No checks on the sufficiency of string buffer AtomID
+ // is made.
+ // GetAtomID returns AtomID.
+ pstr GetAtomID ( pstr AtomID );
+
+ pstr GetAtomIDfmt ( pstr AtomID );
+
+ // ------- checking atom ID
+ // CheckID(..) returns 1 if atom is identified, and 0 otherwise.
+ // Parameters:
+ // aname - atom name. It may or may not be aligned (as in
+ // a PDB file), only first word of the name will
+ // be taken ("CA", " CA" and " CA B" are all
+ // considered as "CA"). aname may be set to NULL
+ // or '*', then this parameter is ignored.
+ // elname - element code. It will work only if element code
+ // is supplied (which might not be the case if
+ // the atom was created in a tricky way). elname
+ // should be used to distinguih between, e.g.
+ // "Ca" and "C_alpha"). elname may be set to NULL,
+ // or '*', then this parameter is ignored.
+ // aloc - the alternate location code. aloc may be set to
+ // NULL or '*', then this parameter is ignored.
+ // IMPORTANT: comparison is case-sensitive.
+ // The atom is considered as identified, if all non-NULL
+ // parameters do match. If all parameters are set NULL, any atom
+ // is identified.
+ // DEFAULT values correspond to 'any element' and
+ // 'no alternate location code'
+ // NOTE that " " is not an empty item.
+ int CheckID ( const AtomName aname, const Element elname=NULL,
+ const AltLoc aloc=pstr("") );
+
+ // CheckIDS(..) works exactly like CheckID(..), but it takes
+ // the only parameter, the atom ID, which is of the form:
+ // {name} {[element]} {:altcode}
+ // Here {} means that the item may be omitted. Any item may be
+ // represented by a wildcard '*', which means 'any value'. Just
+ // absence of an item means 'empty', which makes sense only for
+ // alternate location code. Missing name or element therefore
+ // mean 'any name' or 'any element', correspondingly (same as a
+ // wildcard). There should be no spaces in ID except for leading
+ // spaces; any following space will terminate parsing.
+ // The followings are perfectly valid IDs:
+ // CA[C]:A (carbon C_alpha in location A)
+ // CA[*]:A (either C_alpha or Ca in location A)
+ // CA:A (same as above)
+ // CA (either C_alpha or Ca with no location indicator)
+ // CA[] (same as above)
+ // CA[C]: (C_alpha with no location indicator)
+ // [C] (any carbon with no location indicator)
+ // [C]:* (any carbon with any location indicator)
+ // *[C]:* (same as above)
+ // :A (any atom in location A)
+ // *[*]:A (same as above)
+ // *[*]:* (any atom)
+ // * (any atom with no alternate location indicator)
+ int CheckIDS ( cpstr ID );
+
+
+ // ------- transform coordinates: x := m*x + v
+ void Transform ( mat33 & tm, vect3 & v );
+ void Transform ( mat44 & tm );
+ void TransformCopy ( mat44 & tm,
+ realtype & xx, realtype & yy, realtype & zz );
+ void TransformSet ( mat44 & tm,
+ realtype xx, realtype yy, realtype zz );
+
+
+ // ------- user-defined data handlers
+ int PutUDData ( int UDDhandle, int iudd );
+ int PutUDData ( int UDDhandle, realtype rudd );
+ int PutUDData ( int UDDhandle, cpstr sudd );
+
+ int GetUDData ( int UDDhandle, int & iudd );
+ int GetUDData ( int UDDhandle, realtype & rudd );
+ int GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+ int GetUDData ( int UDDhandle, pstr & sudd );
+
+
+ int GetIndex() { return index; }
+
+ virtual void Copy ( PAtom atom ); // without references in
+ // residues
+
+ void SetShortBinary(); // leaves only coordinates in binary files
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ int index; // index in the file
+ int nBonds; // number of bonds in the lowest byte (!)
+ PAtomBond Bond; // atom bonds
+
+ void InitAtom ();
+ void FreeMemory ();
+ void StandardPDBOut ( cpstr Record, pstr S );
+ void GetData ( cpstr S );
+ ERROR_CODE CheckData ( cpstr S );
+ void GetStat ( realtype v,
+ realtype & v_min, realtype & v_max,
+ realtype & v_m, realtype & v_m2 );
+ void _setBonds ( PPAtom A ); // used only in Residue
+
+ };
+
+
+ // ====================== Residue ==========================
+
+ enum ALTLOC_FLAG {
+ ALF_NoAltCodes = 0x00000000,
+ ALF_EmptyAltLoc = 0x00000001,
+ ALF_NoEmptyAltLoc = 0x00000002,
+ ALF_Mess = 0x00000004,
+ ALF_Occupancy = 0x00000008
+ };
+
+ enum SSE_FLAG {
+ SSE_None = 0,
+ SSE_Strand = 1,
+ SSE_Bulge = 2,
+ SSE_3Turn = 3,
+ SSE_4Turn = 4,
+ SSE_5Turn = 5,
+ SSE_Helix = 6
+ };
+
+ DefineFactoryFunctions(Residue);
+
+ class Residue : public UDData {
+
+ friend class Atom;
+ friend class Chain;
+ friend class Root;
+
+ public :
+
+ ResName name; //!< residue name - all spaces cut
+ ResName label_comp_id; //!< assigned residue name
+ ChainID label_asym_id; //!< assigned chain Id
+ InsCode insCode; //!< residue insertion code
+ PChain chain; //!< reference to chain
+ PPAtom atom; //!< array of atoms
+ int seqNum; //!< residue sequence number
+ int label_seq_id; //!< assigned residue sequence number
+ int label_entity_id; //!< assigned entity id
+ int index; //!< index in the chain
+ int nAtoms; //!< number of atoms in the residue
+ byte SSE; //!< SSE type
+
+ Residue ();
+ Residue ( PChain Chain_Owner );
+ Residue ( PChain Chain_Owner, const ResName resName,
+ int sqNum, const InsCode ins );
+ Residue ( io::RPStream Object );
+ ~Residue();
+
+ void SetChain ( PChain Chain_Owner );
+ void SetResID ( const ResName resName, int sqNum,
+ const InsCode ins );
+ void SetChainID ( const ChainID chID );
+
+ void PDBASCIIAtomDump ( io::RFile f );
+ void MakeAtomCIF ( mmcif::PData CIF );
+
+ PChain GetChain();
+ PModel GetModel();
+
+ int GetModelNum ();
+ pstr GetChainID ();
+ pstr GetLabelAsymID();
+ pstr GetResName ();
+ pstr GetLabelCompID();
+ int GetAASimilarity ( const ResName resName );
+ int GetAASimilarity ( PResidue res );
+ realtype GetAAHydropathy();
+ void SetResName ( const ResName resName );
+ int GetSeqNum ();
+ int GetLabelSeqID ();
+ int GetLabelEntityID();
+ pstr GetInsCode ();
+ int GetResidueNo ();
+ int GetCenter ( realtype & x, realtype & y, realtype & z );
+ void * GetCoordHierarchy(); // PCMMDBFile
+
+ void GetAtomStatistics ( RAtomStat AS );
+ void CalAtomStatistics ( RAtomStat AS );
+
+ pstr GetResidueID ( pstr ResidueID );
+
+ // GetAltLocations(..) returns the number of different
+ // alternative locations in nAltLocs, the locations themselves
+ // - in aLoc and the corresponding occupancies - in occupancy.
+ // aLoc and occupancy are allocated dynamically; it is
+ // responsibility of the application to deallocate aLoc prior
+ // calling GetAltLocations(..) if they were previously allocated.
+ // Either, the application is responsible for deallocating aLoc and
+ // occupancy after use.
+ // occupancy[i] may return -1.0 if occupancies were not read
+ // from coordinate file.
+ // alflag returns ALF_NoAltCodes if no alt codes was found,
+ // otherwise the output is decoded according to bits:
+ // ALF_EmptyAltLoc alternative locations include the
+ // "no alt loc indicator" ("" for
+ // Atom::altLoc).
+ // This means that each atom that has alt locs
+ // different of "", also includes one marked as
+ // "".
+ // ALF_NoEmptyAltLoc alternative locations do not include the
+ // "no alt loc indicator" ("" for
+ // Atom::altLoc).
+ // This means that each atom has either ""
+ // alt loc or at least two alt locs different
+ // of "".
+ // ALF_Mess incorrect residue: it mixes both
+ // ""-including and not-""-including schemes
+ // ALF_Occupancy warning that sum of occupancies for alt
+ // located atoms differ from 1.0 by more
+ // than 0.01.
+ void GetAltLocations ( int & nAltLocs, PAltLoc & aLoc,
+ rvector & occupancy, int & alflag );
+ int GetNofAltLocations();
+
+ bool isAminoacid ();
+ bool isNucleotide ();
+ int isDNARNA (); // 0(neither),1(DNA),2(RNA)
+ bool isSugar ();
+ bool isSolvent ();
+ bool isModRes ();
+ bool isInSelection ( int selHnd );
+ bool isNTerminus ();
+ bool isCTerminus ();
+
+ // ------- checking residue ID
+ // CheckID(..) returns 1 if residue is identified, and 0 otherwise.
+ // Parameters:
+ // sname - pointer to sequence number; if NULL then ignored.
+ // inscode - insertion code; if NULL or '*' then ignored.
+ // resname - residue name; if NULL or '*' then ignored.
+ // IMPORTANT: comparison is case-sensitive.
+ // The residue is considered as identified, if all non-NULL
+ // parameters do match. If all parameters are set NULL, any
+ // residue is identified.
+ // DEFAULT values correspond to 'any residue name' and
+ // 'no insertion code'
+ // NOTE that " " is not an empty item.
+ int CheckID ( int * snum, const InsCode inscode=pstr(""),
+ const ResName resname=NULL );
+
+ // CheckIDS(..) works exactly like CheckID(..), but it takes
+ // the only parameter, the residue ID, which is of the form:
+ // {seqnum} {(name)} {.inscode}
+ // Here {} means that the item may be omitted. Any item may be
+ // represented by a wildcard '*', which means 'any value'. Just
+ // absence of a value means 'empty', which is meaningful only for
+ // the insertion code. Missing sequence number or residue name
+ // therefore mean 'any sequence number' or 'any residue name',
+ // correspondingly (same as a wildcard). There should be no
+ // spaces in ID except for leading spaces; any following space will
+ // terminate parsing. The followings are perfectly valid IDs:
+ // 27(ALA).A (residue 27A ALA)
+ // 27().A (residue 27A)
+ // 27(*).A (same as above)
+ // 27.A (same as above)
+ // 27 (residue 27)
+ // 27(). (same as above)
+ // (ALA) (any ALA without insertion code)
+ // (ALA). (same as above)
+ // (ALA).* (any ALA)
+ // *(ALA).* (any ALA)
+ // .A (any residue with insertion code A)
+ // *(*).A (same as above)
+ // *(*).* (any residue)
+ // * (any residue with no insertion code)
+ int CheckIDS ( cpstr ID );
+
+
+ // -------------------- Extracting atoms ----------------------
+
+ int GetNumberOfAtoms ();
+ int GetNumberOfAtoms ( bool countTers );
+
+ PAtom GetAtom ( const AtomName aname, const Element elname=NULL,
+ const AltLoc aloc=cpstr("") );
+ PAtom GetAtom ( int atomNo );
+
+ void GetAtomTable ( PPAtom & atomTable, int & NumberOfAtoms );
+
+ // GetAtomTable1(..) returns atom table without TER atoms and
+ // without NULL atom pointers. NumberOfAtoms returns the actual
+ // number of atom pointers in atomTable.
+ // atomTable is allocated withing the function. If it was
+ // not set to NULL before calling the function, the latter will
+ // attempt to deallocate it first.
+ // The application is responsible for deleting atomTable,
+ // however it must not touch atom pointers, i.e. use simply
+ // "delete[] atomTable;". Never pass atomTable from GetAtomTable()
+ // into this function, unless you set it to NULL before doing that.
+ void GetAtomTable1 ( PPAtom & atomTable, int & NumberOfAtoms );
+
+
+ // --------------------- Deleting atoms -----------------------
+
+ int DeleteAtom ( const AtomName aname, const Element elname=NULL,
+ const AltLoc aloc=cpstr("") );
+ int DeleteAtom ( int atomNo );
+ int DeleteAllAtoms();
+
+ // DeleteAltLocs() leaves only alternative location with maximal
+ // occupancy, if those are equal or unspecified, the one with
+ // "least" alternative location indicator.
+ // The function returns the number of deleted atoms. The atom
+ // table remains untrimmed, so that nAtoms are wrong until that
+ // is done. Tables are trimmed by FinishStructEdit() or
+ // explicitely.
+ int DeleteAltLocs ();
+
+ void TrimAtomTable ();
+
+ // ---------------------- Adding atoms ------------------------
+
+ // AddAtom(..) adds atom to the residue. If residue is associated
+ // with a coordinate hierarchy, and atom 'atm' is not, the latter
+ // is checked in automatically. If atom 'atm' belongs to any
+ // coordinate hierarchy (even though that of the residue), it is
+ // *copied* rather than simply taken over, and is checked in.
+ // If residue is not associated with a coordinate hierarchy, all
+ // added atoms will be checked in automatically once the residue
+ // is checked in.
+ int AddAtom ( PAtom atm );
+
+ // InsertAtom(..) inserts atom into the specified position of
+ // the residue. If residue is associated with a coordinate
+ // hierarchy, and atom 'atm' is not, the latter is checked in
+ // automatically. If atom 'atm' belongs to any coordinate
+ // hierarchy (even though that of the residue), it is *copied*
+ // rather than simply taken over, and is checked in.
+ // If residue is not associated with a coordinate hierarchy, all
+ // added atoms will be checked in automatically once the residue
+ // is checked in.
+ int InsertAtom ( PAtom atm, int position );
+
+ // This version inserts before the atom with given name. If such
+ // name is not found, the atom is appended to the end.
+ int InsertAtom ( PAtom atm, const AtomName aname );
+
+ // --------------------------------------------------------------
+
+ void ApplyTransform ( mat44 & TMatrix ); // transforms all
+ // coordinates by
+ // multiplying with
+ // matrix TMatrix
+
+ void MaskAtoms ( PMask Mask );
+ void UnmaskAtoms ( PMask Mask );
+
+
+ // ------- user-defined data handlers
+ int PutUDData ( int UDDhandle, int iudd );
+ int PutUDData ( int UDDhandle, realtype rudd );
+ int PutUDData ( int UDDhandle, cpstr sudd );
+
+ int GetUDData ( int UDDhandle, int & iudd );
+ int GetUDData ( int UDDhandle, realtype & rudd );
+ int GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+ int GetUDData ( int UDDhandle, pstr & sudd );
+
+
+ bool isMainchainHBond ( PResidue res );
+
+ void Copy ( PResidue res );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ int AtmLen; // length of atom array
+ bool Exclude; // used internally
+
+ void InitResidue ();
+ void FreeMemory ();
+ int _AddAtom ( PAtom atm );
+ int _ExcludeAtom ( int kndex ); // 1: residue gets empty,
+ // 0 otherwise
+ void _copy ( PResidue res );
+ void _copy ( PResidue res, PPAtom atm, int & atom_index );
+ void ExpandAtomArray ( int nAdd );
+ void CheckInAtoms ();
+
+ };
+
+
+ extern realtype BondAngle ( PAtom A, PAtom B, PAtom C );
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_bondmngr.cpp b/mmdb2/mmdb_bondmngr.cpp
new file mode 100644
index 0000000..6c7b99f
--- /dev/null
+++ b/mmdb2/mmdb_bondmngr.cpp
@@ -0,0 +1,121 @@
+// $Id: mmdb_bondmngr.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 15.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_bondmngr <implementation>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::BondManager ( MMDB bonds maker )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+
+#include <string.h>
+
+#include "mmdb_bondmngr.h"
+#include "mmdb_math_graph.h"
+
+namespace mmdb {
+
+ // ===================== BondManager =====================
+
+ BondManager::BondManager() : SelManager() {
+ }
+
+ BondManager::BondManager ( io::RPStream Object )
+ : SelManager(Object) {
+ }
+
+ BondManager::~BondManager() {}
+
+ void BondManager::MakeBonds ( bool calc_only ) {
+ UNUSED_ARGUMENT(calc_only);
+ PModel mdl;
+ PChain chain;
+ PResidue res;
+ math::Graph graph;
+ math::PPVertex V;
+ math::PPEdge E;
+ int i, im,ic,ir, nV,nE, k1,k2;
+
+ RemoveBonds();
+
+ for (im=0;im<nModels;im++) {
+ mdl = model[im];
+ if (mdl)
+ for (ic=0;ic<mdl->nChains;ic++) {
+ chain = mdl->chain[ic];
+ if (chain)
+ for (ir=0;ir<chain->nResidues;ir++) {
+ res = chain->residue[ir];
+ if (res) {
+ graph.MakeGraph ( res,NULL );
+ graph.GetVertices ( V,nV );
+ graph.GetEdges ( E,nE );
+ for (i=0;i<nE;i++) {
+ k1 = V[E[i]->GetVertex1()-1]->GetUserID();
+ k2 = V[E[i]->GetVertex2()-1]->GetUserID();
+ res->atom[k1]->AddBond ( res->atom[k2],E[i]->GetType() );
+ res->atom[k2]->AddBond ( res->atom[k1],E[i]->GetType() );
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ void BondManager::RemoveBonds() {
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i])
+ atom[i]->FreeBonds();
+ }
+
+ // ------------------- Stream functions ----------------------
+
+ void BondManager::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ SelManager::write ( f );
+ }
+
+ void BondManager::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ SelManager::read ( f );
+ }
+
+
+ MakeStreamFunctions(BondManager)
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_bondmngr.h b/mmdb2/mmdb_bondmngr.h
new file mode 100644
index 0000000..9186232
--- /dev/null
+++ b/mmdb2/mmdb_bondmngr.h
@@ -0,0 +1,73 @@
+// $Id: mmdb_bondmngr.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 15.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_bondmngr <interface>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::BondManager ( MMDB bonds maker )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_BondMngr__
+#define __MMDB_BondMngr__
+
+#include "mmdb_selmngr.h"
+
+namespace mmdb {
+
+ // ======================= BondManager =======================
+
+ DefineClass(BondManager);
+ DefineStreamFunctions(BondManager);
+
+ class BondManager : public SelManager {
+
+ public :
+
+ BondManager ();
+ BondManager ( io::RPStream Object );
+ ~BondManager();
+
+ void MakeBonds ( bool calc_only );
+ void RemoveBonds();
+
+ protected :
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ };
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_chain.cpp b/mmdb2/mmdb_chain.cpp
new file mode 100644
index 0000000..1c3ab8e
--- /dev/null
+++ b/mmdb2/mmdb_chain.cpp
@@ -0,0 +1,2575 @@
+// $Id: mmdb_chain.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 16.05.14 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Chain <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::ProModel ( a virtue of Model )
+// ~~~~~~~~~ mmdb::DBReference ( DBREF records )
+// mmdb::ChainContainer ( container of in-chain classes )
+// mmdb::ContainerChain ( chain containered class template)
+// mmdb::SeqAdv ( SEQADV records )
+// mmdb::SeqRes ( SEQRES records )
+// mmdb::ModRes ( MODRES records )
+// mmdb::HetRec ( HET records )
+// mmdb::Chain ( chain class )
+//
+// Copyright (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mmdb_chain.h"
+#include "mmdb_model.h"
+#include "mmdb_root.h"
+#include "mmdb_cifdefs.h"
+
+namespace mmdb {
+
+ // ================== ProModel ======================
+
+ MakeStreamFunctions(ProModel)
+
+ // ============== ChainContainer ====================
+
+ PContainerClass ChainContainer::MakeContainerClass ( int ClassID ) {
+ switch (ClassID) {
+ default :
+ case ClassID_Template : return
+ ClassContainer::MakeContainerClass(ClassID);
+ case ClassID_DBReference : return new DBReference ( chain );
+ case ClassID_SeqAdv : return new SeqAdv ( chain );
+ case ClassID_ModRes : return new ModRes ( chain );
+ case ClassID_Het : return new HetRec ( chain );
+ }
+ }
+
+ void ChainContainer::SetChain ( PChain Chain_Owner ) {
+ int i;
+ chain = Chain_Owner;
+ for (i=0;i<length;i++)
+ if (Container[i])
+ (void)PContainerChain(Container[i])->SetChain ( chain );
+ }
+
+ cpstr ChainContainer::Get1stChainID() {
+ int i;
+ i = 0;
+ if (Container) {
+ while ((i<length-1) && (!Container[i])) i++;
+ if (Container[i])
+ return PContainerChain(Container[i])->chainID;
+ else return NULL;
+ } else
+ return NULL;
+ }
+
+ void ChainContainer::MoveByChainID ( const ChainID chainID,
+ PChainContainer ChainContainer ) {
+ int i;
+ for (i=0;i<length;i++)
+ if (Container[i]) {
+ if (!strcmp(PContainerChain(Container[i])->chainID,chainID)) {
+ ChainContainer->AddData ( Container[i] );
+ Container[i] = NULL;
+ }
+ }
+ }
+
+
+ MakeStreamFunctions(ChainContainer)
+
+
+ // ================ ContainerChain ===================
+
+ ContainerChain::ContainerChain() : ContainerClass() {
+ chain = NULL;
+ chainID[0] = char(0);
+ }
+
+ ContainerChain::ContainerChain ( PChain Chain_Owner)
+ : ContainerClass() {
+ chain = Chain_Owner;
+ if (chain) strcpy ( chainID,chain->GetChainID() );
+ else chainID[0] = char(0);
+ }
+
+ void ContainerChain::SetChain ( PChain Chain_Owner ) {
+ chain = Chain_Owner;
+ if (chain) strcpy ( chainID,chain->GetChainID() );
+ else strcpy ( chainID,"" );
+ }
+
+ MakeStreamFunctions(ContainerChain)
+
+
+ // ================ DBReference ===================
+
+ DBReference::DBReference() : ContainerChain() {
+ InitDBReference();
+ }
+
+ DBReference::DBReference( PChain Chain_Owner )
+ : ContainerChain(Chain_Owner) {
+ InitDBReference();
+ }
+
+ DBReference::DBReference ( PChain Chain_Owner, cpstr S )
+ : ContainerChain(Chain_Owner) {
+ InitDBReference();
+ ConvertPDBASCII ( S );
+ }
+
+ DBReference::DBReference ( io::RPStream Object )
+ : ContainerChain(Object) {
+ InitDBReference();
+ }
+
+ DBReference::~DBReference() {}
+
+ void DBReference::InitDBReference() {
+ seqBeg = 0;
+ strcpy ( insBeg ,"-" );
+ seqEnd = 0;
+ strcpy ( insEnd ,"-" );
+ strcpy ( database ,"------" );
+ strcpy ( dbAccession,"--------" );
+ strcpy ( dbIdCode ,"------------" );
+ dbseqBeg = 0;
+ strcpy ( dbinsBeg,"-" );
+ dbseqEnd = 0;
+ strcpy ( dbinsEnd,"-" );
+ }
+
+ void DBReference::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+ // makes the ASCII PDB DBREF line number N
+ // from the class' data
+ strcpy ( S,"DBREF" );
+ PadSpaces ( S,80 );
+ strcpy_n ( &(S[7]),chain->GetEntryID(),4 );
+ if (chain->chainID[0]) S[12] = chain->chainID[0];
+ PutIntIns ( &(S[14]),seqBeg,4,insBeg );
+ PutIntIns ( &(S[20]),seqEnd,4,insEnd );
+ strcpy_n ( &(S[26]),database ,6 );
+ strcpy_n ( &(S[33]),dbAccession,8 );
+ strcpy_n ( &(S[42]),dbIdCode ,12 );
+ PutIntIns ( &(S[55]),dbseqBeg,5,dbinsBeg );
+ PutIntIns ( &(S[62]),dbseqEnd,5,dbinsEnd );
+ }
+
+ void DBReference::MakeCIF ( mmcif::PData CIF, int N ) {
+ UNUSED_ARGUMENT(N);
+ mmcif::PLoop Loop1,Loop2;
+ int RC1,RC2;
+
+ RC1 = CIF->AddLoop ( CIFCAT_STRUCT_REF_SEQ,Loop1 );
+ RC2 = CIF->AddLoop ( CIFCAT_STRUCT_REF ,Loop2 );
+
+ if ((RC1!=mmcif::CIFRC_Ok) || (RC2!=mmcif::CIFRC_Ok)) {
+ // the category was (re)created, provide tags
+ Loop1->AddLoopTag ( CIFTAG_NDB_PDB_ID_CODE );
+ Loop1->AddLoopTag ( CIFTAG_NDB_CHAIN_ID );
+ Loop1->AddLoopTag ( CIFTAG_SEQ_ALIGN_BEG );
+ Loop1->AddLoopTag ( CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE );
+ Loop1->AddLoopTag ( CIFTAG_SEQ_ALIGN_END );
+ Loop1->AddLoopTag ( CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE );
+ Loop1->AddLoopTag ( CIFTAG_NDB_DB_ACCESSION );
+ Loop1->AddLoopTag ( CIFTAG_DB_ALIGN_BEG );
+ Loop1->AddLoopTag ( CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE );
+ Loop1->AddLoopTag ( CIFTAG_DB_ALIGN_END );
+ Loop1->AddLoopTag ( CIFTAG_NDB_DB_ALIGN_END_INS_CODE );
+ Loop2->AddLoopTag ( CIFTAG_DB_NAME );
+ Loop2->AddLoopTag ( CIFTAG_DB_CODE );
+ }
+
+ Loop1->AddString ( chain->GetEntryID(),true );
+ Loop1->AddString ( chain->chainID ,true );
+ Loop1->AddInteger ( seqBeg );
+ Loop1->AddString ( insBeg ,true );
+ Loop1->AddInteger ( seqEnd );
+ Loop1->AddString ( insEnd ,true );
+ Loop1->AddString ( dbAccession ,true );
+ Loop1->AddInteger ( dbseqBeg );
+ Loop1->AddString ( dbinsBeg ,true );
+ Loop1->AddInteger ( dbseqEnd );
+ Loop1->AddString ( dbinsEnd ,true );
+
+ Loop2->AddString ( database,true );
+ Loop2->AddString ( dbIdCode,true );
+
+ }
+
+ ERROR_CODE DBReference::GetCIF ( mmcif::PData CIF, int & n ) {
+ // GetCIF(..) must be always run without reference to Chain,
+ // see CModel::GetCIF(..).
+ mmcif::PLoop Loop1,Loop2;
+ mmcif::PStruct Struct2;
+ pstr F;
+ int RC,ref_id1,ref_id2;
+ CIF_MODE CIFMode;
+ ERROR_CODE rc;
+
+ Loop1 = CIF->GetLoop ( CIFCAT_STRUCT_REF_SEQ );
+
+ if (!Loop1) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+ if (n>=Loop1->GetLoopLength()) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+
+ // Determine the ChainID first and store it locally. It will
+ // be used by CModel for generating chains and placing the
+ // primary structure data BEFORE reading the coordinate section.
+ CIFMode = CIF_NDB;
+ F = Loop1->GetString ( CIFName(TAG_CHAIN_ID,CIFMode),n,RC );
+ if ((RC) || (!F)) {
+ CIFMode = CIF_PDBX;
+ F = Loop1->GetString ( CIFName(TAG_CHAIN_ID,CIFMode),n,RC );
+ }
+ if ((!RC) && F) {
+ strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
+ Loop1->DeleteField ( CIFName(TAG_CHAIN_ID,CIFMode),n );
+ } else
+ strcpy ( chainID,"" );
+
+
+ rc = CIFGetInteger(seqBeg,Loop1,CIFName(TAG_SEQ_ALIGN_BEG,CIFMode),n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+ CIFGetString ( insBeg,Loop1,CIFName(TAG_SEQ_ALIGN_BEG_INS_CODE,CIFMode),
+ n,sizeof(InsCode),pstr(" ") );
+
+ rc = CIFGetInteger(seqEnd,Loop1,CIFName(TAG_SEQ_ALIGN_END,CIFMode),n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+ CIFGetString ( insEnd,Loop1,CIFName(TAG_SEQ_ALIGN_END_INS_CODE,CIFMode),
+ n,sizeof(InsCode),pstr(" ") );
+ CIFGetString ( dbAccession,Loop1,CIFName(TAG_DB_ACCESSION,CIFMode),
+ n,sizeof(DBAcCode),pstr(" ") );
+
+ rc = CIFGetInteger(dbseqBeg,Loop1,CIFName(TAG_DB_ALIGN_BEG,CIFMode),n);
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+ CIFGetString ( dbinsBeg,Loop1,CIFName(TAG_DB_ALIGN_BEG_INS_CODE,CIFMode),
+ n,sizeof(InsCode),pstr(" ") );
+
+ rc = CIFGetInteger(dbseqEnd,Loop1,CIFName(TAG_DB_ALIGN_END,CIFMode),n);
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+ CIFGetString ( dbinsEnd,Loop1,CIFName(TAG_DB_ALIGN_END_INS_CODE,CIFMode),
+ n,sizeof(InsCode),pstr(" ") );
+
+ Loop2 = CIF->GetLoop ( CIFCAT_STRUCT_REF );
+ if (Loop2) {
+ CIFGetString ( database,Loop2,CIFTAG_DB_NAME,n,
+ sizeof(DBName) ,pstr(" ") );
+ CIFGetString ( dbIdCode,Loop2,CIFTAG_DB_CODE,n,
+ sizeof(DBIdCode),pstr(" ") );
+ } else if (CIFMode==CIF_PDBX) {
+ Struct2 = CIF->GetStructure ( CIFCAT_STRUCT_REF );
+ if (Struct2 &&
+ (!CIFGetInteger(ref_id1,Loop1,CIFTAG_REF_ID,n)) &&
+ (!CIFGetInteger(ref_id2,Struct2,CIFTAG_ID,false))) {
+ if (ref_id1==ref_id2) {
+ CIFGetString ( database,Struct2,CIFTAG_DB_NAME,
+ sizeof(DBName) ,pstr(" ") ,false );
+ CIFGetString ( dbIdCode,Struct2,CIFTAG_DB_CODE,
+ sizeof(DBIdCode),pstr(" "),false );
+ }
+ }
+ }
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+
+ ERROR_CODE DBReference::ConvertPDBASCII ( cpstr S ) {
+ IDCode idCode;
+ if (chain->chainID[0]) {
+ if (S[12]!=chain->chainID[0])
+ return Error_WrongChainID;
+ } else if (S[12]!=' ') {
+ chain->chainID[0] = S[12];
+ chain->chainID[1] = char(0);
+ } else
+ chain->chainID[0] = char(0);
+ strcpy ( idCode,chain->GetEntryID() );
+ if (idCode[0]) {
+ if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
+ return Error_WrongEntryID;
+ } else {
+ GetString ( idCode,&(S[7]),4 );
+ chain->SetEntryID ( idCode );
+ }
+ GetIntIns ( seqBeg,insBeg,&(S[14]),4 );
+ GetIntIns ( seqEnd,insEnd,&(S[20]),4 );
+ strcpy_ncs ( database ,&(S[26]),6 );
+ strcpy_ncs ( dbAccession ,&(S[33]),8 );
+ strcpy_ncs ( dbIdCode ,&(S[42]),12 );
+ GetIntIns ( dbseqBeg,dbinsBeg,&(S[55]),5 );
+ GetIntIns ( dbseqEnd,dbinsEnd,&(S[62]),5 );
+ return Error_NoError;
+ }
+
+ void DBReference::Copy ( PContainerClass DBRef ) {
+
+ ContainerChain::Copy ( DBRef );
+
+ seqBeg = PDBReference(DBRef)->seqBeg;
+ seqEnd = PDBReference(DBRef)->seqEnd;
+ dbseqBeg = PDBReference(DBRef)->dbseqBeg;
+ dbseqEnd = PDBReference(DBRef)->dbseqEnd;
+ strcpy ( insBeg ,PDBReference(DBRef)->insBeg );
+ strcpy ( insEnd ,PDBReference(DBRef)->insEnd );
+ strcpy ( database ,PDBReference(DBRef)->database );
+ strcpy ( dbAccession,PDBReference(DBRef)->dbAccession );
+ strcpy ( dbIdCode ,PDBReference(DBRef)->dbIdCode );
+ strcpy ( dbinsBeg ,PDBReference(DBRef)->dbinsBeg );
+ strcpy ( dbinsEnd ,PDBReference(DBRef)->dbinsEnd );
+
+ }
+
+ void DBReference::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &seqBeg );
+ f.WriteInt ( &seqEnd );
+ f.WriteInt ( &dbseqBeg );
+ f.WriteInt ( &dbseqEnd );
+ f.WriteTerLine ( insBeg ,false );
+ f.WriteTerLine ( insEnd ,false );
+ f.WriteTerLine ( database ,false );
+ f.WriteTerLine ( dbAccession,false );
+ f.WriteTerLine ( dbIdCode ,false );
+ f.WriteTerLine ( dbinsBeg ,false );
+ f.WriteTerLine ( dbinsEnd ,false );
+ }
+
+ void DBReference::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &seqBeg );
+ f.ReadInt ( &seqEnd );
+ f.ReadInt ( &dbseqBeg );
+ f.ReadInt ( &dbseqEnd );
+ f.ReadTerLine ( insBeg ,false );
+ f.ReadTerLine ( insEnd ,false );
+ f.ReadTerLine ( database ,false );
+ f.ReadTerLine ( dbAccession,false );
+ f.ReadTerLine ( dbIdCode ,false );
+ f.ReadTerLine ( dbinsBeg ,false );
+ f.ReadTerLine ( dbinsEnd ,false );
+ }
+
+ MakeStreamFunctions(DBReference)
+
+
+
+ // ================ SeqAdv ===================
+
+ SeqAdv::SeqAdv() : ContainerChain() {
+ InitSeqAdv();
+ }
+
+ SeqAdv::SeqAdv ( PChain Chain_Owner )
+ : ContainerChain(Chain_Owner) {
+ InitSeqAdv();
+ }
+
+ SeqAdv::SeqAdv ( PChain Chain_Owner, cpstr S )
+ : ContainerChain(Chain_Owner) {
+ InitSeqAdv();
+ ConvertPDBASCII ( S );
+ }
+
+ SeqAdv::SeqAdv ( io::RPStream Object ) : ContainerChain(Object) {
+ InitSeqAdv();
+ }
+
+ SeqAdv::~SeqAdv() {
+ if (conflict) delete[] conflict;
+ }
+
+ void SeqAdv::InitSeqAdv() {
+ strcpy ( resName ,"---" );
+ seqNum = 0;
+ strcpy ( insCode ,"-" );
+ strcpy ( database ,"------" );
+ strcpy ( dbAccession,"---------" );
+ strcpy ( dbRes ,"---" );
+ dbSeq = 0;
+ conflict = NULL;
+ CreateCopy ( conflict,pstr(" ") );
+ }
+
+ void SeqAdv::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+ // makes the ASCII PDB SEQADV line number N
+ // from the class' data
+ strcpy ( S,"SEQADV" );
+ PadSpaces ( S,80 );
+ strcpy_n ( &(S[7]) ,chain->GetEntryID(),4 );
+ strcpy_n ( &(S[12]),resName ,3 );
+ if (chain->chainID[0]) S[16] = chain->chainID[0];
+ PutIntIns ( &(S[18]),seqNum,4,insCode );
+ strcpy_n ( &(S[24]),database ,4 );
+ strcpy_n ( &(S[29]),dbAccession,9 );
+ strcpy_n ( &(S[39]),dbRes ,3 );
+ PutInteger ( &(S[43]),dbSeq ,5 );
+ strcpy_n ( &(S[49]),conflict,IMin(strlen(conflict),21) );
+ }
+
+ ERROR_CODE SeqAdv::ConvertPDBASCII ( cpstr S ) {
+ IDCode idCode;
+ if (chain->chainID[0]) {
+ if (S[16]!=chain->chainID[0])
+ return Error_WrongChainID;
+ } else if (S[16]!=' ') {
+ chain->chainID[0] = S[16];
+ chain->chainID[1] = char(0);
+ } else
+ chain->chainID[0] = char(0);
+ strcpy ( idCode,chain->GetEntryID() );
+ if (idCode[0]) {
+ if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
+ return Error_WrongEntryID;
+ } else {
+ GetString ( idCode,&(S[7]),4 );
+ chain->SetEntryID ( idCode );
+ }
+ strcpy_ncs ( resName ,&(S[12]),3 );
+ GetIntIns ( seqNum,insCode,&(S[18]),4 );
+ strcpy_ncs ( database ,&(S[24]),4 );
+ strcpy_ncs ( dbAccession ,&(S[29]),9 );
+ strcpy_ncs ( dbRes ,&(S[39]),3 );
+ GetInteger ( dbSeq,&(S[43]),5 );
+ CreateCopy ( conflict,&(S[49]) );
+ CutSpaces ( conflict,SCUTKEY_END );
+ return Error_NoError;
+ }
+
+
+ void SeqAdv::MakeCIF ( mmcif::PData CIF, int N ) {
+ UNUSED_ARGUMENT(N);
+ mmcif::PLoop Loop;
+ int RC;
+
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_REF_SEQ_DIF,Loop );
+
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_NDB_PDB_ID_CODE );
+ Loop->AddLoopTag ( CIFTAG_MON_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_PDB_CHAIN_ID );
+ Loop->AddLoopTag ( CIFTAG_SEQ_NUM );
+ Loop->AddLoopTag ( CIFTAG_NDB_PDB_INS_CODE );
+ Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_NAME );
+ Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_ACCESSION_CODE );
+ Loop->AddLoopTag ( CIFTAG_DB_MON_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_SEQ_NUM );
+ Loop->AddLoopTag ( CIFTAG_DETAILS );
+ }
+
+ Loop->AddString ( chain->GetEntryID(),true );
+ Loop->AddString ( resName ,true );
+ Loop->AddString ( chain->chainID ,true );
+ Loop->AddInteger ( seqNum );
+ Loop->AddString ( insCode ,true );
+ Loop->AddString ( database ,true );
+ Loop->AddString ( dbAccession ,true );
+ Loop->AddString ( dbRes ,true );
+ Loop->AddInteger ( dbSeq );
+ Loop->AddString ( conflict ,true );
+
+ }
+
+ ERROR_CODE SeqAdv::GetCIF ( mmcif::PData CIF, int & n ) {
+ // GetCIF(..) must be always run without reference to Chain,
+ // see CModel::GetCIF(..).
+ mmcif::PLoop Loop;
+ pstr F;
+ int RC;
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_REF_SEQ_DIF );
+ if (!Loop) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+ if (n>=Loop->GetLoopLength()) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+ // Determine the ChainID first and store it locally. It will
+ // be used by CModel for generating chains and placing the
+ // primary structure data BEFORE reading the coordinate section.
+
+ F = Loop->GetString ( CIFTAG_NDB_PDB_CHAIN_ID,n,RC );
+ if ((!RC) && F) {
+ strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
+ Loop->DeleteField ( CIFTAG_NDB_PDB_CHAIN_ID,n );
+ } else
+ strcpy ( chainID,"" );
+
+ CIFGetString ( resName,Loop,CIFTAG_MON_ID,n,sizeof(ResName),
+ pstr("UNK") );
+
+ CIFGetIntegerD ( seqNum,Loop,CIFTAG_SEQ_NUM );
+
+ CIFGetString ( insCode,Loop,CIFTAG_NDB_PDB_INS_CODE,
+ n,sizeof(InsCode),pstr(" ") );
+
+ CIFGetString ( database,Loop,CIFTAG_NDB_SEQ_DB_NAME,n,
+ sizeof(DBName),pstr(" ") );
+
+ CIFGetString ( dbAccession,Loop,CIFTAG_NDB_SEQ_DB_ACCESSION_CODE,
+ n,sizeof(DBAcCode),pstr(" ") );
+
+ CIFGetString ( dbRes,Loop,CIFTAG_DB_MON_ID,n,sizeof(ResName),
+ pstr(" ") );
+
+ CIFGetIntegerD ( dbSeq,Loop,CIFTAG_NDB_SEQ_DB_SEQ_NUM );
+ // if (CIFGetInteger1(dbSeq,Loop,CIFTAG_NDB_SEQ_DB_SEQ_NUM,n))
+ // dbSeq = MinInt4;
+
+ F = Loop->GetString ( CIFTAG_DETAILS,n,RC );
+ if ((!RC) && F) {
+ CreateCopy ( conflict,F );
+ Loop->DeleteField ( CIFTAG_DETAILS,n );
+ } else
+ CreateCopy ( conflict,pstr(" ") );
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+ void SeqAdv::Copy ( PContainerClass SeqAdv ) {
+
+ ContainerClass::Copy ( SeqAdv );
+
+ seqNum = PSeqAdv(SeqAdv)->seqNum;
+ dbSeq = PSeqAdv(SeqAdv)->dbSeq;
+ strcpy ( resName ,PSeqAdv(SeqAdv)->resName );
+ strcpy ( insCode ,PSeqAdv(SeqAdv)->insCode );
+ strcpy ( database ,PSeqAdv(SeqAdv)->database );
+ strcpy ( dbAccession,PSeqAdv(SeqAdv)->dbAccession );
+ strcpy ( dbRes ,PSeqAdv(SeqAdv)->dbRes );
+ CreateCopy ( conflict,PSeqAdv(SeqAdv)->conflict );
+
+ }
+
+ void SeqAdv::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &seqNum );
+ f.WriteInt ( &dbSeq );
+ f.WriteTerLine ( resName ,false );
+ f.WriteTerLine ( insCode ,false );
+ f.WriteTerLine ( database ,false );
+ f.WriteTerLine ( dbAccession,false );
+ f.WriteTerLine ( dbRes ,false );
+ f.CreateWrite ( conflict );
+ }
+
+ void SeqAdv::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &seqNum );
+ f.ReadInt ( &dbSeq );
+ f.ReadTerLine ( resName ,false );
+ f.ReadTerLine ( insCode ,false );
+ f.ReadTerLine ( database ,false );
+ f.ReadTerLine ( dbAccession,false );
+ f.ReadTerLine ( dbRes ,false );
+ f.CreateRead ( conflict );
+ }
+
+ MakeStreamFunctions(SeqAdv)
+
+
+
+ // ================ SeqRes ===================
+
+ SeqRes::SeqRes() : io::Stream() {
+ InitSeqRes();
+ }
+
+ SeqRes::SeqRes ( io::RPStream Object ) : io::Stream(Object) {
+ InitSeqRes();
+ }
+
+ SeqRes::~SeqRes() {
+ FreeMemory();
+ }
+
+ void SeqRes::SetChain ( PChain Chain_Owner ) {
+ chain = Chain_Owner;
+ if (chain) strcpy ( chainID,chain->chainID );
+ else strcpy ( chainID,"" );
+ }
+
+ void SeqRes::InitSeqRes() {
+ chain = NULL;
+ numRes = -1;
+ resName = NULL;
+ serNum = 0;
+ strcpy ( chainID,"" );
+ }
+
+ void SeqRes::FreeMemory() {
+ if (resName) delete[] resName;
+ resName = NULL;
+ numRes = -1;
+ serNum = 0;
+ }
+
+ void SeqRes::PDBASCIIDump ( io::RFile f ) {
+ // writes the ASCII PDB SEQRES lines into file f
+ char S[100];
+ int i,k,sN;
+ if (numRes<0) return;
+ strcpy ( S,"SEQRES" );
+ PadSpaces ( S,80 );
+ if (chain->chainID[0])
+ S[11] = chain->chainID[0];
+ PutInteger ( &(S[13]),numRes,4 );
+ if (resName) {
+ i = 0;
+ sN = 1;
+ while (i<numRes) {
+ PutInteger ( &(S[7]),sN,3 );
+ k = 19;
+ while ((i<numRes) && (k<70)) {
+ if (resName[i][0])
+ strcpy_n ( &(S[k]),resName[i],3 );
+ else strcpy_n ( &(S[k]),pstr(" "),3 );
+ i++;
+ k += 4;
+ }
+ while (k<70) {
+ strcpy_n ( &(S[k]),pstr(" "),3 );
+ k += 4;
+ }
+ f.WriteLine ( S );
+ sN++;
+ }
+ } else {
+ S[9] = '0';
+ strcpy_n ( &(S[19]),pstr("UNK"),3 );
+ f.WriteLine ( S );
+ }
+ }
+
+ ERROR_CODE SeqRes::ConvertPDBASCII ( cpstr S ) {
+ int i,k,sN,nR;
+ if (chain->chainID[0]) {
+ if (S[11]!=chain->chainID[0])
+ return Error_WrongChainID;
+ } else if (S[11]!=' ') {
+ chain->chainID[0] = S[11];
+ chain->chainID[1] = char(0);
+ } else
+ chain->chainID[0] = char(0);
+ GetInteger ( sN,&(S[8]) ,3 );
+ GetInteger ( nR,&(S[13]),4 );
+ if (sN==0) {
+ FreeMemory();
+ numRes = nR;
+ } else {
+ serNum++;
+ if (sN!=serNum)
+ return Error_SEQRES_serNum;
+ if (sN==1) {
+ FreeMemory();
+ resName = new ResName[nR];
+ for (i=0;i<nR;i++)
+ resName[i][0] = char(0);
+ numRes = nR;
+ serNum = sN;
+ } else if (nR!=numRes)
+ return Error_SEQRES_numRes;
+ i = 0;
+ while ((i<nR) && (resName[i][0])) i++;
+ if (i>=nR)
+ return Error_SEQRES_extraRes;
+ k = 19;
+ while ((i<nR) && (k<70)) {
+ GetString ( resName[i],&(S[k]),3 );
+ if (!strcmp(resName[i]," ")) resName[i][0] = char(0);
+ else i++;
+ k += 4;
+ }
+ }
+ return Error_NoError;
+ }
+
+
+ void SeqRes::MakeCIF ( mmcif::PData CIF ) {
+ // Note that SeqRes only adds sequence to the CIF loop common
+ // to all chains. Therefore this loop should be wiped off from
+ // CIF structure before putting first sequence into it.
+ mmcif::PLoop Loop;
+ int RC,i;
+
+ if (numRes<0) return;
+
+ RC = CIF->AddLoop ( CIFCAT_NDB_POLY_SEQ_SCHEME,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_MON_ID );
+ }
+
+ if (resName)
+ for (i=0;i<numRes;i++) {
+ Loop->AddString ( chain->chainID,true );
+ Loop->AddString ( resName[i] ,true );
+ }
+ else
+ for (i=0;i<numRes;i++) {
+ Loop->AddString ( chain->GetEntryID(),true );
+ Loop->AddString ( pstr("UNK") ,true );
+ }
+
+ }
+
+ ERROR_CODE SeqRes::GetCIF ( mmcif::PData CIF ) {
+ // Tries to get sequence from the CIF structure. A sequence
+ // for first met chain is extracted and then removed from
+ // the CIF structure, so that sequential calls will extract
+ // all sequencies. Chain ID is stored locally in chainID;
+ // reference to parent chain is neither used nor checked.
+ // Returns 0 if sequence was extracted and 1 otherwise.
+ mmcif::PLoop Loop;
+ ResName * rN;
+ ChainID chID;
+ pstr F;
+ cpstr CHAIN_ID;
+ int RC,i,l;
+ CIF_MODE CIFMode;
+ bool isMon;
+
+ FreeMemory();
+
+ CIFMode = CIF_NDB;
+ Loop = CIF->GetLoop ( CIFName(CAT_POLY_SEQ_SCHEME,CIFMode) );
+ if (!Loop) {
+ CIFMode = CIF_PDBX;
+ Loop = CIF->GetLoop ( CIFName(CAT_POLY_SEQ_SCHEME,CIFMode) );
+ if (!Loop) return Error_NoLoop;
+ }
+
+ l = Loop->GetLoopLength();
+ if (l<=0) return Error_NoLoop;
+
+ rN = new ResName[l];
+ chainID[0] = char(1);
+ numRes = 0;
+ isMon = false;
+ CHAIN_ID = CIFName(TAG_SEQ_CHAIN_ID,CIFMode);
+ for (i=0;i<l;i++) {
+ F = Loop->GetString ( CHAIN_ID,i,RC );
+ if (!RC) {
+ if (F) strcpy ( chID,F );
+ else chID[0] = char(0);
+ if (chainID[0]==char(1)) strcpy ( chainID,chID );
+ if (!strcmp(chainID,chID)) {
+ CIFGetString ( rN[numRes],Loop,CIFTAG_MON_ID,i,
+ sizeof(ResName),pstr("UNK") );
+ Loop->DeleteField ( CHAIN_ID,i );
+ if (strcmp(rN[numRes],"UNK")) isMon = true;
+ numRes++;
+ }
+ }
+ }
+
+ if (numRes==0) {
+ numRes = -1;
+ delete[] rN;
+ return Error_EmptyCIFLoop;
+ }
+
+ if (isMon) {
+ resName = new ResName[numRes];
+ for (i=0;i<numRes;i++)
+ strcpy ( resName[i],rN[i] );
+ }
+
+ delete[] rN;
+
+ return Error_NoError;
+
+ }
+
+ void SeqRes::Copy ( PSeqRes SeqRes ) {
+ int i;
+
+ FreeMemory();
+
+ numRes = SeqRes->numRes;
+ serNum = SeqRes->serNum;
+
+ if (SeqRes->resName) {
+ resName = new ResName[numRes];
+ for (i=0;i<numRes;i++)
+ strcpy ( resName[i],SeqRes->resName[i] );
+ }
+
+ }
+
+ void SeqRes::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &numRes );
+ f.WriteInt ( &serNum );
+ if (resName) i = 1;
+ else i = 0;
+ f.WriteInt ( &i );
+ if (resName)
+ for (i=0;i<numRes;i++)
+ f.WriteTerLine ( resName[i],false );
+ }
+
+ void SeqRes::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ FreeMemory();
+ f.ReadByte ( &Version );
+ f.ReadInt ( &numRes );
+ f.ReadInt ( &serNum );
+ f.ReadInt ( &i );
+ if (i) {
+ resName = new ResName[numRes];
+ for (i=0;i<numRes;i++)
+ f.ReadTerLine ( resName[i],false );
+ }
+ }
+
+
+ MakeStreamFunctions(SeqRes)
+
+
+
+ // ================ ModRes ===================
+
+ ModRes::ModRes() : ContainerChain() {
+ InitModRes();
+ }
+
+ ModRes::ModRes ( PChain Chain_Owner )
+ : ContainerChain(Chain_Owner) {
+ InitModRes();
+ }
+
+ ModRes::ModRes ( PChain Chain_Owner, cpstr S )
+ : ContainerChain(Chain_Owner) {
+ InitModRes();
+ ConvertPDBASCII ( S );
+ }
+
+ ModRes::ModRes ( io::RPStream Object ) : ContainerChain(Object) {
+ InitModRes();
+ }
+
+ ModRes::~ModRes() {
+ if (comment) delete[] comment;
+ }
+
+ void ModRes::InitModRes() {
+ strcpy ( resName,"---" );
+ seqNum = 0;
+ strcpy ( insCode,"-" );
+ comment = NULL;
+ CreateCopy ( comment,pstr(" ") );
+ strcpy ( stdRes ,"---" );
+ }
+
+ void ModRes::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+ // makes the ASCII PDB MODRES line number N
+ // from the class' data
+ strcpy ( S,"MODRES" );
+ PadSpaces ( S,80 );
+ strcpy_n ( &(S[7]) ,chain->GetEntryID(),4 );
+ strcpy_n ( &(S[12]),resName ,3 );
+ if (chain->chainID[0]) S[16] = chain->chainID[0];
+ PutIntIns ( &(S[18]),seqNum,4,insCode );
+ strcpy_n ( &(S[24]),stdRes ,3 );
+ strcpy_n ( &(S[29]),comment,IMin(strlen(comment),41) );
+ }
+
+ ERROR_CODE ModRes::ConvertPDBASCII ( cpstr S ) {
+ IDCode idCode;
+ if (chain->chainID[0]) {
+ if (S[16]!=chain->chainID[0])
+ return Error_WrongChainID;
+ } else if (S[16]!=' ') {
+ chain->chainID[0] = S[16];
+ chain->chainID[1] = char(0);
+ } else
+ chain->chainID[0] = char(0);
+ strcpy ( idCode,chain->GetEntryID() );
+ if (idCode[0]) {
+ if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
+ return Error_WrongEntryID;
+ } else {
+ GetString ( idCode,&(S[7]),4 );
+ chain->SetEntryID ( idCode );
+ }
+ GetString ( resName ,&(S[12]),3 );
+ GetIntIns ( seqNum,insCode,&(S[18]),4 );
+ GetString ( stdRes ,&(S[24]),3 );
+ CreateCopy ( comment ,&(S[29]) );
+ CutSpaces ( comment,SCUTKEY_END );
+ return Error_NoError;
+ }
+
+ void ModRes::MakeCIF ( mmcif::PData CIF, int N ) {
+ UNUSED_ARGUMENT(CIF);
+ UNUSED_ARGUMENT(N);
+ /* -- apparently wrong use of _struct_conn, to be revised
+ mmcif::PLoop Loop;
+ int RC;
+
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_CONN,Loop );
+
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_PDB_ID );
+ Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_PTNR1_LABEL_INS_CODE );
+ Loop->AddLoopTag ( CIFTAG_NDB_PTNR1_STANDARD_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_DETAILS );
+ }
+
+ Loop->AddString ( pstr("MODRES") );
+ Loop->AddString ( chain->GetEntryID(),true );
+ Loop->AddString ( resName ,true );
+ Loop->AddString ( chain->chainID ,true );
+ Loop->AddInteger ( seqNum );
+ Loop->AddString ( insCode ,true );
+ Loop->AddString ( stdRes ,true );
+ Loop->AddString ( comment ,true );
+
+ */
+
+ }
+
+ ERROR_CODE ModRes::GetCIF ( mmcif::PData CIF, int & n ) {
+ UNUSED_ARGUMENT(CIF);
+ // GetCIF(..) must be always run without reference to Chain,
+ // see CModel::GetCIF(..).
+
+ /* -- apparently wrong use of _struct_conn, to be revised
+ mmcif::PLoop Loop;
+ pstr F;
+ int l,RC;
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
+ if (!Loop) {
+ n = -1;
+ return;
+ }
+
+ l = Loop->GetLoopLength();
+ while (n<l) {
+ F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,n,RC );
+ if ((!RC) && F) {
+ if (!strcmp(F,"MODRES")) break;
+ }
+ n++;
+ }
+ if (n>=l) {
+ n = -1;
+ return;
+ }
+
+ Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,n );
+
+ // Determine the ChainID first and store it locally. It will
+ // be used by CModel for generating chains and placing the
+ // primary structure data BEFORE reading the coordinate section.
+ F = Loop->GetString ( CIFTAG_PTNR1_LABEL_ASYM_ID,n,RC );
+ if ((!RC) && F) {
+ strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
+ Loop->DeleteField ( CIFTAG_PTNR1_LABEL_ASYM_ID,n );
+ } else
+ strcpy ( chainID,"" );
+
+
+ CIFGetString ( resName,Loop,CIFTAG_PTNR1_LABEL_COMP_ID,n,
+ sizeof(ResName),pstr("UNK") );
+
+ if (CIFGetInteger(seqNum,Loop,CIFTAG_PTNR1_LABEL_SEQ_ID,n))
+ return;
+
+ CIFGetString ( insCode,Loop,CIFTAG_NDB_PTNR1_LABEL_INS_CODE,
+ n,sizeof(InsCode),pstr(" ") );
+
+ CIFGetString ( stdRes,Loop,CIFTAG_NDB_PTNR1_STANDARD_COMP_ID,n,
+ sizeof(ResName),pstr("UNK") );
+
+ F = Loop->GetString ( CIFTAG_DETAILS,n,RC );
+ if ((!RC) && F) {
+ CreateCopy ( comment,F );
+ Loop->DeleteField ( CIFTAG_DETAILS,n );
+ } else
+ CreateCopy ( comment,pstr(" ") );
+
+ n++;
+
+ */
+
+ n = -1;
+
+ return Error_EmptyCIF;
+
+ }
+
+ void ModRes::Copy ( PContainerClass ModRes ) {
+ seqNum = PModRes(ModRes)->seqNum;
+ strcpy ( resName,PModRes(ModRes)->resName );
+ strcpy ( insCode,PModRes(ModRes)->insCode );
+ strcpy ( stdRes ,PModRes(ModRes)->stdRes );
+ CreateCopy ( comment,PModRes(ModRes)->comment );
+ }
+
+ void ModRes::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &seqNum );
+ f.WriteTerLine ( resName,false );
+ f.WriteTerLine ( insCode,false );
+ f.WriteTerLine ( stdRes ,false );
+ f.CreateWrite ( comment );
+ }
+
+ void ModRes::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &seqNum );
+ f.ReadTerLine ( resName,false );
+ f.ReadTerLine ( insCode,false );
+ f.ReadTerLine ( stdRes ,false );
+ f.CreateRead ( comment );
+ }
+
+ MakeStreamFunctions(ModRes)
+
+
+
+ // ================ HetRec ======================
+
+ HetRec::HetRec() : ContainerChain() {
+ InitHetRec();
+ }
+
+ HetRec::HetRec ( PChain Chain_Owner )
+ : ContainerChain(Chain_Owner) {
+ InitHetRec();
+ }
+
+ HetRec::HetRec ( PChain Chain_Owner, cpstr S )
+ : ContainerChain(Chain_Owner) {
+ InitHetRec();
+ ConvertPDBASCII ( S );
+ }
+
+ HetRec::HetRec ( io::RPStream Object ) : ContainerChain(Object) {
+ InitHetRec();
+ }
+
+ HetRec::~HetRec() {
+ if (comment) delete[] comment;
+ }
+
+ void HetRec::InitHetRec() {
+ strcpy ( hetID ,"---" );
+ strcpy ( insCode,"-" );
+ seqNum = 0;
+ numHetAtoms = 0;
+ comment = NULL;
+ CreateCopy ( comment,pstr(" ") );
+ }
+
+ void HetRec::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+ // makes the ASCII PDB MODRES line number N
+ // from the class' data
+ strcpy ( S,"HET" );
+ PadSpaces ( S,80 );
+ strcpy_n ( &(S[7]) ,hetID,3 );
+ if (chain->chainID[0]) S[12] = chain->chainID[0];
+ PutIntIns ( &(S[13]),seqNum,4,insCode );
+ PutInteger ( &(S[20]),numHetAtoms,5 );
+ strcpy_n ( &(S[30]),comment,IMin(strlen(comment),40) );
+ }
+
+ ERROR_CODE HetRec::ConvertPDBASCII ( cpstr S ) {
+ if (chain->chainID[0]) {
+ if (S[12]!=chain->chainID[0])
+ return Error_WrongChainID;
+ } else if (S[12]!=' ') {
+ chain->chainID[0] = S[12];
+ chain->chainID[1] = char(0);
+ } else
+ chain->chainID[0] = char(0);
+ GetString ( hetID ,&(S[7]) ,3 );
+ GetIntIns ( seqNum,insCode,&(S[13]),4 );
+ GetInteger ( numHetAtoms ,&(S[20]),5 );
+ CreateCopy ( comment ,&(S[30]) );
+ CutSpaces ( comment,SCUTKEY_END );
+ return Error_NoError;
+ }
+
+ void HetRec::MakeCIF ( mmcif::PData CIF, int N ) {
+ UNUSED_ARGUMENT(N);
+ mmcif::PLoop Loop;
+ int RC;
+
+ RC = CIF->AddLoop ( CIFCAT_NDB_NONSTANDARD_LIST,Loop );
+
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_AUTH_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_AUTH_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_INS_CODE );
+ Loop->AddLoopTag ( CIFTAG_NUMBER_ATOMS_NH );
+ Loop->AddLoopTag ( CIFTAG_DETAILS );
+ }
+
+ Loop->AddString ( hetID ,true );
+ Loop->AddString ( chain->chainID,true );
+ Loop->AddInteger ( seqNum );
+ Loop->AddString ( insCode ,true );
+ Loop->AddInteger ( numHetAtoms );
+ Loop->AddString ( comment ,true );
+
+ }
+
+ ERROR_CODE HetRec::GetCIF ( mmcif::PData CIF, int & n ) {
+ // GetCIF(..) must be always run without reference to Chain,
+ // see CModel::GetCIF(..).
+ mmcif::PLoop Loop;
+ pstr F;
+ int RC;
+ ERROR_CODE rc;
+
+ Loop = CIF->GetLoop ( CIFCAT_NDB_NONSTANDARD_LIST );
+ if (!Loop) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+ if (n>=Loop->GetLoopLength()) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+ // Determine the ChainID first and store it locally. It will
+ // be used by CModel for generating chains and placing the
+ // primary structure data BEFORE reading the coordinate section.
+ F = Loop->GetString ( CIFTAG_AUTH_ASYM_ID,n,RC );
+ if ((!RC) && F) {
+ strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
+ Loop->DeleteField ( CIFTAG_AUTH_ASYM_ID,n );
+ } else
+ strcpy ( chainID,"" );
+
+
+ CIFGetString ( hetID,Loop,CIFTAG_ID,n,sizeof(ResName),
+ pstr("UNK") );
+
+ rc = CIFGetInteger ( seqNum,Loop,CIFTAG_AUTH_SEQ_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( insCode,Loop,CIFTAG_INS_CODE,n,sizeof(InsCode),
+ pstr(" ") );
+
+ rc = CIFGetInteger ( numHetAtoms,Loop,CIFTAG_NUMBER_ATOMS_NH,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ F = Loop->GetString ( CIFTAG_DETAILS,n,RC );
+ if ((!RC) && F) {
+ CreateCopy ( comment,F );
+ Loop->DeleteField ( CIFTAG_DETAILS,n );
+ } else
+ CreateCopy ( comment,pstr(" ") );
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+ void HetRec::Copy ( PContainerClass Het ) {
+ seqNum = PHetRec(Het)->seqNum;
+ numHetAtoms = PHetRec(Het)->numHetAtoms;
+ strcpy ( hetID ,PHetRec(Het)->hetID );
+ strcpy ( insCode,PHetRec(Het)->insCode );
+ CreateCopy ( comment,PHetRec(Het)->comment );
+ }
+
+ void HetRec::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &seqNum );
+ f.WriteInt ( &numHetAtoms );
+ f.WriteTerLine ( hetID ,false );
+ f.WriteTerLine ( insCode,false );
+ f.CreateWrite ( comment );
+ }
+
+ void HetRec::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &seqNum );
+ f.ReadInt ( &numHetAtoms );
+ f.ReadTerLine ( hetID ,false );
+ f.ReadTerLine ( insCode,false );
+ f.CreateRead ( comment );
+ }
+
+ MakeStreamFunctions(HetRec)
+
+
+
+ // ===================== Chain =======================
+
+ Chain::Chain() : UDData() {
+ InitChain();
+ SetChain ( pstr("") );
+ }
+
+ Chain::Chain ( PProModel Model, const ChainID chID ) : UDData() {
+ InitChain();
+ SetChain ( chID );
+ if (Model) Model->AddChain ( this );
+ }
+
+ Chain::Chain ( io::RPStream Object ) : UDData(Object) {
+ InitChain();
+ SetChain ( pstr("") );
+ }
+
+ void Chain::InitChain() {
+ nResidues = 0;
+ resLen = 0;
+ residue = NULL;
+ model = NULL;
+ chainID[0] = char(0);
+ prevChainID[0] = char(0);
+ nWeights = 0;
+ Weight = 0.0;
+ Exclude = true;
+ }
+
+ void Chain::SetChain ( const ChainID chID ) {
+ strcpy ( chainID,chID );
+ if (chID[0]==' ') chainID[0] = char(0);
+ DBRef .SetChain ( this );
+ seqAdv.SetChain ( this );
+ seqRes.SetChain ( this );
+ modRes.SetChain ( this );
+ Het .SetChain ( this );
+ }
+
+ void Chain::SetChainID ( const ChainID chID ) {
+ strcpy ( chainID,chID );
+ if (chID[0]==' ') chainID[0] = char(0);
+ }
+
+ Chain::~Chain() {
+ FreeMemory();
+ if (model) model->_ExcludeChain ( chainID );
+ }
+
+ void Chain::FreeMemory() {
+ DeleteAllResidues();
+ if (residue) delete[] residue;
+ resLen = 0;
+ nResidues = 0;
+ residue = NULL;
+ FreeAnnotations();
+ }
+
+ void Chain::FreeAnnotations() {
+ DBRef .FreeContainer();
+ seqAdv.FreeContainer();
+ seqRes.FreeMemory ();
+ modRes.FreeContainer();
+ Het .FreeContainer();
+ }
+
+ void Chain::SetModel ( PProModel Model ) {
+ model = Model;
+ }
+
+ PManager Chain::GetCoordHierarchy() {
+ if (model) return model->GetCoordHierarchy();
+ return NULL;
+ }
+
+ void Chain::CheckInAtoms() {
+ int i;
+ if (GetCoordHierarchy())
+ for (i=0;i<nResidues;i++)
+ if (residue[i])
+ residue[i]->CheckInAtoms();
+ }
+
+ ERROR_CODE Chain::ConvertDBREF ( cpstr PDBString ) {
+ PContainerChain ContainerChain;
+ ERROR_CODE RC;
+ ContainerChain = new DBReference(this);
+ RC = ContainerChain->ConvertPDBASCII ( PDBString );
+ if (RC) {
+ delete ContainerChain;
+ return RC;
+ }
+ DBRef.AddData ( ContainerChain );
+ return Error_NoError;
+ }
+
+ ERROR_CODE Chain::ConvertSEQADV ( cpstr PDBString ) {
+ PContainerChain ContainerChain;
+ ERROR_CODE RC;
+ ContainerChain = new SeqAdv(this);
+ RC = ContainerChain->ConvertPDBASCII ( PDBString );
+ if (RC) {
+ delete ContainerChain;
+ return RC;
+ }
+ seqAdv.AddData ( ContainerChain );
+ return Error_NoError;
+ }
+
+ ERROR_CODE Chain::ConvertSEQRES ( cpstr PDBString ) {
+ return seqRes.ConvertPDBASCII ( PDBString );
+ }
+
+ ERROR_CODE Chain::ConvertMODRES ( cpstr PDBString ) {
+ PContainerChain ContainerChain;
+ ERROR_CODE RC;
+ ContainerChain = new ModRes(this);
+ RC = ContainerChain->ConvertPDBASCII ( PDBString );
+ if (RC) {
+ delete ContainerChain;
+ return RC;
+ }
+ modRes.AddData ( ContainerChain );
+ return Error_NoError;
+ }
+
+ ERROR_CODE Chain::ConvertHET ( cpstr PDBString ) {
+ PContainerChain ContainerChain;
+ ERROR_CODE RC;
+ ContainerChain = new HetRec(this);
+ RC = ContainerChain->ConvertPDBASCII ( PDBString );
+ if (RC) {
+ delete ContainerChain;
+ return RC;
+ }
+ Het.AddData ( ContainerChain );
+ return Error_NoError;
+ }
+
+
+ void Chain::PDBASCIIDump ( io::RFile f ) {
+ // this function was for test purposes and is not used
+ // for normal function of MMDB
+ DBRef .PDBASCIIDump ( f );
+ seqAdv.PDBASCIIDump ( f );
+ seqRes.PDBASCIIDump ( f );
+ modRes.PDBASCIIDump ( f );
+ Het .PDBASCIIDump ( f );
+ }
+
+ void Chain::PDBASCIIAtomDump ( io::RFile f ) {
+ int i;
+ for (i=0;i<nResidues;i++)
+ if (residue[i])
+ residue[i]->PDBASCIIAtomDump ( f );
+ }
+
+ void Chain::MakeAtomCIF ( mmcif::PData CIF ) {
+ int i;
+ for (i=0;i<nResidues;i++)
+ if (residue[i])
+ residue[i]->MakeAtomCIF ( CIF );
+ }
+
+
+ int Chain::GetNumberOfResidues() {
+ return nResidues;
+ }
+
+ PResidue Chain::GetResidue ( int resNo ) {
+ if ((0<=resNo) && (resNo<nResidues))
+ return residue[resNo];
+ else return NULL;
+ }
+
+
+ PResidue Chain::GetResidueCreate ( const ResName resName,
+ int seqNum,
+ const InsCode insCode,
+ bool Enforce ) {
+ // Returns pointer on residue, whose name, sequence number and
+ // insert code are given in resName, seqNum and insCode, respectively.
+ // If such a residue is absent in the chain, one is created at
+ // the end of the chain.
+ int i;
+
+ // check if such a residue is already in the chain
+ if (insCode[0]) {
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if ((seqNum==residue[i]->seqNum) &&
+ (!strcmp(insCode,residue[i]->insCode))) {
+ if (!strcmp(resName,residue[i]->name))
+ return residue[i]; // it is there; just return the pointer
+ else if (!Enforce)
+ return NULL; // duplicate seqNum and insCode!
+ }
+ }
+ } else {
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if ((seqNum==residue[i]->seqNum) &&
+ (!residue[i]->insCode[0])) {
+ if (!strcmp(resName,residue[i]->name))
+ return residue[i]; // it is there; just return the pointer
+ else if (!Enforce)
+ return NULL; // duplicate seqNum and insCode!
+ }
+ }
+ }
+
+ // expand the residue array, if necessary
+ if (nResidues>=resLen)
+ ExpandResidueArray ( 100 );
+
+ // create new residue
+ residue[nResidues] = newResidue();
+ residue[nResidues]->SetChain ( this );
+ residue[nResidues]->SetResID ( resName,seqNum,insCode );
+ residue[nResidues]->index = nResidues;
+ nResidues++;
+
+ return residue[nResidues-1];
+
+ }
+
+ void Chain::ExpandResidueArray ( int inc ) {
+ PPResidue Residue1;
+ int i;
+ resLen += inc;
+ Residue1 = new PResidue[resLen];
+ for (i=0;i<nResidues;i++)
+ Residue1[i] = residue[i];
+ if (residue) delete[] residue;
+ residue = Residue1;
+ for (i=nResidues;i<resLen;i++)
+ residue[i] = NULL;
+ }
+
+ PResidue Chain::GetResidue ( int seqNum, const InsCode insCode ) {
+ // Returns pointer on residue, whose sequence number and
+ // insert code are given in seqNum and insCode, respectively.
+ // If such a residue is absent in the chain, returns NULL.
+ int i;
+ bool isInsCode;
+ if (insCode) isInsCode = insCode[0]!=char(0);
+ else isInsCode = false;
+ if (isInsCode) {
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if ((seqNum==residue[i]->seqNum) &&
+ (!strcmp(insCode,residue[i]->insCode)))
+ return residue[i];
+ }
+ } else {
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if ((seqNum==residue[i]->seqNum) && (!residue[i]->insCode[0]))
+ return residue[i];
+ }
+ }
+ return NULL;
+ }
+
+ int Chain::GetResidueNo ( int seqNum, const InsCode insCode ) {
+ // GetResidueNo(..) returns the residue number in the chain's
+ // residues table. Residues are numbered as 0..nres-1 as they appear
+ // in the coordinate file.
+ // If residue is not found, the function returns -1.
+ int i;
+ bool isInsCode;
+ if (insCode) isInsCode = insCode[0]!=char(0);
+ else isInsCode = false;
+ if (isInsCode) {
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if ((seqNum==residue[i]->seqNum) &&
+ (!strcmp(insCode,residue[i]->insCode)))
+ return i;
+ }
+ } else {
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if ((seqNum==residue[i]->seqNum) && (!residue[i]->insCode[0]))
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ void Chain::GetResidueTable ( PPResidue & resTable,
+ int & NumberOfResidues ) {
+ resTable = residue;
+ NumberOfResidues = nResidues;
+ }
+
+ int Chain::_ExcludeResidue ( const ResName resName, int seqNum,
+ const InsCode insCode ) {
+ // ExcludeResidue(..) excludes (but does not dispose!) a residue
+ // from the chain. Returns 1 if the chain gets empty and 0 otherwise.
+ int i,k;
+
+ if (!Exclude) return 0;
+
+ // find the residue
+ k = -1;
+ for (i=0;(i<nResidues) && (k<0);i++)
+ if ((seqNum==residue[i]->seqNum) &&
+ (!strcmp(insCode,residue[i]->insCode)) &&
+ (!strcmp(resName,residue[i]->name)))
+ k = i;
+
+ if (k>=0) {
+ for (i=k+1;i<nResidues;i++) {
+ residue[i-1] = residue[i];
+ if (residue[i-1])
+ residue[i-1]->index = i-1;
+ }
+ nResidues--;
+ residue[nResidues] = NULL;
+ }
+
+ if (nResidues<=0) return 1;
+ else return 0;
+
+ }
+
+
+
+ // ------------------ Deleting residues --------------------------
+
+ int Chain::DeleteResidue ( int resNo ) {
+ if ((0<=resNo) && (resNo<nResidues)) {
+ if (residue[resNo]) {
+ Exclude = false;
+ delete residue[resNo];
+ residue[resNo] = NULL;
+ Exclude = true;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ int Chain::DeleteResidue ( int seqNum, const InsCode insCode ) {
+ int i;
+ if (insCode[0]) {
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if ((seqNum==residue[i]->seqNum) &&
+ (!strcmp(insCode,residue[i]->insCode))) {
+ Exclude = false;
+ delete residue[i];
+ residue[i] = NULL;
+ Exclude = true;
+ return 1;
+ }
+ }
+ } else {
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if ((seqNum==residue[i]->seqNum) && (!residue[i]->insCode[0])) {
+ Exclude = false;
+ delete residue[i];
+ residue[i] = NULL;
+ Exclude = true;
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+
+
+ int Chain::DeleteAllResidues() {
+ int i,k;
+ Exclude = false;
+ k = 0;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ delete residue[i];
+ residue[i] = NULL;
+ k++;
+ }
+ nResidues = 0;
+ Exclude = true;
+ return k;
+ }
+
+
+ int Chain::DeleteSolvent() {
+ int i,k;
+ Exclude = false;
+ k = 0;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if (residue[i]->isSolvent()) {
+ delete residue[i];
+ residue[i] = NULL;
+ k++;
+ }
+ }
+ Exclude = true;
+ return k;
+ }
+
+
+ void Chain::TrimResidueTable() {
+ int i,j;
+ Exclude = false;
+ j = 0;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) {
+ if (residue[i]->nAtoms>0) {
+ if (j<i) {
+ residue[j] = residue[i];
+ residue[j]->index = j;
+ residue[i] = NULL;
+ }
+ j++;
+ } else {
+ delete residue[i];
+ residue[i] = NULL;
+ }
+ }
+ nResidues = j;
+ Exclude = true;
+ }
+
+ int Chain::AddResidue ( PResidue res ) {
+ // modify both CModel::Copy methods simultaneously!
+ //
+ // Copy(PCModel,PPAtom,int&) copies atoms into array 'atom'
+ // starting from position atom_index. 'atom' should be able to
+ // accept all new atoms - no checks on the length of 'atom'
+ // is being made. This function should not be used in applications.
+ return InsResidue ( res,nResidues );
+ }
+
+ /*
+ PCmmdbRoot mmdbRoot;
+ PChain chain1;
+ int i;
+
+ for (i=0;i<nResidues;i++)
+ if (residue[i]==res) return -i; // this residue is already there
+
+ if (res) {
+
+ mmdbRoot = PCmmdbRoot(GetCoordHierarchy());
+
+ // get space for new residue
+ if (nResidues>=resLen)
+ ExpandResidueArray ( 100 );
+
+ if (res->GetCoordHierarchy()) {
+ residue[nResidues] = newResidue();
+ residue[nResidues]->SetChain ( this );
+ residue[nResidues]->SetResID ( res->name,res->seqNum,res->insCode );
+ if (mmdbRoot) {
+ // get space for new atoms
+ mmdbRoot->AddAtomArray ( res->GetNumberOfAtoms(true) );
+ residue[nResidues]->Copy ( res,mmdbRoot->Atom,mmdbRoot->nAtoms );
+ } else {
+ for (i=0;i<res->nAtoms;i++)
+ residue[nResidues]->AddAtom ( res->atom[i] );
+ }
+ } else {
+ residue[nResidues] = res;
+ chain1 = res->GetChain();
+ if (chain1)
+ for (i=0;i<chain1->nResidues;i++)
+ if (chain1->residue[i]==res) {
+ chain1->residue[i] = NULL;
+ break;
+ }
+ residue[nResidues]->SetChain ( this );
+ if (mmdbRoot)
+ residue[nResidues]->CheckInAtoms();
+ }
+ nResidues++;
+
+ }
+
+ return nResidues;
+
+ }
+ */
+
+ int Chain::InsResidue ( PResidue res, int seqNum,
+ const InsCode insCode ) {
+ return InsResidue ( res,GetResidueNo(seqNum,insCode) );
+ }
+
+ int Chain::InsResidue ( PResidue res, int pos ) {
+ // Inserts residue res onto position pos of the chain,
+ // pos=0..nResidues-1 . Residues pos..nResidues-1 are
+ // shifted up the chain.
+ // The function places new atoms on the top of atom
+ // index. It is advisable to call
+ // CmmdbRoot::PDBCleanup ( PDBCLEAN_INDEX ) after all
+ // insertions are done.
+ PRoot mmdbRoot;
+ PChain chain1;
+ int i,pp;
+
+ pp = IMax ( 0,IMin(nResidues,pos) );
+
+ for (i=0;i<nResidues;i++)
+ if (residue[i]==res) return -i; // this residue is already there
+
+ if (res) {
+
+ mmdbRoot = PRoot(GetCoordHierarchy());
+
+ // get space for new residue
+ if (nResidues>=resLen)
+ ExpandResidueArray ( 100 );
+
+ // shift residues to the end of the chain as necessary
+ for (i=nResidues;i>pp;i--)
+ residue[i] = residue[i-1];
+
+ // insert the new residue
+ if (res->GetCoordHierarchy()) {
+ residue[pp] = newResidue();
+ residue[pp]->SetChain ( this );
+ residue[pp]->SetResID ( res->name,res->seqNum,res->insCode );
+ if (mmdbRoot) {
+ // get space for new atoms
+ mmdbRoot->AddAtomArray ( res->GetNumberOfAtoms(true) );
+ residue[pp]->_copy ( res,mmdbRoot->atom,mmdbRoot->nAtoms );
+ } else {
+ for (i=0;i<res->nAtoms;i++)
+ residue[pp]->AddAtom ( res->atom[i] );
+ }
+ } else {
+ residue[pp] = res;
+ chain1 = res->GetChain();
+ if (chain1)
+ for (i=0;i<chain1->nResidues;i++)
+ if (chain1->residue[i]==res) {
+ chain1->residue[i] = NULL;
+ break;
+ }
+ residue[pp]->SetChain ( this );
+ if (mmdbRoot)
+ residue[pp]->CheckInAtoms();
+ }
+ nResidues++;
+
+ }
+
+ return nResidues;
+
+ }
+
+
+ // -------------------- Extracting atoms -----------------------
+
+ int Chain::GetNumberOfAtoms ( bool countTers ) {
+ int i,na;
+ na = 0;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) na += residue[i]->GetNumberOfAtoms ( countTers );
+ return na;
+ }
+
+ int Chain::GetNumberOfAtoms ( int seqNo, const InsCode insCode ) {
+ PResidue res;
+ res = GetResidue ( seqNo,insCode );
+ if (res) return res->nAtoms;
+ return 0;
+ }
+
+ int Chain::GetNumberOfAtoms ( int resNo ) {
+ if ((0<=resNo) && (resNo<nResidues)) {
+ if (residue[resNo]) return residue[resNo]->nAtoms;
+ }
+ return 0;
+ }
+
+ PAtom Chain::GetAtom ( int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ PResidue res;
+ res = GetResidue ( seqNo,insCode );
+ if (res) return res->GetAtom ( aname,elmnt,aloc );
+ return NULL;
+ }
+
+ PAtom Chain::GetAtom ( int seqNo, const InsCode insCode,
+ int atomNo ) {
+ PResidue res;
+ res = GetResidue ( seqNo,insCode );
+ if (res) {
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ return res->atom[atomNo];
+ }
+ return NULL;
+ }
+
+ PAtom Chain::GetAtom ( int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ if ((0<=resNo) && (resNo<nResidues)) {
+ if (residue[resNo])
+ return residue[resNo]->GetAtom ( aname,elmnt,aloc );
+ }
+ return NULL;
+ }
+
+ PAtom Chain::GetAtom ( int resNo, int atomNo ) {
+ PResidue res;
+ if ((0<=resNo) && (resNo<nResidues)) {
+ res = residue[resNo];
+ if (res) {
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ return res->atom[atomNo];
+ }
+ }
+ return NULL;
+ }
+
+ void Chain::GetAtomTable ( int seqNo, const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ res = GetResidue ( seqNo,insCode );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+
+ void Chain::GetAtomTable ( int resNo, PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ if ((0<=resNo) && (resNo<nResidues)) {
+ res = residue[resNo];
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+ }
+
+
+ void Chain::GetAtomTable1 ( int seqNo, const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms ) {
+ PResidue res;
+ res = GetResidue ( seqNo,insCode );
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void Chain::GetAtomTable1 ( int resNo, PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ if ((0<=resNo) && (resNo<nResidues))
+ res = residue[resNo];
+ else res = NULL;
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ int Chain::DeleteAtom ( int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ PResidue res;
+ res = GetResidue ( seqNo,insCode );
+ if (res) return res->DeleteAtom ( aname,elmnt,aloc );
+ return 0;
+ }
+
+ int Chain::DeleteAtom ( int seqNo, const InsCode insCode,
+ int atomNo ) {
+ PResidue res;
+ res = GetResidue ( seqNo,insCode );
+ if (res) return res->DeleteAtom ( atomNo );
+ return 0;
+ }
+
+ int Chain::DeleteAtom ( int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ if ((0<=resNo) && (resNo<nResidues)) {
+ if (residue[resNo])
+ return residue[resNo]->DeleteAtom ( aname,elmnt,aloc );
+ }
+ return 0;
+ }
+
+ int Chain::DeleteAtom ( int resNo, int atomNo ) {
+ if ((0<=resNo) && (resNo<nResidues)) {
+ if (residue[resNo])
+ return residue[resNo]->DeleteAtom ( atomNo );
+ }
+ return 0;
+ }
+
+
+ int Chain::DeleteAllAtoms ( int seqNo, const InsCode insCode ) {
+ PResidue res;
+ res = GetResidue ( seqNo,insCode );
+ if (res) return res->DeleteAllAtoms();
+ return 0;
+ }
+
+ int Chain::DeleteAllAtoms ( int resNo ) {
+ if ((0<=resNo) && (resNo<nResidues)) {
+ if (residue[resNo])
+ return residue[resNo]->DeleteAllAtoms();
+ }
+ return 0;
+ }
+
+ int Chain::DeleteAllAtoms() {
+ int i,k;
+ k = 0;
+ for (i=0;i<nResidues;i++)
+ if (residue[i])
+ k += residue[i]->DeleteAllAtoms();
+ return k;
+ }
+
+ int Chain::DeleteAltLocs() {
+ // This function leaves only alternative location with maximal
+ // occupancy, if those are equal or unspecified, the one with
+ // "least" alternative location indicator.
+ // The function returns the number of deleted. All tables remain
+ // untrimmed, so that explicit trimming or calling FinishStructEdit()
+ // is required.
+ int i,n;
+
+ n = 0;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) n += residue[i]->DeleteAltLocs();
+
+ return n;
+
+ }
+
+
+ int Chain::AddAtom ( int seqNo, const InsCode insCode,
+ PAtom atom ) {
+ PResidue res;
+ res = GetResidue ( seqNo,insCode );
+ if (res) return res->AddAtom ( atom );
+ return 0;
+ }
+
+ int Chain::AddAtom ( int resNo, PAtom atom ) {
+ if ((0<=resNo) && (resNo<nResidues)) {
+ if (residue[resNo])
+ return residue[resNo]->AddAtom ( atom );
+ }
+ return 0;
+ }
+
+
+ void Chain::Copy ( PChain chain ) {
+ // modify both Chain::_copy and Chain::Copy methods simultaneously!
+ int i;
+
+ FreeMemory();
+
+ if (chain) {
+
+ CopyAnnotations ( chain );
+
+ nResidues = chain->nResidues;
+ resLen = nResidues;
+ if (nResidues>0) {
+ residue = new PResidue[nResidues];
+ for (i=0;i<nResidues;i++) {
+ residue[i] = newResidue();
+ residue[i]->SetChain ( this );
+ residue[i]->Copy ( chain->residue[i] );
+ }
+ }
+
+ }
+
+ }
+
+ void Chain::CopyAnnotations ( PChain chain ) {
+ if (chain) {
+ strcpy ( chainID ,chain->chainID );
+ strcpy ( prevChainID,chain->prevChainID );
+ DBRef .Copy ( &(chain->DBRef) );
+ seqAdv.Copy ( &(chain->seqAdv) ); // SEQADV records
+ seqRes.Copy ( &(chain->seqRes) ); // SEQRES data
+ modRes.Copy ( &(chain->modRes) ); // MODRES records
+ Het .Copy ( &(chain->Het) ); // HET records
+ }
+ }
+
+
+ void Chain::_copy ( PChain chain ) {
+ // modify both Chain::_copy and Chain::Copy methods simultaneously!
+ int i;
+
+ FreeMemory();
+
+ strcpy ( chainID ,chain->chainID );
+ strcpy ( prevChainID,chain->prevChainID );
+
+ DBRef .Copy ( &(chain->DBRef) );
+ seqAdv.Copy ( &(chain->seqAdv) ); // SEQADV records
+ seqRes.Copy ( &(chain->seqRes) ); // SEQRES data
+ modRes.Copy ( &(chain->modRes) ); // MODRES records
+ Het .Copy ( &(chain->Het) ); // HET records
+
+ nResidues = chain->nResidues;
+ resLen = nResidues;
+ if (nResidues>0) {
+ residue = new PResidue[nResidues];
+ for (i=0;i<nResidues;i++) {
+ residue[i] = newResidue();
+ residue[i]->SetChain ( this );
+ residue[i]->_copy ( chain->residue[i] );
+ }
+ }
+
+ }
+
+ void Chain::_copy ( PChain chain, PPAtom atom, int & atom_index ) {
+ // modify both Chain::_copy and Chain::Copy methods simultaneously!
+ int i;
+
+ FreeMemory();
+
+ strcpy ( chainID ,chain->chainID );
+ strcpy ( prevChainID,chain->prevChainID );
+
+ DBRef .Copy ( &(chain->DBRef) );
+ seqAdv.Copy ( &(chain->seqAdv) ); // SEQADV records
+ seqRes.Copy ( &(chain->seqRes) ); // SEQRES data
+ modRes.Copy ( &(chain->modRes) ); // MODRES records
+ Het .Copy ( &(chain->Het) ); // HET records
+
+ nResidues = chain->nResidues;
+ resLen = nResidues;
+ if (nResidues>0) {
+ residue = new PResidue[nResidues];
+ for (i=0;i<nResidues;i++)
+ if (chain->residue[i]) {
+ residue[i] = newResidue();
+ residue[i]->SetChain ( this );
+ residue[i]->_copy ( chain->residue[i],atom,atom_index );
+ } else
+ residue[i] = NULL;
+ }
+
+ }
+
+ /*
+ void Chain::Duplicate ( PChain Chain ) {
+ int i;
+
+ FreeMemory();
+
+ strcpy ( chainID ,chain->chainID );
+ strcpy ( prevChainID,chain->prevChainID );
+
+ DBReference.Copy ( &(chain->DBReference) );
+ SeqAdv .Copy ( &(chain->SeqAdv) ); // SEQADV records
+ SeqRes .Copy ( &(chain->SeqRes) ); // SEQRES data
+ ModRes .Copy ( &(chain->ModRes) ); // MODRES records
+ Het .Copy ( &(chain->Het) ); // HET records
+
+ nResidues = chain->nResidues;
+ resLen = nResidues;
+ if (nResidues>0) {
+ Residue = new PResidue[nResidues];
+ for (i=0;i<nResidues;i++) {
+ residue[i] = newResidue();
+ residue[i]->SetChain ( this );
+ residue[i]->Duplicate ( chain->residue[i] );
+ }
+ }
+
+ }
+ */
+
+ cpstr Chain::GetEntryID() {
+ if (model) return model->GetEntryID();
+ else return pstr("");
+ }
+
+ void Chain::SetEntryID ( const IDCode idCode ) {
+ if (model) model->SetEntryID ( idCode );
+ }
+
+ int Chain::GetModelNum() {
+ if (model) return model->GetSerNum();
+ return 0;
+ }
+
+ cpstr Chain::GetChainID ( pstr ChID ) {
+ ChID[0] = char(0);
+ if (model)
+ sprintf ( ChID,"/%i/",model->GetSerNum() );
+ else strcpy ( ChID,"/-/" );
+ strcat ( ChID,chainID );
+ return ChID;
+ }
+
+
+ void Chain::GetAtomStatistics ( RAtomStat AS ) {
+ AS.Init();
+ CalAtomStatistics ( AS );
+ AS.Finish();
+ }
+
+ void Chain::CalAtomStatistics ( RAtomStat AS ) {
+ int i;
+ for (i=0;i<nResidues;i++)
+ if (residue[i])
+ residue[i]->CalAtomStatistics ( AS );
+ }
+
+ void Chain::ApplyTransform ( mat44 & TMatrix ) {
+ // transforms all coordinates by multiplying with matrix TMatrix
+ int i;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) residue[i]->ApplyTransform ( TMatrix );
+ }
+
+ bool Chain::isSolventChain() {
+ // returns true if chain contains only solvent molecules
+ bool B,P;
+ int i;
+ B = true;
+ P = false;
+ for (i=0;(i<nResidues) && B;i++)
+ if (residue[i]) {
+ P = true;
+ B = residue[i]->isSolvent();
+ }
+ return (B && P);
+ }
+
+ bool Chain::isInSelection ( int selHnd ) {
+ PRoot mmdbRoot = (PRoot)GetCoordHierarchy();
+ PMask mask;
+ if (mmdbRoot) {
+ mask = mmdbRoot->GetSelMask ( selHnd );
+ if (mask) return CheckMask ( mask );
+ }
+ return false;
+ }
+
+ bool Chain::isAminoacidChain() {
+ // returns true if chain contains at least one aminoacid residue
+ bool B,P;
+ int i;
+ B = false;
+ P = false;
+ for (i=0;(i<nResidues) && (!B);i++)
+ if (residue[i]) {
+ P = true;
+ B = residue[i]->isAminoacid();
+ }
+ return (B && P);
+ }
+
+ bool Chain::isNucleotideChain() {
+ // returns true if chain contains at least one nucleotide residue
+ bool B,P;
+ int i;
+ B = false;
+ P = false;
+ for (i=0;(i<nResidues) && (!B);i++)
+ if (residue[i]) {
+ P = true;
+ B = residue[i]->isNucleotide();
+ }
+ return (B && P);
+ }
+
+ int Chain::CheckID ( const ChainID chID ) {
+ if (chID) {
+ if (!strcmp(chID,chainID)) return 1;
+ }
+ return 0;
+ }
+
+ int Chain::CheckIDS ( cpstr CID ) {
+ ChainID chn;
+ InsCode inscode;
+ ResName resname;
+ AtomName atm;
+ Element elm;
+ AltLoc aloc;
+ int mdl,sn,rc;
+
+ rc = ParseAtomPath ( CID,mdl,chn,sn,inscode,resname,
+ atm,elm,aloc,NULL );
+ if (rc>=0) {
+ if (!strcmp(chn,chainID)) return 1;
+ }
+ return 0;
+
+ }
+
+ int Chain::GetNumberOfDBRefs() {
+ return DBRef.Length();
+ }
+
+ PDBReference Chain::GetDBRef ( int dbRefNo ) {
+ return (PDBReference)DBRef.GetContainerClass ( dbRefNo );
+ }
+
+
+ void Chain::MaskAtoms ( PMask mask ) {
+ int i;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) residue[i]->MaskAtoms ( mask );
+ }
+
+ void Chain::MaskResidues ( PMask mask ) {
+ int i;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) residue[i]->SetMask ( mask );
+ }
+
+ void Chain::UnmaskAtoms ( PMask mask ) {
+ int i;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) residue[i]->UnmaskAtoms ( mask );
+ }
+
+ void Chain::UnmaskResidues ( PMask mask ) {
+ int i;
+ for (i=0;i<nResidues;i++)
+ if (residue[i]) residue[i]->RemoveMask ( mask );
+ }
+
+
+
+
+ // ------- user-defined data handlers
+
+ int Chain::PutUDData ( int UDDhandle, int iudd ) {
+ if (UDDhandle & UDRF_CHAIN)
+ return UDData::putUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Chain::PutUDData ( int UDDhandle, realtype rudd ) {
+ if (UDDhandle & UDRF_CHAIN)
+ return UDData::putUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Chain::PutUDData ( int UDDhandle, cpstr sudd ) {
+ if (UDDhandle & UDRF_CHAIN)
+ return UDData::putUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Chain::GetUDData ( int UDDhandle, int & iudd ) {
+ if (UDDhandle & UDRF_CHAIN)
+ return UDData::getUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Chain::GetUDData ( int UDDhandle, realtype & rudd ) {
+ if (UDDhandle & UDRF_CHAIN)
+ return UDData::getUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Chain::GetUDData ( int UDDhandle, pstr sudd, int maxLen ) {
+ if (UDDhandle & UDRF_CHAIN)
+ return UDData::getUDData ( UDDhandle,sudd,maxLen );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Chain::GetUDData ( int UDDhandle, pstr & sudd ) {
+ if (UDDhandle & UDRF_CHAIN)
+ return UDData::getUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+
+ // -------------------------------------------------------------------
+
+ DefineClass(SortResidues)
+
+ class QSortResidues : public QuickSort {
+ public :
+ QSortResidues() : QuickSort() {}
+ int Compare ( int i, int j );
+ void Swap ( int i, int j );
+ void Sort ( PPResidue res, int nresidues );
+ };
+
+ int QSortResidues::Compare ( int i, int j ) {
+ int diff;
+ diff = ((PPResidue)data)[i]->seqNum - ((PPResidue)data)[j]->seqNum;
+ if (diff==0)
+ diff = strcmp( (PPResidue(data))[i]->insCode,
+ (PPResidue(data))[j]->insCode );
+ if (diff>0) return 1;
+ if (diff<0) return -1;
+ return 0;
+ }
+
+ void QSortResidues::Swap ( int i, int j ) {
+ PResidue res;
+ res = ((PPResidue)data)[i];
+ ((PPResidue)data)[i] = ((PPResidue)data)[j];
+ ((PPResidue)data)[j] = res;
+ }
+
+ void QSortResidues::Sort ( PPResidue res, int nresidues ) {
+ QuickSort::Sort ( &(res[0]),nresidues );
+ }
+
+ void Chain::SortResidues() {
+ QSortResidues SR;
+ TrimResidueTable();
+ SR.Sort ( residue,nResidues );
+ }
+
+ int Chain::GetNofModResidues() {
+ return modRes.Length();
+ }
+
+ PModRes Chain::GetModResidue ( int modResNo ) {
+ return PModRes(modRes.GetContainerClass(modResNo));
+ }
+
+ void Chain::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+
+ f.WriteByte ( &Version );
+
+ UDData::write ( f );
+
+ f.WriteTerLine ( chainID ,false );
+ f.WriteTerLine ( prevChainID,false );
+
+ DBRef .write ( f ); // Database reference
+ seqAdv.write ( f ); // SEQADV records
+ seqRes.write ( f ); // SEQRES data
+ modRes.write ( f ); // MODRES records
+ Het .write ( f ); // HET records
+
+ f.WriteInt ( &nResidues );
+ for (i=0;i<nResidues;i++)
+ residue[i]->write ( f );
+
+ }
+
+ void Chain::read ( io::RFile f ) {
+ // The Atom array in CmmdbRoot must be already read
+ // prior to calling this function!
+ int i;
+ byte Version;
+
+ FreeMemory();
+
+ f.ReadByte ( &Version );
+
+ UDData::read ( f );
+
+ f.ReadTerLine ( chainID ,false );
+ f.ReadTerLine ( prevChainID,false );
+
+ DBRef .read ( f ); // Database reference
+ seqAdv.read ( f ); // SEQADV records
+ seqRes.read ( f ); // SEQRES data
+ modRes.read ( f ); // MODRES records
+ Het .read ( f ); // HET records
+
+ SetChain ( chainID );
+
+ f.ReadInt ( &nResidues );
+ resLen = nResidues;
+ if (nResidues>0) {
+ residue = new PResidue[nResidues];
+ for (i=0;i<nResidues;i++) {
+ residue[i] = newResidue();
+ residue[i]->SetChain ( this );
+ residue[i]->read ( f );
+ }
+ }
+
+ }
+
+
+ MakeFactoryFunctions(Chain)
+
+} // namespace mmdb
+
+
+// ===================================================================
+
+ /*
+void TestChain() {
+// reads from 'in.chain', writes into
+// 'out.chain' and 'abin.chain'
+CFile f;
+char S[81];
+PChain Chain;
+
+ Chain = newChain();
+
+ f.assign ( "in.chain",true );
+ if (f.reset()) {
+ while (!f.FileEnd()) {
+ f.ReadLine ( S,sizeof(S) );
+ chain->ConvertPDBString ( S );
+ }
+ f.shut();
+ } else {
+ printf ( " Can't open input file 'in.chain' \n" );
+ delete Chain;
+ return;
+ }
+
+ f.assign ( "out.chain",true );
+ if (f.rewrite()) {
+ chain->PDBASCIIDump ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open output file 'out.chain' \n" );
+ delete Chain;
+ return;
+ }
+
+
+ f.assign ( "mmdb.chain.bin",false );
+ if (f.rewrite()) {
+ chain->write ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open binary chain file for writing.\n" );
+ delete Chain;
+ return;
+ }
+
+ delete Chain;
+ printf ( " Chain deleted.\n" );
+
+ Chain = newChain();
+ if (f.reset()) {
+ chain->read ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open binary chain file for reading.\n" );
+ delete Chain;
+ return;
+ }
+
+ f.assign ( "abin.chain",true );
+ if (f.rewrite()) {
+ chain->PDBASCIIDump ( f );
+ f.shut();
+ } else
+ printf ( " Can't open output file 'abin.chain' \n" );
+
+ delete Chain;
+
+}
+ */
diff --git a/mmdb2/mmdb_chain.h b/mmdb2/mmdb_chain.h
new file mode 100644
index 0000000..db46f0e
--- /dev/null
+++ b/mmdb2/mmdb_chain.h
@@ -0,0 +1,662 @@
+// $Id: mmdb_chain.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Chain <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::ProModel ( a virtue of Model )
+// ~~~~~~~~~ mmdb::DBReference ( DBREF records )
+// mmdb::ChainContainer ( container of in-chain classes )
+// mmdb::ContainerChain ( chain containered class template)
+// mmdb::SeqAdv ( SEQADV records )
+// mmdb::SeqRes ( SEQRES records )
+// mmdb::ModRes ( MODRES records )
+// mmdb::HetRec ( HET records )
+// mmdb::Chain ( chain class )
+//
+// Copyright (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Chain__
+#define __MMDB_Chain__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_utils.h"
+#include "mmdb_atom.h"
+#include "mmdb_defs.h"
+
+namespace mmdb {
+
+ // ==================== ProModel ======================
+
+ // This class is a virtue needed only for defining certain
+ // functions of Model, which are used by Chain and
+ // Residue
+
+ DefineClass(ProModel);
+ DefineStreamFunctions(ProModel);
+
+ DefineClass(Manager);
+
+ class ProModel : public UDData {
+
+ friend class Chain;
+
+ public :
+
+ ProModel () : UDData () {}
+ ProModel ( io::RPStream Object ) : UDData ( Object ) {}
+ ~ProModel () {}
+
+ virtual cpstr GetEntryID () { return ""; }
+ virtual void SetEntryID ( const IDCode ) {}
+
+ virtual int AddChain ( PChain ) { return 0; }
+
+ // returns pointer to Root
+ virtual PManager GetCoordHierarchy() { return NULL; }
+
+ // GetNumberOfModels() returns TOTAL number of models
+ virtual int GetNumberOfModels() { return 0; }
+
+ // GetNumberOfAllAtoms() returns TOTAL number of atoms in
+ // all models
+ virtual int GetNumberOfAllAtoms() { return 0; }
+
+ // returns pointer to the general Atom array
+ virtual PPAtom GetAllAtoms() { return NULL; }
+
+ virtual int GetSerNum () { return 0; }
+
+ virtual void ExpandAtomArray ( int ) {}
+ virtual void AddAtomArray ( int ) {}
+
+ protected :
+
+ virtual int _ExcludeChain ( const ChainID ) { return 0; }
+
+ };
+
+
+
+ // ==================== ChainContainer ======================
+
+ DefineClass(ChainContainer);
+ DefineStreamFunctions(ChainContainer);
+
+ class ChainContainer : public ClassContainer {
+
+ public :
+
+ ChainContainer () : ClassContainer () {}
+ ChainContainer ( io::RPStream Object )
+ : ClassContainer ( Object ) {}
+ ~ChainContainer () {}
+
+ PContainerClass MakeContainerClass ( int ClassID );
+
+ void SetChain ( PChain Chain_Owner ); // must be set before using
+ // the Container
+
+ // special functions used in Model::GetCIF(..)
+ cpstr Get1stChainID ();
+ void MoveByChainID ( const ChainID chainID,
+ PChainContainer chainContainer );
+
+ protected :
+ PChain chain;
+
+ };
+
+
+ // ================== ContainerChain =====================
+
+ DefineClass(ContainerChain);
+ DefineStreamFunctions(ContainerChain);
+
+ class ContainerChain : public ContainerClass {
+
+ friend class ChainContainer;
+
+ public :
+
+ ContainerChain ();
+ ContainerChain ( PChain Chain_Owner );
+ ContainerChain ( io::RPStream Object ) : ContainerClass(Object) {}
+
+ void SetChain ( PChain Chain_Owner );
+
+ protected :
+ PChain chain;
+ ChainID chainID; // just a copy of Chain->chainID
+
+ };
+
+
+ // ================== DBReference ========================
+
+ DefineClass(DBReference);
+ DefineStreamFunctions(DBReference);
+
+ class DBReference : public ContainerChain {
+
+ public :
+
+ int seqBeg; // initial seq num of the PDB seq-ce segment
+ InsCode insBeg; // initial ins code of the PDB seq-ce segm-t
+ int seqEnd; // ending seq number of the PDB seq-ce segm-t
+ InsCode insEnd; // ending ins code of the PDB seq-ce segment
+ DBName database; // sequence database name
+ DBAcCode dbAccession; // sequence database accession code
+ DBIdCode dbIdCode; // sequence database identification code
+ int dbseqBeg; // initial seq number of the database segment
+ InsCode dbinsBeg; // ins code of initial residue of the segment
+ int dbseqEnd; // ending seq number of the database segment
+ InsCode dbinsEnd; // ins code of the ending residue of the seg-t
+
+ DBReference ();
+ DBReference ( PChain Chain_Owner );
+ DBReference ( PChain Chain_Owner, cpstr S );
+ DBReference ( io::RPStream Object );
+ ~DBReference();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_DBReference; }
+
+ void Copy ( PContainerClass DBRef );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitDBReference();
+
+ };
+
+
+ // ==================== SeqAdv ===========================
+
+ DefineClass(SeqAdv);
+ DefineStreamFunctions(SeqAdv);
+
+ class SeqAdv : public ContainerChain {
+
+ public :
+
+ ResName resName; // residue name in conflict
+ int seqNum; // residue sequence number
+ InsCode insCode; // residue insertion code
+ DBName database; // sequence database name
+ DBAcCode dbAccession; // sequence database accession code
+ ResName dbRes; // sequence database residue name
+ int dbSeq; // sequence database sequence number
+ pstr conflict; // conflict comment
+
+ SeqAdv ();
+ SeqAdv ( PChain Chain_Owner );
+ SeqAdv ( PChain Chain_Owner, cpstr S );
+ SeqAdv ( io::RPStream Object );
+ ~SeqAdv();
+
+ void PDBASCIIDump ( pstr S, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_SeqAdv; }
+
+ void Copy ( PContainerClass seqAdv );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitSeqAdv();
+
+ };
+
+
+ // ================== SeqRes ========================
+
+ DefineClass(SeqRes);
+ DefineStreamFunctions(SeqRes);
+
+ class SeqRes : public io::Stream {
+
+ friend class Model;
+ friend class Chain;
+
+ public :
+
+ int numRes; // number of residues in the chain
+ PResName resName; // residue names
+
+ SeqRes ();
+ SeqRes ( io::RPStream Object );
+ ~SeqRes();
+
+ void SetChain ( PChain Chain_Owner );
+ void PDBASCIIDump ( io::RFile f );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+
+ void MakeCIF ( mmcif::PData CIF );
+ ERROR_CODE GetCIF ( mmcif::PData CIF );
+
+ void Copy ( PSeqRes seqRes );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ PChain chain;
+ ChainID chainID;
+ int serNum;
+
+ void InitSeqRes();
+ void FreeMemory();
+
+ };
+
+
+ // ================== ModRes ========================
+
+ DefineClass(ModRes);
+ DefineStreamFunctions(ModRes);
+
+ class ModRes : public ContainerChain {
+
+ public :
+
+ ResName resName; // residue name used
+ int seqNum; // residue sequence number
+ InsCode insCode; // residue insertion code
+ ResName stdRes; // standard residue name
+ pstr comment; // description of the residue modification
+
+ ModRes ();
+ ModRes ( PChain Chain_Owner );
+ ModRes ( PChain Chain_Owner, cpstr S );
+ ModRes ( io::RPStream Object );
+ ~ModRes();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_ModRes; }
+
+ void Copy ( PContainerClass modRes );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitModRes();
+
+ };
+
+
+ // ================== HetRec ===========================
+
+ DefineClass(HetRec);
+ DefineStreamFunctions(HetRec);
+
+ class HetRec : public ContainerChain {
+
+ public :
+
+ ResName hetID; // Het identifier (right-justified)
+ int seqNum; // sequence number
+ InsCode insCode; // insertion code
+ int numHetAtoms; // number of HETATM records for the
+ // group present in the entry
+ pstr comment; // text describing Het group
+
+ HetRec ();
+ HetRec ( PChain Chain_Owner );
+ HetRec ( PChain Chain_Owner, cpstr S );
+ HetRec ( io::RPStream Object );
+ ~HetRec();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_Het; }
+
+ void Copy ( PContainerClass Het );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitHetRec();
+
+ };
+
+
+ // ================= Chain =======================
+
+ DefineFactoryFunctions(Chain);
+
+ class Chain : public UDData {
+
+ friend class DBReference;
+ friend class SeqAdv;
+ friend class SeqRes;
+ friend class ModRes;
+ friend class HetRec;
+ friend class Residue;
+ friend class Atom;
+ friend class Model;
+ friend class Root;
+ friend class SelManager;
+ friend class BondManager;
+ friend class CoorManager;
+ friend class Manager;
+
+ public :
+
+ ChainContainer DBRef; // database reference
+ ChainContainer seqAdv; // SEQADV records
+ SeqRes seqRes; // Sequence residues, SEQRES records
+ ChainContainer modRes; // modification descriptions
+ ChainContainer Het; // non-standard residues descriptions
+
+ Chain (); // SetModel() MUST be used after this constructor!
+ Chain ( PProModel model, const ChainID chID );
+ Chain ( io::RPStream Object );
+ ~Chain();
+
+ void FreeAnnotations();
+
+ void SetModel ( PProModel model );
+ void SetChain ( const ChainID chID );
+
+ PManager GetCoordHierarchy(); // PRoot
+
+ // ConvertXXXXX(..) functions do not check for record name
+ // and assume that PDBString is at least 81 symbols long
+ // (including the terminating null).
+ ERROR_CODE ConvertDBREF ( cpstr PDBString );
+ ERROR_CODE ConvertSEQADV ( cpstr PDBString );
+ ERROR_CODE ConvertSEQRES ( cpstr PDBString );
+ ERROR_CODE ConvertMODRES ( cpstr PDBString );
+ ERROR_CODE ConvertHET ( cpstr PDBString );
+
+ // This function should be used for testing purposes only.
+ // A full PDB ASCII dump for all models and chains involved
+ // is done by Root class.
+ void PDBASCIIDump ( io::RFile f );
+
+ void PDBASCIIAtomDump ( io::RFile f );
+ void MakeAtomCIF ( mmcif::PData CIF );
+
+
+ // ----------------- Extracting residues -------------------------
+
+ int GetNumberOfResidues(); // returns number of res-s in the chain
+ PResidue GetResidue ( int resNo ); // returns resNo-th residue
+ // in the chain;
+ // 0<=resNo<nResidues
+
+ // GetResidue(..) returns pointer on residue, whose sequence
+ // number and insert code are given in seqNum and insCode,
+ // respectively. If such a residue is absent in the chain,
+ // returns NULL.
+ PResidue GetResidue ( int seqNum, const InsCode insCode );
+
+ // GetResidueNo(..) returns the residue number in the chain's
+ // residues table. Residues are numbered as 0..nres-1 as they
+ // appear in the coordinate file.
+ // If residue is not found, the function returns -1.
+ int GetResidueNo ( int seqNum, const InsCode insCode );
+
+ void GetResidueTable ( PPResidue & resTable,
+ int & NumberOfResidues );
+
+ // GetResidueCreate(..) returns pointer on residue, whose name,
+ // sequence number and insertion code are given by resName, seqNum
+ // and insCode, respectively. If such a residue is absent in the
+ // chain, one is created at the end of chain.
+ // If a residue with given sequence number and insertion code
+ // is present in the chain but has a different name, the function
+ // returns NULL unless Enforce is set True. In the latter case,
+ // a new residue is still created at the end of chain, but there
+ // is no guarantee that any function operating on the sequence
+ // number and insertion code will work properly.
+ PResidue GetResidueCreate ( const ResName resName, int seqNum,
+ const InsCode insCode, bool Enforce );
+
+
+ // ------------------ Deleting residues ----------------------
+
+ int DeleteResidue ( int resNo ); // returns num of deleted res-s
+ int DeleteResidue ( int seqNum, const InsCode insCode );
+ int DeleteAllResidues();
+ int DeleteSolvent ();
+ void TrimResidueTable (); // do not forget to call after all dels
+
+ // ------------------- Adding residues -----------------------
+
+ // AddResidue(..) adds residue to the chain, InsResidue inserts
+ // the residue on the specified position of the chain (other
+ // residues are shifted up to the end of chain). Position in the
+ // chain may be specified by a serial number (that is position in
+ // the residue table) or by seqNum and insCode of one of the
+ // chain's residues (the new residue is then inserted before that
+ // one). If the chain is associated with a coordinate hierarchy,
+ // and residue 'res' is not, the latter is checked in
+ // automatically. If residue 'res' belongs to any coordinate
+ // hierarchy (even though that of the residue), it is *copied*
+ // rather than simply taken over, and is checked in.
+ // If the chain is not associated with a coordinate hierarchy,
+ // all added residues will be checked in automatically once the
+ // chain is checked in.
+ int AddResidue ( PResidue res );
+ int InsResidue ( PResidue res, int pos );
+ int InsResidue ( PResidue res, int seqNum, const InsCode insCode );
+
+ // -------------------- Extracting atoms ---------------------
+
+ int GetNumberOfAtoms ( bool countTers );
+ int GetNumberOfAtoms ( int seqNo, const InsCode insCode );
+ int GetNumberOfAtoms ( int resNo );
+
+ PAtom GetAtom ( int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ PAtom GetAtom ( int seqNo, const InsCode insCode, int atomNo );
+ PAtom GetAtom ( int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ PAtom GetAtom ( int resNo, int atomNo );
+
+ void GetAtomTable ( int seqNo, const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable ( int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+
+ // GetAtomTable1(..) returns atom table without TER atoms and
+ // without NULL atom pointers. NumberOfAtoms returns the actual
+ // number of atom pointers in atomTable.
+ // atomTable is allocated withing the function. If it was
+ // not set to NULL before calling the function, the latter will
+ // attempt to deallocate it first.
+ // The application is responsible for deleting atomTable,
+ // however it must not touch atom pointers, i.e. use simply
+ // "delete[] atomTable;". Never pass atomTable from
+ // GetAtomTable(..) into this function, unless you set it to NULL
+ // before doing that.
+ void GetAtomTable1 ( int seqNo, const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable1 ( int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+
+ // --------------------- Deleting atoms ----------------------
+
+ int DeleteAtom ( int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( int seqNo,
+ const InsCode insCode,
+ int atomNo );
+ int DeleteAtom ( int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( int resNo, int atomNo );
+
+ int DeleteAllAtoms ( int seqNo, const InsCode insCode );
+ int DeleteAllAtoms ( int resNo );
+ int DeleteAllAtoms ();
+
+ // DeleteAltLocs() leaves only alternative location with maximal
+ // occupancy, if those are equal or unspecified, the one with
+ // "least" alternative location indicator.
+ // The function returns the number of deleted. All tables remain
+ // untrimmed, so that explicit trimming or calling
+ // FinishStructEdit() is required.
+ int DeleteAltLocs();
+
+ // ---------------------- Adding atoms -----------------------
+
+ int AddAtom ( int seqNo, const InsCode insCode, PAtom atom );
+ int AddAtom ( int resNo, PAtom atom );
+
+ // -------------------------------------------------------------
+
+ void ApplyTransform ( mat44 & TMatrix ); // transforms all
+ // coordinates by multiplying
+ // with matrix TMatrix
+
+ int GetModelNum();
+ PModel GetModel () { return (PModel)model; }
+ cpstr GetChainID () { return chainID; }
+ void SetChainID ( const ChainID chID );
+ cpstr GetChainID ( pstr ChID ); // returns /m/c
+
+ void GetAtomStatistics ( RAtomStat AS );
+ void CalAtomStatistics ( RAtomStat AS );
+
+ int CheckID ( const ChainID chID );
+ int CheckIDS ( cpstr CID );
+
+ cpstr GetEntryID ();
+ void SetEntryID ( const IDCode idCode );
+
+ int GetNumberOfDBRefs ();
+ PDBReference GetDBRef ( int dbRefNo ); // 0..nDBRefs-1
+
+ void MaskAtoms ( PMask Mask );
+ void MaskResidues ( PMask Mask );
+ void UnmaskAtoms ( PMask Mask );
+ void UnmaskResidues ( PMask Mask );
+
+ void SortResidues ();
+
+ int GetNofModResidues();
+ PModRes GetModResidue ( int modResNo ); // 0.. on
+
+ bool isSolventChain ();
+ bool isInSelection ( int selHnd );
+ bool isAminoacidChain ();
+ bool isNucleotideChain();
+
+
+ // ------- user-defined data handlers
+ int PutUDData ( int UDDhandle, int iudd );
+ int PutUDData ( int UDDhandle, realtype rudd );
+ int PutUDData ( int UDDhandle, cpstr sudd );
+
+ int GetUDData ( int UDDhandle, int & iudd );
+ int GetUDData ( int UDDhandle, realtype & rudd );
+ int GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+ int GetUDData ( int UDDhandle, pstr & sudd );
+
+ void Copy ( PChain chain );
+ void CopyAnnotations ( PChain chain );
+
+ void write ( io::RFile f ); // writes header to PDB binary file
+ void read ( io::RFile f ); // reads header from PDB binary file
+
+ protected :
+
+ ChainID chainID; // chain ID
+ ChainID prevChainID; // if chain is renamed, its original
+ // name may be saved here.
+ PProModel model; // pointer to model class
+
+ int nWeights; // used externally for sorting
+ realtype Weight; // chains
+
+ int nResidues; // number of residues
+ PPResidue residue; // array of residues
+
+ bool Exclude; // used internally
+
+ void InitChain ();
+ void FreeMemory();
+
+ void ExpandResidueArray ( int inc );
+ // _ExcludeResidue(..) excludes (but does not dispose!) a residue
+ // from the chain. Returns 1 if the chain gets empty and 0
+ // otherwise.
+ int _ExcludeResidue ( const ResName resName, int seqNum,
+ const InsCode insCode );
+ void _copy ( PChain chain );
+ void _copy ( PChain chain, PPAtom atom, int & atom_index );
+ void CheckInAtoms();
+
+ private :
+ int resLen; // length of Residue array
+
+ };
+
+
+ extern void TestChain(); // reads from 'in.chain', writes into
+ // 'out.chain' and 'abin.chain'
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_cifdefs.cpp b/mmdb2/mmdb_cifdefs.cpp
new file mode 100644
index 0000000..270a0ad
--- /dev/null
+++ b/mmdb2/mmdb_cifdefs.cpp
@@ -0,0 +1,369 @@
+// $Id: mmdb_cifdefs.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 21.11.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDBF_Defs <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Namespace: mmdb::
+//
+// CIF Definitions
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include "mmdb_cifdefs.h"
+
+namespace mmdb {
+
+ // ------------------------------------------------------------------
+
+ cpstr CIFName ( int NameID, CIF_MODE Mode ) {
+ // Gives CIF name according to CIF Mode.
+
+ switch (Mode) {
+
+ case CIF_NDB :
+
+ switch (NameID) {
+ case CAT_POLY_SEQ_SCHEME :
+ return CIFCAT_NDB_POLY_SEQ_SCHEME;
+ case TAG_ID_CODE :
+ return CIFTAG_NDB_PDB_ID_CODE;
+ case TAG_CHAIN_ID :
+ return CIFTAG_NDB_CHAIN_ID;
+ case TAG_SEQ_ALIGN_BEG :
+ return CIFTAG_SEQ_ALIGN_BEG;
+ case TAG_SEQ_ALIGN_BEG_INS_CODE :
+ return CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE;
+ case TAG_SEQ_ALIGN_END :
+ return CIFTAG_SEQ_ALIGN_END;
+ case TAG_SEQ_ALIGN_END_INS_CODE :
+ return CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE;
+ case TAG_DB_ACCESSION :
+ return CIFTAG_NDB_DB_ACCESSION;
+ case TAG_DB_ALIGN_BEG :
+ return CIFTAG_DB_ALIGN_BEG;
+ case TAG_DB_ALIGN_BEG_INS_CODE :
+ return CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE;
+ case TAG_DB_ALIGN_END :
+ return CIFTAG_DB_ALIGN_END;
+ case TAG_DB_ALIGN_END_INS_CODE :
+ return CIFTAG_NDB_DB_ALIGN_END_INS_CODE;
+ case TAG_SEQ_CHAIN_ID :
+ return CIFTAG_ID;
+ default : return pstr("ERROR_IN_CIF_NAME_1");
+ }
+
+ case CIF_PDBX :
+
+ switch (NameID) {
+ case CAT_POLY_SEQ_SCHEME :
+ return CIFCAT_PDBX_POLY_SEQ_SCHEME;
+ case TAG_ID_CODE :
+ return CIFTAG_PDBX_PDB_ID_CODE;
+ case TAG_CHAIN_ID :
+ return CIFTAG_PDBX_STRAND_ID;
+ case TAG_SEQ_ALIGN_BEG :
+ return CIFTAG_SEQ_ALIGN_BEG;
+ case TAG_SEQ_ALIGN_BEG_INS_CODE :
+ return CIFTAG_PDBX_SEQ_ALIGN_BEG_INS_CODE;
+ case TAG_SEQ_ALIGN_END :
+ return CIFTAG_SEQ_ALIGN_END;
+ case TAG_SEQ_ALIGN_END_INS_CODE :
+ return CIFTAG_PDBX_SEQ_ALIGN_END_INS_CODE;
+ case TAG_DB_ACCESSION :
+ return CIFTAG_PDBX_DB_ACCESSION;
+ case TAG_DB_ALIGN_BEG :
+ return CIFTAG_DB_ALIGN_BEG;
+ case TAG_DB_ALIGN_BEG_INS_CODE :
+ return CIFTAG_PDBX_DB_ALIGN_BEG_INS_CODE;
+ case TAG_DB_ALIGN_END :
+ return CIFTAG_DB_ALIGN_END;
+ case TAG_DB_ALIGN_END_INS_CODE :
+ return CIFTAG_PDBX_DB_ALIGN_END_INS_CODE;
+ case TAG_SEQ_CHAIN_ID :
+ return CIFTAG_ASYM_ID;
+ default : return pstr("ERROR_IN_CIF_NAME_2");
+ }
+
+ default : return pstr("ERROR_IN_CIF_NAME_3");
+
+ }
+
+ }
+
+ cpstr CIFCAT_ATOM_SITE = cpstr("_atom_site");
+ cpstr CIFCAT_ATOM_SITE_ANISOTROP = cpstr("_atom_site_anisotrop");
+ cpstr CIFCAT_ATOM_SITES = cpstr("_atom_sites");
+ cpstr CIFCAT_AUDIT_AUTHOR = cpstr("_audit_author");
+ cpstr CIFCAT_CELL = cpstr("_cell");
+ cpstr CIFCAT_CHEM_COMP = cpstr("_chem_comp");
+ cpstr CIFCAT_CITATION = cpstr("_citation");
+ cpstr CIFCAT_DATABASE = cpstr("_database");
+ cpstr CIFCAT_DATABASE_PDB_CAVEAT = cpstr("_database_pdb_caveat");
+ cpstr CIFCAT_DATABASE_PDB_MATRIX = cpstr("_database_pdb_matrix");
+ cpstr CIFCAT_DATABASE_PDB_REV = cpstr("_database_pdb_rev");
+ cpstr CIFCAT_DATABASE_PDB_TVECT = cpstr("_database_pdb_tvect");
+ cpstr CIFCAT_ENTITY = cpstr("_entity");
+ cpstr CIFCAT_EXPTL = cpstr("_exptl");
+ cpstr CIFCAT_NDB_DATABASE_REMARK = cpstr("_ndb_database_remark");
+ cpstr CIFCAT_NDB_NONSTANDARD_LIST = cpstr("_ndb_nonstandard_list");
+ cpstr CIFCAT_NDB_POLY_SEQ_SCHEME = cpstr("_ndb_poly_seq_scheme");
+ cpstr CIFCAT_PDBX_POLY_SEQ_SCHEME = cpstr("_pdbx_poly_seq_scheme");
+ cpstr CIFCAT_REFINE = cpstr("_refine");
+ cpstr CIFCAT_SPRSDE = cpstr("_ndb_database_pdb_obs_spr");
+ cpstr CIFCAT_STRUCT = cpstr("_struct");
+ cpstr CIFCAT_STRUCT_ASYM = cpstr("_struct_asym");
+ cpstr CIFCAT_STRUCT_CONF = cpstr("_struct_conf");
+ cpstr CIFCAT_STRUCT_CONN = cpstr("_struct_conn");
+ cpstr CIFCAT_STRUCT_LINKR = cpstr("_struct_linkr");
+ cpstr CIFCAT_STRUCT_KEYWORDS = cpstr("_struct_keywords");
+ cpstr CIFCAT_STRUCT_NCS_OPER = cpstr("_struct_ncs_oper");
+ cpstr CIFCAT_STRUCT_REF = cpstr("_struct_ref");
+ cpstr CIFCAT_STRUCT_REF_SEQ = cpstr("_struct_ref_seq");
+ cpstr CIFCAT_STRUCT_REF_SEQ_DIF = cpstr("_struct_ref_seq_dif");
+ cpstr CIFCAT_STRUCT_SHEET = cpstr("_struct_sheet");
+ cpstr CIFCAT_STRUCT_SHEET_RANGE = cpstr("_struct_sheet_range");
+ cpstr CIFCAT_STRUCT_SHEET_ORDER = cpstr("_struct_sheet_order");
+ cpstr CIFCAT_STRUCT_SHEET_HBOND = cpstr("_struct_sheet_hbond");
+ cpstr CIFCAT_SYMMETRY = cpstr("_symmetry");
+ cpstr CIFCAT_OBSLTE = cpstr("_ndb_database_pdb_obs_spr");
+
+
+ cpstr CIFTAG_ANGLE_ALPHA = cpstr("angle_alpha");
+ cpstr CIFTAG_ANGLE_BETA = cpstr("angle_beta");
+ cpstr CIFTAG_ANGLE_GAMMA = cpstr("angle_gamma");
+ cpstr CIFTAG_ASYM_ID = cpstr("asym_id");
+ cpstr CIFTAG_ATOM_TYPE_SYMBOL = cpstr("atom_type_symbol");
+ cpstr CIFTAG_AUTH_ASYM_ID = cpstr("auth_asym_id");
+ cpstr CIFTAG_AUTH_ATOM_ID = cpstr("auth_atom_id");
+ cpstr CIFTAG_AUTH_COMP_ID = cpstr("auth_comp_id");
+ cpstr CIFTAG_AUTH_SEQ_ID = cpstr("auth_seq_id");
+ cpstr CIFTAG_B_ISO_OR_EQUIV = cpstr("B_iso_or_equiv");
+ cpstr CIFTAG_B_ISO_OR_EQUIV_ESD = cpstr("B_iso_or_equiv_esd");
+ cpstr CIFTAG_BEG_LABEL_ASYM_ID = cpstr("beg_label_asym_id");
+ cpstr CIFTAG_BEG_LABEL_COMP_ID = cpstr("beg_label_comp_id");
+ cpstr CIFTAG_BEG_LABEL_SEQ_ID = cpstr("beg_label_seq_id");
+ cpstr CIFTAG_CARTN_X = cpstr("cartn_x");
+ cpstr CIFTAG_CARTN_X_ESD = cpstr("cartn_x_esd");
+ cpstr CIFTAG_CARTN_Y = cpstr("cartn_y");
+ cpstr CIFTAG_CARTN_Y_ESD = cpstr("cartn_y_esd");
+ cpstr CIFTAG_CARTN_Z = cpstr("cartn_z");
+ cpstr CIFTAG_CARTN_Z_ESD = cpstr("cartn_z_esd");
+ cpstr CIFTAG_PDBX_FORMAL_CHARGE = cpstr("pdbx_formal_charge");
+ cpstr CIFTAG_CODE = cpstr("code");
+ cpstr CIFTAG_CODE_NDB = cpstr("code_NDB");
+ cpstr CIFTAG_CODE_PDB = cpstr("code_PDB");
+ cpstr CIFTAG_CONF_TYPE_ID = cpstr("conf_type_id");
+ cpstr CIFTAG_CONN_TYPE_ID = cpstr("conn_type_id");
+ cpstr CIFTAG_DATE = cpstr("date");
+ cpstr CIFTAG_DATE_ORIGINAL = cpstr("date_original");
+ cpstr CIFTAG_DB_ALIGN_BEG = cpstr("db_align_beg");
+ cpstr CIFTAG_DB_ALIGN_END = cpstr("db_align_end");
+ cpstr CIFTAG_DB_CODE = cpstr("db_code");
+ cpstr CIFTAG_DB_MON_ID = cpstr("db_mon_id");
+ cpstr CIFTAG_DB_NAME = cpstr("db_name");
+ cpstr CIFTAG_DETAILS = cpstr("details");
+ cpstr CIFTAG_END_LABEL_ASYM_ID = cpstr("end_label_asym_id");
+ cpstr CIFTAG_END_LABEL_COMP_ID = cpstr("end_label_comp_id");
+ cpstr CIFTAG_END_LABEL_SEQ_ID = cpstr("end_label_seq_id");
+ cpstr CIFTAG_ENTITY_ID = cpstr("entity_id");
+ cpstr CIFTAG_ENTRY_ID = cpstr("entry_id");
+ cpstr CIFTAG_FORMULA = cpstr("formula");
+ cpstr CIFTAG_FRACT_TRANSF_MATRIX11 = cpstr("fract_transf_matrix[1][1]");
+ cpstr CIFTAG_FRACT_TRANSF_MATRIX12 = cpstr("fract_transf_matrix[1][2]");
+ cpstr CIFTAG_FRACT_TRANSF_MATRIX13 = cpstr("fract_transf_matrix[1][3]");
+ cpstr CIFTAG_FRACT_TRANSF_MATRIX21 = cpstr("fract_transf_matrix[2][1]");
+ cpstr CIFTAG_FRACT_TRANSF_MATRIX22 = cpstr("fract_transf_matrix[2][2]");
+ cpstr CIFTAG_FRACT_TRANSF_MATRIX23 = cpstr("fract_transf_matrix[2][3]");
+ cpstr CIFTAG_FRACT_TRANSF_MATRIX31 = cpstr("fract_transf_matrix[3][1]");
+ cpstr CIFTAG_FRACT_TRANSF_MATRIX32 = cpstr("fract_transf_matrix[3][2]");
+ cpstr CIFTAG_FRACT_TRANSF_MATRIX33 = cpstr("fract_transf_matrix[3][3]");
+ cpstr CIFTAG_FRACT_TRANSF_VECTOR1 = cpstr("fract_transf_vector[1]");
+ cpstr CIFTAG_FRACT_TRANSF_VECTOR2 = cpstr("fract_transf_vector[2]");
+ cpstr CIFTAG_FRACT_TRANSF_VECTOR3 = cpstr("fract_transf_vector[3]");
+ cpstr CIFTAG_GROUP_PDB = cpstr("group_PDB" );
+ cpstr CIFTAG_ID = cpstr("id");
+ cpstr CIFTAG_INS_CODE = cpstr("ins_code");
+ cpstr CIFTAG_LABEL_ALT_ID = cpstr("label_alt_id");
+ cpstr CIFTAG_LABEL_ATOM_ID = cpstr("label_atom_id");
+ cpstr CIFTAG_LABEL_ASYM_ID = cpstr("label_asym_id");
+ cpstr CIFTAG_LABEL_COMP_ID = cpstr("label_comp_id");
+ cpstr CIFTAG_LABEL_ENTITY_ID = cpstr("label_entity_id");
+ cpstr CIFTAG_LABEL_SEQ_ID = cpstr("label_seq_id");
+ cpstr CIFTAG_LENGTH_A = cpstr("length_a");
+ cpstr CIFTAG_LENGTH_B = cpstr("length_b");
+ cpstr CIFTAG_LENGTH_C = cpstr("length_c");
+ cpstr CIFTAG_LS_D_RES_HIGH = cpstr("ls_d_res_high");
+ cpstr CIFTAG_MATRIX11 = cpstr("matrix[1][1]");
+ cpstr CIFTAG_MATRIX12 = cpstr("matrix[1][2]");
+ cpstr CIFTAG_MATRIX13 = cpstr("matrix[1][3]");
+ cpstr CIFTAG_MATRIX21 = cpstr("matrix[2][1]");
+ cpstr CIFTAG_MATRIX22 = cpstr("matrix[2][2]");
+ cpstr CIFTAG_MATRIX23 = cpstr("matrix[2][3]");
+ cpstr CIFTAG_MATRIX31 = cpstr("matrix[3][1]");
+ cpstr CIFTAG_MATRIX32 = cpstr("matrix[3][2]");
+ cpstr CIFTAG_MATRIX33 = cpstr("matrix[3][3]");
+ cpstr CIFTAG_METHOD = cpstr("method");
+ cpstr CIFTAG_MOD_TYPE = cpstr("mod_type");
+ cpstr CIFTAG_MON_ID = cpstr("mon_id");
+ cpstr CIFTAG_NAME = cpstr("name");
+ cpstr CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB = cpstr("ndb_beg_label_ins_code_pdb");
+ cpstr CIFTAG_NDB_CHAIN_ID = cpstr("ndb_chain_id");
+ cpstr CIFTAG_NDB_COMPONENT_NO = cpstr("ndb_component_no");
+ cpstr CIFTAG_NDB_DESCRIPTOR = cpstr("ndb_descriptor");
+ cpstr CIFTAG_NDB_DB_ACCESSION = cpstr("ndb_db_accession");
+ cpstr CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE = cpstr("ndb_db_align_beg_ins_code");
+ cpstr CIFTAG_NDB_DB_ALIGN_END_INS_CODE = cpstr("ndb_db_align_end_ins_code");
+ cpstr CIFTAG_NDB_END_LABEL_INS_CODE_PDB = cpstr("ndb_end_label_ins_code_pdb");
+ //cpstr CIFTAG_NDB_INS_CODE = cpstr("ndb_ins_code");
+ cpstr CIFTAG_PDBX_PDB_INS_CODE = cpstr("pdbx_PDB_ins_code");
+ cpstr CIFTAG_NDB_HELIX_CLASS_PDB = cpstr("ndb_helix_class_pdb");
+ cpstr CIFTAG_NDB_KEYWORDS = cpstr("ndb_keywords");
+ cpstr CIFTAG_NDB_LABEL_ALT_ID = cpstr("ndb_label_alt_id");
+ cpstr CIFTAG_NDB_LABEL_ATOM_ID = cpstr("ndb_label_atom_id");
+ cpstr CIFTAG_NDB_LABEL_ASYM_ID = cpstr("ndb_label_asym_id");
+ cpstr CIFTAG_NDB_LABEL_COMP_ID = cpstr("ndb_label_comp_id");
+ cpstr CIFTAG_NDB_LABEL_INS_CODE = cpstr("ndb_label_ins_code");
+ cpstr CIFTAG_NDB_LABEL_SEQ_NUM = cpstr("ndb_label_seq_num");
+ cpstr CIFTAG_NDB_LENGTH = cpstr("ndb_length");
+ cpstr CIFTAG_NDB_MODEL = cpstr("ndb_model");
+ cpstr CIFTAG_NDB_PDB_CHAIN_ID = cpstr("ndb_pdb_chain_id");
+ cpstr CIFTAG_NDB_PDB_ID = cpstr("ndb_pdb_id");
+ cpstr CIFTAG_NDB_PDB_ID_CODE = cpstr("ndb_pdb_id_code");
+ cpstr CIFTAG_NDB_PDB_INS_CODE = cpstr("ndb_pdb_ins_code");
+ cpstr CIFTAG_NDB_PTNR1_LABEL_INS_CODE = cpstr("ndb_ptnr1_label_ins_code");
+ cpstr CIFTAG_NDB_PTNR1_STANDARD_COMP_ID = cpstr("ndb_ptnr1_standard_comp_id");
+ cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID = cpstr("ndb_range_1_beg_label_comp_id");
+ cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID = cpstr("ndb_range_1_beg_label_asym_id");
+ cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE= cpstr("ndb_range_1_beg_label_ins_code");
+ cpstr CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID = cpstr("ndb_range_1_end_label_comp_id");
+ cpstr CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID = cpstr("ndb_range_1_end_label_asym_id");
+ cpstr CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE= cpstr("ndb_range_1_end_label_ins_code");
+ cpstr CIFTAG_NDB_SEQ_ALIGN_BEG = cpstr("ndb_seq_align_beg");
+ cpstr CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE = cpstr("ndb_seq_align_beg_ins_code");
+ cpstr CIFTAG_NDB_SEQ_ALIGN_END = cpstr("ndb_seq_align_end");
+ cpstr CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE = cpstr("ndb_seq_align_end_ins_code");
+ cpstr CIFTAG_NDB_SEQ_DB_NAME = cpstr("ndb_seq_db_name");
+ cpstr CIFTAG_NDB_SEQ_DB_ACCESSION_CODE = cpstr("ndb_seq_db_accession_code");
+ cpstr CIFTAG_NDB_SEQ_DB_SEQ_NUM = cpstr("ndb_seq_db_seq_num");
+ cpstr CIFTAG_NDB_SYNONYMS = cpstr("ndb_synonyms");
+ cpstr CIFTAG_NUM = cpstr("num");
+ cpstr CIFTAG_NUMBER_ATOMS_NH = cpstr("number_atoms_nh");
+ cpstr CIFTAG_NUMBER_STRANDS = cpstr("number_strands");
+ cpstr CIFTAG_OCCUPANCY = cpstr("occupancy");
+ cpstr CIFTAG_OCCUPANCY_ESD = cpstr("occupancy_esd");
+ cpstr CIFTAG_ORIGX11 = cpstr("origx[1][1]");
+ cpstr CIFTAG_ORIGX12 = cpstr("origx[1][2]");
+ cpstr CIFTAG_ORIGX13 = cpstr("origx[1][3]");
+ cpstr CIFTAG_ORIGX21 = cpstr("origx[2][1]");
+ cpstr CIFTAG_ORIGX22 = cpstr("origx[2][2]");
+ cpstr CIFTAG_ORIGX23 = cpstr("origx[2][3]");
+ cpstr CIFTAG_ORIGX31 = cpstr("origx[3][1]");
+ cpstr CIFTAG_ORIGX32 = cpstr("origx[3][2]");
+ cpstr CIFTAG_ORIGX33 = cpstr("origx[3][3]");
+ cpstr CIFTAG_ORIGX_VECTOR1 = cpstr("origx_vector[1]");
+ cpstr CIFTAG_ORIGX_VECTOR2 = cpstr("origx_vector[2]");
+ cpstr CIFTAG_ORIGX_VECTOR3 = cpstr("origx_vector[3]");
+ cpstr CIFTAG_PDB_ID = cpstr("pdb_id");
+ cpstr CIFTAG_PDB_MON_ID = cpstr("pdb_mon_id");
+ cpstr CIFTAG_PDB_STRAND_ID = cpstr("pdb_strand_id");
+ cpstr CIFTAG_PDBX_DB_ACCESSION = cpstr("pdbx_db_accession");
+ cpstr CIFTAG_PDBX_DB_ALIGN_BEG_INS_CODE = cpstr("pdbx_db_align_beg_ins_code");
+ cpstr CIFTAG_PDBX_DB_ALIGN_END_INS_CODE = cpstr("pdbx_db_align_end_ins_code");
+ cpstr CIFTAG_PDBX_PDB_ID_CODE = cpstr("pdbx_PDB_id_code");
+ cpstr CIFTAG_PDBX_PDB_MODEL_NUM = cpstr("pdbx_PDB_model_num");
+ cpstr CIFTAG_PDBX_STRAND_ID = cpstr("pdbx_strand_id");
+ cpstr CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID = cpstr("range_1_beg_label_atom_id");
+ cpstr CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID = cpstr("range_1_beg_label_seq_id");
+ cpstr CIFTAG_RANGE_1_END_LABEL_ATOM_ID = cpstr("range_1_end_label_atom_id");
+ cpstr CIFTAG_RANGE_1_END_LABEL_SEQ_ID = cpstr("range_1_end_label_seq_id");
+ cpstr CIFTAG_RANGE_ID_1 = cpstr("range_id_1");
+ cpstr CIFTAG_RANGE_ID_2 = cpstr("range_id_2");
+ cpstr CIFTAG_RCSB_RECORD_REVISED_1 = cpstr("rcsb_record_revised_1");
+ cpstr CIFTAG_RCSB_RECORD_REVISED_2 = cpstr("rcsb_record_revised_2");
+ cpstr CIFTAG_RCSB_RECORD_REVISED_3 = cpstr("rcsb_record_revised_3");
+ cpstr CIFTAG_RCSB_RECORD_REVISED_4 = cpstr("rcsb_record_revised_4");
+ cpstr CIFTAG_PDBX_SEQ_ALIGN_BEG_INS_CODE = cpstr("pdbx_seq_align_beg_ins_code");
+ cpstr CIFTAG_PDBX_SEQ_ALIGN_END_INS_CODE = cpstr("pdbx_seq_align_end_ins_code");
+ cpstr CIFTAG_PTNR1_LABEL_ASYM_ID = cpstr("ptnr1_label_asym_id");
+ cpstr CIFTAG_PTNR1_LABEL_COMP_ID = cpstr("ptnr1_label_comp_id");
+ cpstr CIFTAG_PTNR1_LABEL_SEQ_ID = cpstr("ptnr1_label_seq_id");
+ cpstr CIFTAG_REF_ID = cpstr("ref_id");
+ cpstr CIFTAG_REPLACES = cpstr("replaces");
+ cpstr CIFTAG_REPLACE_PDB_ID = cpstr("replace_pdb_id");
+ cpstr CIFTAG_SEGMENT_ID = cpstr("segment_id");
+ cpstr CIFTAG_SEQ_ALIGN_BEG = cpstr("seq_align_beg");
+ cpstr CIFTAG_SEQ_ALIGN_END = cpstr("seq_align_end");
+ cpstr CIFTAG_SEQ_NUM = cpstr("seq_num");
+ cpstr CIFTAG_SENSE = cpstr("sense");
+ cpstr CIFTAG_SHEET_ID = cpstr("sheet_id");
+ cpstr CIFTAG_SOURCE = cpstr("source");
+ cpstr CIFTAG_SPACE_GROUP_NAME_H_M = cpstr("space_group_name_H-M");
+ cpstr CIFTAG_TEXT = cpstr("text");
+ cpstr CIFTAG_TITLE = cpstr("title");
+ cpstr CIFTAG_TYPE = cpstr("type");
+ cpstr CIFTAG_TYPE_SYMBOL = cpstr("type_symbol");
+ cpstr CIFTAG_VECTOR1 = cpstr("vector[1]");
+ cpstr CIFTAG_VECTOR2 = cpstr("vector[2]");
+ cpstr CIFTAG_VECTOR3 = cpstr("vector[3]");
+ cpstr CIFTAG_U11 = cpstr("u[1][1]");
+ cpstr CIFTAG_U11_ESD = cpstr("u[1][1]_esd");
+ cpstr CIFTAG_U12 = cpstr("u[1][2]");
+ cpstr CIFTAG_U12_ESD = cpstr("u[1][2]_esd");
+ cpstr CIFTAG_U13 = cpstr("u[1][3]");
+ cpstr CIFTAG_U13_ESD = cpstr("u[1][3]_esd");
+ cpstr CIFTAG_U22 = cpstr("u[2][2]");
+ cpstr CIFTAG_U22_ESD = cpstr("u[2][2]_esd");
+ cpstr CIFTAG_U23 = cpstr("u[2][3]");
+ cpstr CIFTAG_U23_ESD = cpstr("u[2][3]_esd");
+ cpstr CIFTAG_U33 = cpstr("u[3][3]");
+ cpstr CIFTAG_U33_ESD = cpstr("u[3][3]_esd");
+ cpstr CIFTAG_Z_PDB = cpstr("z_pdb");
+
+ cpstr CIFTAG_CONN_PTNR1_AUTH_ATOM_ID = cpstr("ptnr1_auth_atom_id");
+ cpstr CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID = cpstr("pdbx_ptnr1_auth_alt_id");
+ cpstr CIFTAG_CONN_PTNR1_AUTH_COMP_ID = cpstr("ptnr1_auth_comp_id");
+ cpstr CIFTAG_CONN_PTNR1_AUTH_ASYM_ID = cpstr("ptnr1_auth_asym_id");
+ cpstr CIFTAG_CONN_PTNR1_AUTH_SEQ_ID = cpstr("ptnr1_auth_seq_id");
+ cpstr CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE = cpstr("pdbx_ptnr1_PDB_ins_code");
+ cpstr CIFTAG_CONN_DIST = cpstr("link_dist");
+ cpstr CIFTAG_CONN_PTNR2_AUTH_ATOM_ID = cpstr("ptnr2_auth_atom_id");
+ cpstr CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID = cpstr("pdbx_ptnr2_auth_alt_id");
+ cpstr CIFTAG_CONN_PTNR2_AUTH_COMP_ID = cpstr("ptnr2_auth_comp_id");
+ cpstr CIFTAG_CONN_PTNR2_AUTH_ASYM_ID = cpstr("ptnr2_auth_asym_id");
+ cpstr CIFTAG_CONN_PTNR2_AUTH_SEQ_ID = cpstr("ptnr2_auth_seq_id");
+ cpstr CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE = cpstr("pdbx_ptnr2_PDB_ins_code");
+ cpstr CIFTAG_CONN_PTNR1_SYMMETRY = cpstr("ptnr1_symmetry");
+ cpstr CIFTAG_CONN_PTNR2_SYMMETRY = cpstr("ptnr2_symmetry");
+ cpstr CIFTAG_CONN_NAME = cpstr("link_name");
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_cifdefs.h b/mmdb2/mmdb_cifdefs.h
new file mode 100644
index 0000000..2185b85
--- /dev/null
+++ b/mmdb2/mmdb_cifdefs.h
@@ -0,0 +1,329 @@
+// $Id: mmdb_cifdefs.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 21.11.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDBF_Defs <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Namespace: mmdb::
+//
+// CIF Definitions
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_CIFDefs__
+#define __MMDB_CIFDefs__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb {
+
+ // ------------------------------------------------------------------
+
+ // Mode IDs
+
+ enum CIF_MODE {
+ CIF_NDB = 0,
+ CIF_PDBX = 1
+ };
+
+ // CIF IDs for mode-dependent CIF names
+
+ enum CIF_ID {
+ CAT_POLY_SEQ_SCHEME = 1,
+ TAG_CHAIN_ID = 101,
+ TAG_DB_ACCESSION = 102,
+ TAG_DB_ALIGN_BEG = 103,
+ TAG_DB_ALIGN_BEG_INS_CODE = 104,
+ TAG_DB_ALIGN_END = 105,
+ TAG_DB_ALIGN_END_INS_CODE = 106,
+ TAG_ID_CODE = 107,
+ TAG_SEQ_CHAIN_ID = 108,
+ TAG_SEQ_ALIGN_BEG = 109,
+ TAG_SEQ_ALIGN_BEG_INS_CODE = 110,
+ TAG_SEQ_ALIGN_END = 111,
+ TAG_SEQ_ALIGN_END_INS_CODE = 112
+ };
+
+ // CIFName(..) gives CIF name according to CIF Mode.
+ extern cpstr CIFName ( int NameID, CIF_MODE Mode );
+
+ // ------------------------------------------------------------------
+
+ extern cpstr CIFCAT_ATOM_SITE ;
+ extern cpstr CIFCAT_ATOM_SITE_ANISOTROP ;
+ extern cpstr CIFCAT_ATOM_SITES ;
+ extern cpstr CIFCAT_AUDIT_AUTHOR ;
+ extern cpstr CIFCAT_CELL ;
+ extern cpstr CIFCAT_CHEM_COMP ;
+ extern cpstr CIFCAT_CITATION ;
+ extern cpstr CIFCAT_DATABASE ;
+ extern cpstr CIFCAT_DATABASE_PDB_CAVEAT ;
+ extern cpstr CIFCAT_DATABASE_PDB_MATRIX ;
+ extern cpstr CIFCAT_DATABASE_PDB_REV ;
+ extern cpstr CIFCAT_DATABASE_PDB_TVECT ;
+ extern cpstr CIFCAT_ENTITY ;
+ extern cpstr CIFCAT_EXPTL ;
+ extern cpstr CIFCAT_NDB_DATABASE_REMARK ;
+ extern cpstr CIFCAT_NDB_NONSTANDARD_LIST ;
+ extern cpstr CIFCAT_NDB_POLY_SEQ_SCHEME ;
+ extern cpstr CIFCAT_PDBX_POLY_SEQ_SCHEME ;
+ extern cpstr CIFCAT_REFINE ;
+ extern cpstr CIFCAT_SPRSDE ;
+ extern cpstr CIFCAT_STRUCT ;
+ extern cpstr CIFCAT_STRUCT_ASYM ;
+ extern cpstr CIFCAT_STRUCT_CONF ;
+ extern cpstr CIFCAT_STRUCT_CONN ;
+ extern cpstr CIFCAT_STRUCT_LINKR ;
+ extern cpstr CIFCAT_STRUCT_KEYWORDS ;
+ extern cpstr CIFCAT_STRUCT_NCS_OPER ;
+ extern cpstr CIFCAT_STRUCT_REF ;
+ extern cpstr CIFCAT_STRUCT_REF_SEQ ;
+ extern cpstr CIFCAT_STRUCT_REF_SEQ_DIF ;
+ extern cpstr CIFCAT_STRUCT_SHEET ;
+ extern cpstr CIFCAT_STRUCT_SHEET_RANGE ;
+ extern cpstr CIFCAT_STRUCT_SHEET_ORDER ;
+ extern cpstr CIFCAT_STRUCT_SHEET_HBOND ;
+ extern cpstr CIFCAT_SYMMETRY ;
+ extern cpstr CIFCAT_OBSLTE ;
+
+
+ extern cpstr CIFTAG_ANGLE_ALPHA ;
+ extern cpstr CIFTAG_ANGLE_BETA ;
+ extern cpstr CIFTAG_ANGLE_GAMMA ;
+ extern cpstr CIFTAG_ASYM_ID ;
+ extern cpstr CIFTAG_ATOM_TYPE_SYMBOL ;
+ extern cpstr CIFTAG_AUTH_ASYM_ID ;
+ extern cpstr CIFTAG_AUTH_ATOM_ID ;
+ extern cpstr CIFTAG_AUTH_COMP_ID ;
+ extern cpstr CIFTAG_AUTH_SEQ_ID ;
+ extern cpstr CIFTAG_B_ISO_OR_EQUIV ;
+ extern cpstr CIFTAG_B_ISO_OR_EQUIV_ESD ;
+ extern cpstr CIFTAG_BEG_LABEL_ASYM_ID ;
+ extern cpstr CIFTAG_BEG_LABEL_COMP_ID ;
+ extern cpstr CIFTAG_BEG_LABEL_SEQ_ID ;
+ extern cpstr CIFTAG_CARTN_X ;
+ extern cpstr CIFTAG_CARTN_X_ESD ;
+ extern cpstr CIFTAG_CARTN_Y ;
+ extern cpstr CIFTAG_CARTN_Y_ESD ;
+ extern cpstr CIFTAG_CARTN_Z ;
+ extern cpstr CIFTAG_CARTN_Z_ESD ;
+ extern cpstr CIFTAG_PDBX_FORMAL_CHARGE ;
+ extern cpstr CIFTAG_CODE ;
+ extern cpstr CIFTAG_CODE_NDB ;
+ extern cpstr CIFTAG_CODE_PDB ;
+ extern cpstr CIFTAG_CONF_TYPE_ID ;
+ extern cpstr CIFTAG_CONN_TYPE_ID ;
+ extern cpstr CIFTAG_DATE ;
+ extern cpstr CIFTAG_DATE_ORIGINAL ;
+ extern cpstr CIFTAG_DB_ALIGN_BEG ;
+ extern cpstr CIFTAG_DB_ALIGN_END ;
+ extern cpstr CIFTAG_DB_CODE ;
+ extern cpstr CIFTAG_DB_MON_ID ;
+ extern cpstr CIFTAG_DB_NAME ;
+ extern cpstr CIFTAG_DETAILS ;
+ extern cpstr CIFTAG_END_LABEL_ASYM_ID ;
+ extern cpstr CIFTAG_END_LABEL_COMP_ID ;
+ extern cpstr CIFTAG_END_LABEL_SEQ_ID ;
+ extern cpstr CIFTAG_ENTITY_ID ;
+ extern cpstr CIFTAG_ENTRY_ID ;
+ extern cpstr CIFTAG_FORMULA ;
+ extern cpstr CIFTAG_FRACT_TRANSF_MATRIX11 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_MATRIX12 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_MATRIX13 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_MATRIX21 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_MATRIX22 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_MATRIX23 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_MATRIX31 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_MATRIX32 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_MATRIX33 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_VECTOR1 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_VECTOR2 ;
+ extern cpstr CIFTAG_FRACT_TRANSF_VECTOR3 ;
+ extern cpstr CIFTAG_GROUP_PDB ;
+ extern cpstr CIFTAG_ID ;
+ extern cpstr CIFTAG_INS_CODE ;
+ extern cpstr CIFTAG_LABEL_ALT_ID ;
+ extern cpstr CIFTAG_LABEL_ATOM_ID ;
+ extern cpstr CIFTAG_LABEL_ASYM_ID ;
+ extern cpstr CIFTAG_LABEL_COMP_ID ;
+ extern cpstr CIFTAG_LABEL_ENTITY_ID ;
+ extern cpstr CIFTAG_LABEL_SEQ_ID ;
+ extern cpstr CIFTAG_LENGTH_A ;
+ extern cpstr CIFTAG_LENGTH_B ;
+ extern cpstr CIFTAG_LENGTH_C ;
+ extern cpstr CIFTAG_LS_D_RES_HIGH ;
+ extern cpstr CIFTAG_MATRIX11 ;
+ extern cpstr CIFTAG_MATRIX12 ;
+ extern cpstr CIFTAG_MATRIX13 ;
+ extern cpstr CIFTAG_MATRIX21 ;
+ extern cpstr CIFTAG_MATRIX22 ;
+ extern cpstr CIFTAG_MATRIX23 ;
+ extern cpstr CIFTAG_MATRIX31 ;
+ extern cpstr CIFTAG_MATRIX32 ;
+ extern cpstr CIFTAG_MATRIX33 ;
+ extern cpstr CIFTAG_METHOD ;
+ extern cpstr CIFTAG_MOD_TYPE ;
+ extern cpstr CIFTAG_MON_ID ;
+ extern cpstr CIFTAG_NAME ;
+ extern cpstr CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB ;
+ extern cpstr CIFTAG_NDB_CHAIN_ID ;
+ extern cpstr CIFTAG_NDB_COMPONENT_NO ;
+ extern cpstr CIFTAG_NDB_DESCRIPTOR ;
+ extern cpstr CIFTAG_NDB_DB_ACCESSION ;
+ extern cpstr CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE ;
+ extern cpstr CIFTAG_NDB_DB_ALIGN_END_INS_CODE ;
+ extern cpstr CIFTAG_NDB_END_LABEL_INS_CODE_PDB ;
+ extern cpstr CIFTAG_PDBX_PDB_INS_CODE ;
+ extern cpstr CIFTAG_NDB_HELIX_CLASS_PDB ;
+ extern cpstr CIFTAG_NDB_KEYWORDS ;
+ extern cpstr CIFTAG_NDB_LABEL_ALT_ID ;
+ extern cpstr CIFTAG_NDB_LABEL_ATOM_ID ;
+ extern cpstr CIFTAG_NDB_LABEL_ASYM_ID ;
+ extern cpstr CIFTAG_NDB_LABEL_COMP_ID ;
+ extern cpstr CIFTAG_NDB_LABEL_INS_CODE ;
+ extern cpstr CIFTAG_NDB_LABEL_SEQ_NUM ;
+ extern cpstr CIFTAG_NDB_LENGTH ;
+ extern cpstr CIFTAG_NDB_MODEL ;
+ extern cpstr CIFTAG_NDB_PDB_CHAIN_ID ;
+ extern cpstr CIFTAG_NDB_PDB_ID ;
+ extern cpstr CIFTAG_NDB_PDB_ID_CODE ;
+ extern cpstr CIFTAG_NDB_PDB_INS_CODE ;
+ extern cpstr CIFTAG_NDB_PTNR1_LABEL_INS_CODE ;
+ extern cpstr CIFTAG_NDB_PTNR1_STANDARD_COMP_ID ;
+ extern cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID ;
+ extern cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID ;
+ extern cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE;
+ extern cpstr CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID ;
+ extern cpstr CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID ;
+ extern cpstr CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE;
+ extern cpstr CIFTAG_NDB_SEQ_ALIGN_BEG ;
+ extern cpstr CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE ;
+ extern cpstr CIFTAG_NDB_SEQ_ALIGN_END ;
+ extern cpstr CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE ;
+ extern cpstr CIFTAG_NDB_SEQ_DB_NAME ;
+ extern cpstr CIFTAG_NDB_SEQ_DB_ACCESSION_CODE ;
+ extern cpstr CIFTAG_NDB_SEQ_DB_SEQ_NUM ;
+ extern cpstr CIFTAG_NDB_SYNONYMS ;
+ extern cpstr CIFTAG_NUM ;
+ extern cpstr CIFTAG_NUMBER_ATOMS_NH ;
+ extern cpstr CIFTAG_NUMBER_STRANDS ;
+ extern cpstr CIFTAG_OCCUPANCY ;
+ extern cpstr CIFTAG_OCCUPANCY_ESD ;
+ extern cpstr CIFTAG_ORIGX11 ;
+ extern cpstr CIFTAG_ORIGX12 ;
+ extern cpstr CIFTAG_ORIGX13 ;
+ extern cpstr CIFTAG_ORIGX21 ;
+ extern cpstr CIFTAG_ORIGX22 ;
+ extern cpstr CIFTAG_ORIGX23 ;
+ extern cpstr CIFTAG_ORIGX31 ;
+ extern cpstr CIFTAG_ORIGX32 ;
+ extern cpstr CIFTAG_ORIGX33 ;
+ extern cpstr CIFTAG_ORIGX_VECTOR1 ;
+ extern cpstr CIFTAG_ORIGX_VECTOR2 ;
+ extern cpstr CIFTAG_ORIGX_VECTOR3 ;
+ extern cpstr CIFTAG_PDB_ID ;
+ extern cpstr CIFTAG_PDB_MON_ID ;
+ extern cpstr CIFTAG_PDB_STRAND_ID ;
+ extern cpstr CIFTAG_PDBX_DB_ACCESSION ;
+ extern cpstr CIFTAG_PDBX_DB_ALIGN_BEG_INS_CODE ;
+ extern cpstr CIFTAG_PDBX_DB_ALIGN_END_INS_CODE ;
+ extern cpstr CIFTAG_PDBX_PDB_ID_CODE ;
+ extern cpstr CIFTAG_PDBX_PDB_MODEL_NUM ;
+ extern cpstr CIFTAG_PDBX_STRAND_ID ;
+ extern cpstr CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID ;
+ extern cpstr CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID ;
+ extern cpstr CIFTAG_RANGE_1_END_LABEL_ATOM_ID ;
+ extern cpstr CIFTAG_RANGE_1_END_LABEL_SEQ_ID ;
+ extern cpstr CIFTAG_RANGE_ID_1 ;
+ extern cpstr CIFTAG_RANGE_ID_2 ;
+ extern cpstr CIFTAG_RCSB_RECORD_REVISED_1 ;
+ extern cpstr CIFTAG_RCSB_RECORD_REVISED_2 ;
+ extern cpstr CIFTAG_RCSB_RECORD_REVISED_3 ;
+ extern cpstr CIFTAG_RCSB_RECORD_REVISED_4 ;
+ extern cpstr CIFTAG_PDBX_SEQ_ALIGN_BEG_INS_CODE ;
+ extern cpstr CIFTAG_PDBX_SEQ_ALIGN_END_INS_CODE ;
+ extern cpstr CIFTAG_PTNR1_LABEL_ASYM_ID ;
+ extern cpstr CIFTAG_PTNR1_LABEL_COMP_ID ;
+ extern cpstr CIFTAG_PTNR1_LABEL_SEQ_ID ;
+ extern cpstr CIFTAG_REF_ID ;
+ extern cpstr CIFTAG_REPLACES ;
+ extern cpstr CIFTAG_REPLACE_PDB_ID ;
+ extern cpstr CIFTAG_SEGMENT_ID ;
+ extern cpstr CIFTAG_SEQ_ALIGN_BEG ;
+ extern cpstr CIFTAG_SEQ_ALIGN_END ;
+ extern cpstr CIFTAG_SEQ_NUM ;
+ extern cpstr CIFTAG_SENSE ;
+ extern cpstr CIFTAG_SHEET_ID ;
+ extern cpstr CIFTAG_SOURCE ;
+ extern cpstr CIFTAG_SPACE_GROUP_NAME_H_M ;
+ extern cpstr CIFTAG_TEXT ;
+ extern cpstr CIFTAG_TITLE ;
+ extern cpstr CIFTAG_TYPE ;
+ extern cpstr CIFTAG_TYPE_SYMBOL ;
+ extern cpstr CIFTAG_VECTOR1 ;
+ extern cpstr CIFTAG_VECTOR2 ;
+ extern cpstr CIFTAG_VECTOR3 ;
+ extern cpstr CIFTAG_U11 ;
+ extern cpstr CIFTAG_U11_ESD ;
+ extern cpstr CIFTAG_U12 ;
+ extern cpstr CIFTAG_U12_ESD ;
+ extern cpstr CIFTAG_U13 ;
+ extern cpstr CIFTAG_U13_ESD ;
+ extern cpstr CIFTAG_U22 ;
+ extern cpstr CIFTAG_U22_ESD ;
+ extern cpstr CIFTAG_U23 ;
+ extern cpstr CIFTAG_U23_ESD ;
+ extern cpstr CIFTAG_U33 ;
+ extern cpstr CIFTAG_U33_ESD ;
+ extern cpstr CIFTAG_Z_PDB ;
+
+ extern cpstr CIFTAG_CONN_PTNR1_AUTH_ATOM_ID ;
+ extern cpstr CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID ;
+ extern cpstr CIFTAG_CONN_PTNR1_AUTH_COMP_ID ;
+ extern cpstr CIFTAG_CONN_PTNR1_AUTH_ASYM_ID ;
+ extern cpstr CIFTAG_CONN_PTNR1_AUTH_SEQ_ID ;
+ extern cpstr CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE ;
+ extern cpstr CIFTAG_CONN_DIST ;
+ extern cpstr CIFTAG_CONN_PTNR2_AUTH_ATOM_ID ;
+ extern cpstr CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID ;
+ extern cpstr CIFTAG_CONN_PTNR2_AUTH_COMP_ID ;
+ extern cpstr CIFTAG_CONN_PTNR2_AUTH_ASYM_ID ;
+ extern cpstr CIFTAG_CONN_PTNR2_AUTH_SEQ_ID ;
+ extern cpstr CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE ;
+ extern cpstr CIFTAG_CONN_PTNR1_SYMMETRY ;
+ extern cpstr CIFTAG_CONN_PTNR2_SYMMETRY ;
+ extern cpstr CIFTAG_CONN_NAME ;
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_coormngr.cpp b/mmdb2/mmdb_coormngr.cpp
new file mode 100644
index 0000000..0ab4fbf
--- /dev/null
+++ b/mmdb2/mmdb_coormngr.cpp
@@ -0,0 +1,4347 @@
+// $Id: mmdb_coormngr.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 14.07.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_coormngr <implementation>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Brick ( space brick )
+// ~~~~~~~~~ mmdb::CoorManager ( MMDB atom coordinate manager )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <math.h>
+#include <string.h>
+
+#include "mmdb_coormngr.h"
+#include "mmdb_math_linalg.h"
+#include "mmdb_tables.h"
+
+namespace mmdb {
+
+ // ========================== Brick =============================
+
+ Brick::Brick() {
+ InitBrick();
+ }
+
+ Brick::~Brick() {
+ Clear();
+ }
+
+ void Brick::InitBrick() {
+ atom = NULL;
+ id = NULL;
+ nAtoms = 0;
+ nAllocAtoms = 0;
+ }
+
+ void Brick::Clear() {
+ if (atom) delete[] atom;
+ FreeVectorMemory ( id,0 );
+ atom = NULL;
+ nAtoms = 0;
+ nAllocAtoms = 0;
+ }
+
+ void Brick::AddAtom ( PAtom A, int atomid ) {
+ int i;
+ PPAtom atom1;
+ ivector id1;
+ if (nAtoms>=nAllocAtoms) {
+ nAllocAtoms = nAtoms+10;
+ atom1 = new PAtom[nAllocAtoms];
+ GetVectorMemory ( id1,nAllocAtoms,0 );
+ for (i=0;i<nAtoms;i++) {
+ atom1[i] = atom[i];
+ id1 [i] = id [i];
+ }
+ for (i=nAtoms;i<nAllocAtoms;i++) {
+ atom1[i] = NULL;
+ id1 [i] = -1;
+ }
+ if (atom) delete[] atom;
+ FreeVectorMemory ( id,0 );
+ atom = atom1;
+ id = id1;
+ }
+ atom[nAtoms] = A;
+ id [nAtoms] = atomid;
+ nAtoms++;
+ }
+
+
+ // =========================== mbrick =============================
+
+ MBrick::MBrick ( int nStructures ) {
+ InitMBrick ( nStructures );
+ }
+
+ MBrick::~MBrick() {
+ Clear();
+ }
+
+ void MBrick::InitMBrick ( int nStructures ) {
+ int i;
+ nStruct = nStructures;
+ atom = new PPAtom[nStruct];
+ id = new ivector[nStruct];
+ GetVectorMemory ( nAtoms,nStruct,0 );
+ GetVectorMemory ( nAlloAtoms,nStruct,0 );
+ for (i=0;i<nStruct;i++) {
+ atom [i] = NULL;
+ id [i] = NULL;
+ nAtoms [i] = 0;
+ nAlloAtoms[i] = 0;
+ }
+ }
+
+ void MBrick::Clear() {
+ int i;
+ if (atom) {
+ for (i=0;i<nStruct;i++)
+ if (atom[i]) delete[] atom[i];
+ delete[] atom;
+ atom = NULL;
+ }
+ FreeMatrixMemory ( id,nStruct,0,0 );
+ FreeVectorMemory ( nAtoms,0 );
+ FreeVectorMemory ( nAlloAtoms,0 );
+ nStruct = 0;
+ }
+
+ void MBrick::AddAtom ( PAtom A, int structNo, int atomid ) {
+ int i,natoms,nalloc;
+ PPAtom atom0,atom1;
+ ivector id0,id1;
+ natoms = nAtoms [structNo];
+ nalloc = nAlloAtoms[structNo];
+ atom0 = atom [structNo];
+ id0 = id [structNo];
+ if (natoms>=nalloc) {
+ nalloc = natoms+10;
+ atom1 = new PAtom[nalloc];
+ GetVectorMemory ( id1,nalloc,0 );
+ for (i=0;i<natoms;i++) {
+ atom1[i] = atom0[i];
+ id1 [i] = id0 [i];
+ }
+ for (i=natoms;i<nalloc;i++) {
+ atom1[i] = NULL;
+ id1 [i] = -1;
+ }
+ if (atom0) delete[] atom0;
+ FreeVectorMemory ( id0,0 );
+ atom[structNo] = atom1;
+ id [structNo] = id1;
+ nAlloAtoms[structNo] = nalloc;
+ atom0 = atom1;
+ id0 = id1;
+ }
+ atom0 [natoms] = A;
+ id0 [natoms] = atomid;
+ nAtoms[structNo] = natoms+1;
+ }
+
+
+
+ // ==================== GenSym ========================
+
+ GenSym::GenSym() : SymOps() {
+ InitGenSym();
+ }
+
+ GenSym::GenSym ( io::RPStream Object ) : SymOps(Object) {
+ InitGenSym();
+ }
+
+ GenSym::~GenSym() {} // virtual FreeMmeory is called by ~SymOps()
+
+ void GenSym::InitGenSym() {
+ chID1 = NULL;
+ chID2 = NULL;
+ nChains = NULL;
+ nOpAlloc = 0;
+ }
+
+ void GenSym::FreeMemory() {
+ int i;
+ for (i=0;i<nOpAlloc;i++) {
+ if (chID1[i]) delete[] chID1[i];
+ if (chID2[i]) delete[] chID2[i];
+ }
+ if (chID1) delete[] chID1;
+ if (chID2) delete[] chID2;
+ FreeVectorMemory ( nChains,0 );
+ nOpAlloc = 0;
+ SymOps::FreeMemory();
+ }
+
+ int GenSym::AddSymOp ( cpstr XYZOperation ) {
+ int RC,i;
+ PChainID * ch1ID;
+ PChainID * ch2ID;
+ ivector nChains1;
+
+ RC = SymOps::AddSymOp ( XYZOperation );
+ if (Nops>nOpAlloc) {
+ ch1ID = new PChainID[Nops];
+ ch2ID = new PChainID[Nops];
+ GetVectorMemory ( nChains1,Nops,0 );
+ for (i=0;i<nOpAlloc;i++) {
+ ch1ID[i] = chID1[i];
+ ch2ID[i] = chID2[i];
+ nChains1[i] = nChains[i];
+ }
+ for (i=nOpAlloc;i<Nops;i++) {
+ ch1ID[i] = NULL;
+ ch2ID[i] = NULL;
+ nChains1[i] = 0;
+ }
+ if (chID1) delete[] chID1;
+ if (chID2) delete[] chID2;
+ FreeVectorMemory ( nChains,0 );
+ chID1 = ch1ID;
+ chID2 = ch2ID;
+ nChains = nChains1;
+ nOpAlloc = Nops;
+ }
+ return RC;
+ }
+
+ int GenSym::AddRenChain ( int Nop, const ChainID ch1,
+ const ChainID ch2 ) {
+ int i;
+ PChainID c1,c2;
+ if ((0<=Nop) && (Nop<Nops)) {
+ c1 = new ChainID[nChains[Nop]+1];
+ c2 = new ChainID[nChains[Nop]+1];
+ for (i=0;i<nChains[Nop];i++) {
+ strcpy ( c1[i],chID1[Nop][i] );
+ strcpy ( c2[i],chID2[Nop][i] );
+ }
+ strcpy ( c1[nChains[Nop]],ch1 );
+ strcpy ( c2[nChains[Nop]],ch2 );
+ if (chID1[Nop]) delete[] chID1[Nop];
+ if (chID2[Nop]) delete[] chID2[Nop];
+ chID1[Nop] = c1;
+ chID2[Nop] = c2;
+ nChains[Nop]++;
+ return SYMOP_Ok;
+ } else
+ return SYMOP_NoSymOps;
+ }
+
+ void GenSym::Copy ( PSymOps GenSym ) {
+ int i,j;
+ SymOps::Copy ( GenSym );
+ if (Nops>0) {
+ nOpAlloc = Nops;
+ chID1 = new PChainID[Nops];
+ chID2 = new PChainID[Nops];
+ GetVectorMemory ( nChains,Nops,0 );
+ for (i=0;i<Nops;i++) {
+ nChains[i] = PGenSym(GenSym)->nChains[i];
+ if (nChains[i]<=0) {
+ chID1[i] = NULL;
+ chID2[i] = NULL;
+ } else {
+ chID1[i] = new ChainID[nChains[i]];
+ chID2[i] = new ChainID[nChains[i]];
+ for (j=0;j<nChains[i];j++) {
+ strcpy ( chID1[i][j],PGenSym(GenSym)->chID1[i][j] );
+ strcpy ( chID2[i][j],PGenSym(GenSym)->chID2[i][j] );
+ }
+ }
+ }
+ }
+ }
+
+ void GenSym::write ( io::RFile f ) {
+ int i,j;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ SymOps::write ( f );
+ f.WriteInt ( &nOpAlloc );
+ for (i=0;i<nOpAlloc;i++) {
+ f.WriteInt ( &(nChains[i]) );
+ for (j=0;j<nChains[i];j++) {
+ f.WriteTerLine ( chID1[i][j],false );
+ f.WriteTerLine ( chID2[i][j],false );
+ }
+ }
+ }
+
+ void GenSym::read ( io::RFile f ) {
+ int i,j;
+ byte Version;
+ f.ReadByte ( &Version );
+ SymOps::read ( f );
+ f.ReadInt ( &nOpAlloc );
+ if (nOpAlloc>0) {
+ chID1 = new PChainID[nOpAlloc];
+ chID2 = new PChainID[nOpAlloc];
+ GetVectorMemory ( nChains,nOpAlloc,0 );
+ for (i=0;i<nOpAlloc;i++) {
+ f.ReadInt ( &(nChains[i]) );
+ if (nChains[i]>0) {
+ chID1[i] = new ChainID[nChains[i]];
+ chID2[i] = new ChainID[nChains[i]];
+ for (j=0;j<nChains[i];j++) {
+ f.ReadTerLine ( chID1[i][j],false );
+ f.ReadTerLine ( chID2[i][j],false );
+ }
+ } else {
+ chID1[i] = NULL;
+ chID2[i] = NULL;
+ }
+ }
+ }
+ }
+
+
+ MakeStreamFunctions(GenSym)
+
+
+
+ // ======================= ContactIndex ==========================
+
+ void Contact::Copy ( RContact c ) {
+ id1 = c.id1;
+ id2 = c.id2;
+ group = c.group;
+ dist = c.dist;
+ }
+
+ void Contact::Swap ( RContact c ) {
+ int ib;
+ long lb;
+ realtype rb;
+ ib = id1; id1 = c.id1; c.id1 = ib;
+ ib = id2; id2 = c.id2; c.id2 = ib;
+ lb = group; group = c.group; c.group = lb;
+ rb = dist; dist = c.dist; c.dist = rb;
+ }
+
+ DefineClass(ContactIndex)
+
+ class ContactIndex {
+
+ friend class SelManager;
+
+ public :
+
+ ContactIndex ( PContact contact,
+ int maxlen,
+ int ncontacts,
+ int max_alloc );
+ ~ContactIndex();
+
+ void AddContact ( int id1, int id2, realtype dist, int group );
+ void GetIndex ( RPContact contact, int & ncontacts );
+
+ protected :
+
+ PContact contact_index; // contact index
+ int max_index; // if <=0 then dynamical index
+ // otherwise fixed by max_index
+ int n_contacts; // number of contacts
+ int alloc_index; // physical length of contact_index
+ // when dynamical
+ int alloc_max; // physical limit on allocation
+
+ };
+
+
+ ContactIndex::ContactIndex ( PContact contact,
+ int maxlen,
+ int ncontacts,
+ int max_alloc ) {
+ contact_index = contact;
+ max_index = maxlen;
+ if (!contact_index) n_contacts = 0;
+ else n_contacts = IMax(0,ncontacts);
+ alloc_index = n_contacts;
+ alloc_max = n_contacts + max_alloc;
+ }
+
+ ContactIndex::~ContactIndex() {
+ if (contact_index) delete[] contact_index;
+ contact_index = NULL;
+ n_contacts = 0;
+ alloc_index = 0;
+ }
+
+ void ContactIndex::AddContact ( int id1, int id2, realtype dist,
+ int group ) {
+ PContact cont1;
+ int i;
+
+ if ((alloc_max<=0) || (n_contacts<alloc_max)) {
+ if (max_index>0) {
+ if (n_contacts<max_index) {
+ contact_index[n_contacts].id1 = id1;
+ contact_index[n_contacts].id2 = id2;
+ contact_index[n_contacts].dist = dist;
+ contact_index[n_contacts].group = group;
+ }
+ } else {
+ if (n_contacts>=alloc_index) {
+ alloc_index = n_contacts+IMax(alloc_index/4+10,10);
+ if ((alloc_max>0) && (alloc_index>alloc_max))
+ alloc_index = alloc_max;
+ cont1 = new Contact[alloc_index];
+ for (i=0;i<n_contacts;i++)
+ cont1[i].Copy ( contact_index[i] );
+ if (contact_index) delete[] contact_index;
+ contact_index = cont1;
+ }
+ contact_index[n_contacts].id1 = id1;
+ contact_index[n_contacts].id2 = id2;
+ contact_index[n_contacts].dist = dist;
+ contact_index[n_contacts].group = group;
+ }
+ n_contacts++;
+ }
+ }
+
+ void ContactIndex::GetIndex ( RPContact contact, int & ncontacts ) {
+ contact = contact_index;
+ ncontacts = n_contacts;
+ contact_index = NULL;
+ n_contacts = 0;
+ alloc_index = 0;
+ }
+
+
+ // ======================== MContact =============================
+
+ MContact::MContact ( int nStructures ) {
+ int i;
+ nStruct = nStructures;
+ if (nStruct>0) {
+ atom = new PPAtom[nStruct];
+ id = new ivector[nStruct];
+ GetVectorMemory ( nAtoms,nStruct,0 );
+ GetVectorMemory ( nAlloc,nStruct,0 );
+ for (i=0;i<nStruct;i++) {
+ atom [i] = NULL;
+ id [i] = NULL;
+ nAtoms[i] = 0;
+ nAlloc[i] = 0;
+ }
+ } else {
+ atom = NULL;
+ nAtoms = NULL;
+ nAlloc = NULL;
+ }
+ }
+
+ MContact::~MContact() {
+ int i;
+ if (atom) {
+ for (i=0;i<nStruct;i++)
+ if (atom[i]) delete[] atom[i];
+ delete[] atom;
+ atom = NULL;
+ }
+ FreeMatrixMemory ( id,nStruct,0,0 );
+ FreeVectorMemory ( nAtoms,0 );
+ FreeVectorMemory ( nAlloc,0 );
+ nStruct = 0;
+ }
+
+ void MContact::AddContact ( PAtom A, int structNo, int atomid ) {
+ PPAtom A1,A2;
+ ivector id1,id2;
+ int nat,nal,i;
+ A1 = atom [structNo];
+ id1 = id [structNo];
+ nat = nAtoms[structNo];
+ nal = nAlloc[structNo];
+ if (nat>=nal) {
+ nal = nat+10;
+ A2 = new PAtom[nal];
+ GetVectorMemory ( id2,nal,0 );
+ for (i=0;i<nat;i++) {
+ A2 [i] = A1 [i];
+ id2[i] = id1[i];
+ }
+ for (i=nat;i<nal;i++) {
+ A2 [i] = NULL;
+ id2[i] = 0;
+ }
+ if (A1) delete[] A1;
+ FreeVectorMemory ( id1,0 );
+ atom[structNo] = A2;
+ id [structNo] = id2;
+ A1 = A2;
+ id1 = id2;
+ nAlloc[structNo] = nal;
+ }
+ A1 [nat] = A;
+ id1[nat] = atomid;
+ nAtoms[structNo] = nat+1;
+ }
+
+
+ void DeleteMContacts ( PPMContact & mcontact, int nContacts ) {
+ int i;
+ if (mcontact) {
+ for (i=0;i<nContacts;i++)
+ if (mcontact[i]) delete mcontact[i];
+ delete[] mcontact;
+ mcontact = NULL;
+ }
+ }
+
+
+ // ==================== CoorManager =====================
+
+ CoorManager::CoorManager() : Root() {
+ InitMMDBCoorManager();
+ }
+
+ CoorManager::CoorManager ( io::RPStream Object ) : Root(Object) {
+ InitMMDBCoorManager();
+ }
+
+ CoorManager::~CoorManager() {
+ RemoveBricks ();
+ RemoveMBricks();
+ }
+
+ void CoorManager::ResetManager() {
+ Root::ResetManager();
+ RemoveBricks ();
+ RemoveMBricks ();
+ InitMMDBCoorManager();
+ }
+
+ void CoorManager::InitMMDBCoorManager() {
+
+ CoorIDCode = CID_Ok;
+
+ brick_size = 6.0; // angstroms
+ xbrick_0 = 0.0;
+ ybrick_0 = 0.0;
+ zbrick_0 = 0.0;
+ nbrick_x = 0;
+ nbrick_y = 0;
+ nbrick_z = 0;
+ brick = NULL;
+
+ mbrick_size = 6.0; // angstroms
+ xmbrick_0 = 0.0;
+ ymbrick_0 = 0.0;
+ zmbrick_0 = 0.0;
+ nmbrick_x = 0;
+ nmbrick_y = 0;
+ nmbrick_z = 0;
+ mbrick = NULL;
+
+ }
+
+
+ int CoorManager::SetDefaultCoorID ( cpstr CID ) {
+ return DefPath.SetPath ( CID );
+ }
+
+ PModel CoorManager::GetFirstDefinedModel() {
+ PModel mdl;
+ int i;
+ mdl = NULL;
+ for (i=0;(i<nModels) && (!mdl);i++)
+ mdl = model[i];
+ return mdl;
+ }
+
+ int CoorManager::GetFirstModelNum() {
+ PModel mdl;
+ int i;
+ mdl = NULL;
+ for (i=0;(i<nModels) && (!mdl);i++)
+ mdl = model[i];
+ if (mdl) return mdl->GetSerNum();
+ return 1;
+ }
+
+
+ PModel CoorManager::GetModel ( int modelNo ) {
+ if ((modelNo>=1) && (modelNo<=nModels))
+ return model[modelNo-1];
+ else return NULL;
+ }
+
+ PModel CoorManager::GetModel ( cpstr CID ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & APATH_WC_ModelNo)) {
+ CoorIDCode = CID_WrongPath;
+ return NULL;
+ }
+
+ if ((modno>=1) && (modno<=nModels))
+ return model[modno-1];
+ else return NULL;
+
+ }
+
+ void CoorManager::GetModelTable ( PPModel & modelTable,
+ int & NumberOfModels ) {
+ NumberOfModels = nModels;
+ modelTable = model;
+ }
+
+ int CoorManager::DeleteModel ( int modelNo ) {
+ if ((modelNo>=1) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ Exclude = false;
+ delete model[modelNo-1];
+ model[modelNo-1] = NULL;
+ Exclude = true;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteModel ( cpstr CID ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & APATH_WC_ModelNo)) {
+ CoorIDCode = CID_WrongPath;
+ return 0;
+ }
+
+ if ((modno>=1) && (modno<=nModels)) {
+ if (model[modno-1]) {
+ Exclude = false;
+ delete model[modno-1];
+ model[modno-1] = NULL;
+ Exclude = true;
+ return 1;
+ }
+ }
+
+ return 0;
+
+ }
+
+
+ int CoorManager::DeleteSolvent() {
+ int i,k;
+ Exclude = false;
+ k = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ k += model[i]->DeleteSolvent();
+ model[i]->TrimChainTable();
+ if (model[i]->nChains<=0) {
+ delete model[i];
+ model[i] = NULL;
+ }
+ }
+ Exclude = true;
+ return k;
+ }
+
+
+ // ---------------- Adding/Inserting models ---------------
+
+ int CoorManager::AddModel ( PModel mdl ) {
+ PPModel model1;
+ int i,nnat,nat1;
+
+ for (i=0;i<nModels;i++)
+ if (model[i]==mdl) return -i;
+
+ nnat = mdl->GetNumberOfAtoms ( true );
+ AddAtomArray ( nnat ); // get space for new atoms
+
+ if (mdl->GetCoordHierarchy()) {
+ SwitchModel ( nModels+1 ); // get one more model at the end
+ nat1 = nAtoms;
+ model[nModels-1]->_copy ( mdl,atom,nat1 );
+ model[nModels-1]->serNum = nModels;
+ nAtoms = nat1;
+ } else {
+ model1 = new PModel[nModels+1];
+ for (i=0;i<nModels;i++)
+ model1[i] = model[i];
+ if (model) delete[] model;
+ model = model1;
+ model[nModels] = mdl;
+ model[nModels]->SetMMDBManager ( PManager(this),nModels+1 );
+ model[nModels]->CheckInAtoms();
+ nModels++;
+ }
+
+ return nModels;
+
+ }
+
+ int CoorManager::InsModel ( PModel mdl, int modelNo ) {
+ AddModel ( mdl );
+ RotateModels ( modelNo,nModels,1 );
+ return nModels;
+ }
+
+ void CoorManager::RotateModels ( int modelNo1, int modelNo2,
+ int rotdir ) {
+ PModel mdl;
+ PPAtom A;
+ int m1,m2,i11,i12,i21,i22,nat,i,k;
+
+ m1 = IMax ( 0,modelNo1-1 );
+ m2 = IMin ( nModels,modelNo2) - 1;
+ if (m1>m2) ISwap ( m1,m2 );
+
+ if (m1!=m2) {
+
+ if (model[m1] && model[m2]) {
+ model[m1]->GetAIndexRange ( i11,i12 );
+ model[m2]->GetAIndexRange ( i21,i22 );
+ if ((i11<i12) && (i21<i22) && (i12<i22)) {
+ i11--; i12--;
+ i21--; i22--;
+ if (rotdir<0) {
+ // rotate anticlockwise
+ nat = i12-i11+1;
+ A = new PAtom[nat];
+ k = 0;
+ for (i=i11;i<=i12;i++)
+ A[k++] = atom[i];
+ k = i11;
+ for (i=i12+1;i<=i22;i++) {
+ atom[k] = atom[i];
+ if (atom[k]) atom[k]->index = k+1;
+ k++;
+ }
+ for (i=0;i<nat;i++) {
+ atom[k] = A[i];
+ if (atom[k]) atom[k]->index = k+1;
+ k++;
+ }
+ } else {
+ // rotate anticlockwise
+ nat = i22-i21+1;
+ A = new PAtom[nat];
+ k = 0;
+ for (i=i21;i<=i22;i++)
+ A[k++] = atom[i];
+ k = i22;
+ for (i=i21-1;i>=i11;i--) {
+ atom[k] = atom[i];
+ if (atom[k]) atom[k]->index = k+1;
+ k--;
+ }
+ for (i=nat-1;i>=0;i--) {
+ atom[k] = A[i];
+ if (atom[k]) atom[k]->index = k+1;
+ k--;
+ }
+ }
+ delete[] A;
+ }
+ }
+
+ if (rotdir<0) {
+ // rotate anticlockwise
+ mdl = model[m1];
+ for (i=m1;i<m2;i++) {
+ model[i] = model[i+1];
+ model[i]->serNum = i+1;
+ }
+ model[m2] = mdl;
+ model[m2]->serNum = m2+1;
+ } else {
+ // rotate clockwise
+ mdl = model[m2];
+ for (i=m2;i>m1;i--) {
+ model[i] = model[i-1];
+ model[i]->serNum = i+1;
+ }
+ model[m1] = mdl;
+ model[m1]->serNum = m1+1;
+ }
+
+ }
+
+ }
+
+
+ void CoorManager::SwapModels ( int modelNo1, int modelNo2 ) {
+ PModel mdl;
+ PPAtom A;
+ int m1,m2,i11,i12,i21,i22,i,k,n;
+
+ n = 0; // tp depress "uninitialized" warning
+
+ m1 = IMax ( 0,modelNo1-1 );
+ m2 = IMin ( nModels,modelNo2) - 1;
+ if (m1>m2) ISwap ( m1,m2 );
+
+ if (m1!=m2) {
+
+ if (model[m1])
+ model[m1]->GetAIndexRange ( i11,i12 );
+ else {
+ n = m1;
+ while ((!model[n]) && (n<m2)) n++;
+ if (n<m2) {
+ model[n]->GetAIndexRange ( i11,i12 );
+ i12 = i11-1;
+ } else
+ n = -1;
+ }
+
+ if (n>=0) {
+ if (model[m2])
+ model[m2]->GetAIndexRange ( i21,i22 );
+ else {
+ n = m2;
+ while ((!model[n]) && (m1<n)) n--;
+ if (m1<n) {
+ model[n]->GetAIndexRange ( i21,i22 );
+ i22 = i21-1;
+ } else
+ n = -1;
+ }
+ }
+
+ if (n>=0) {
+
+ i11--; i12--;
+ i21--; i22--;
+
+ A = new PAtom[atmLen];
+ k = 0;
+
+ for (i=0 ;i<i11 ;i++) A[k++] = atom[i];
+ for (i=i21 ;i<=i22 ;i++) A[k++] = atom[i];
+ for (i=i12+1 ;i<i21 ;i++) A[k++] = atom[i];
+ for (i=i11 ;i<=i12 ;i++) A[k++] = atom[i];
+
+ for (i=0 ;i<nAtoms;i++) if (A[i]) A[i]->index = i+1;
+ for (i=nAtoms;i<atmLen;i++) A[i] = NULL;
+
+ if (atom) delete[] atom;
+ atom = A;
+
+ }
+
+ mdl = model[m2];
+ model[m2] = model[m1];
+ model[m1] = mdl;
+
+ model[m1]->serNum = m1+1;
+ model[m2]->serNum = m2+1;
+
+ }
+
+ }
+
+
+ PChain CoorManager::GetChain ( int modelNo, const ChainID chainID ) {
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->GetChain ( chainID );
+ }
+ return NULL;
+ }
+
+ PChain CoorManager::GetChain ( int modelNo, int chainNo ) {
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->GetChain ( chainNo );
+ }
+ return NULL;
+ }
+
+ PChain CoorManager::GetChain ( cpstr CID ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID))) {
+ CoorIDCode = CID_WrongPath;
+ return NULL;
+ }
+ return GetChain ( modno,chname );
+
+ }
+
+ void CoorManager::GetChainTable ( int modelNo,
+ PPChain & chainTable,
+ int & NumberOfChains ) {
+ chainTable = NULL;
+ NumberOfChains = 0;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ chainTable = model[modelNo-1]->chain;
+ NumberOfChains = model[modelNo-1]->nChains;
+ }
+ }
+ }
+
+ void CoorManager::GetChainTable ( cpstr CID,
+ PPChain & chainTable,
+ int & NumberOfChains ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+
+ chainTable = NULL;
+ NumberOfChains = 0;
+ CoorIDCode = CID_Ok;
+
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & APATH_WC_ModelNo)) {
+ CoorIDCode = CID_WrongPath;
+ return;
+ }
+
+ if ((0<modno) && (modno<=nModels)) {
+ if (model[modno-1]) {
+ chainTable = model[modno-1]->chain;
+ NumberOfChains = model[modno-1]->nChains;
+ }
+ }
+ }
+
+
+ int CoorManager::DeleteChain ( int modelNo, const ChainID chID ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteChain ( chID );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteChain ( int modelNo, int chainNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteChain ( chainNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllChains ( int modelNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllChains();
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllChains() {
+ int i,k;
+ k = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) k += model[i]->DeleteAllChains();
+ return k;
+ }
+
+ int CoorManager::AddChain ( int modelNo, PChain chain ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->AddChain ( chain );
+ }
+ return 0;
+ }
+
+
+ PResidue CoorManager::GetResidue ( int modelNo,
+ const ChainID chainID,
+ int seqNo,
+ const InsCode insCode ) {
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->GetResidue ( chainID,seqNo,insCode );
+ }
+ return NULL;
+ }
+
+ PResidue CoorManager::GetResidue ( int modelNo, int chainNo,
+ int seqNo,
+ const InsCode insCode ) {
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->GetResidue ( chainNo,seqNo,insCode );
+ }
+ return NULL;
+ }
+
+ PResidue CoorManager::GetResidue ( int modelNo,
+ const ChainID chainID,
+ int resNo ) {
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->GetResidue ( chainID,resNo );
+ }
+ return NULL;
+ }
+
+ PResidue CoorManager::GetResidue ( int modelNo, int chainNo,
+ int resNo ) {
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->GetResidue ( chainNo,resNo );
+ }
+ return NULL;
+ }
+
+ PResidue CoorManager::GetResidue ( cpstr CID ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
+ APATH_WC_SeqNum | APATH_WC_InsCode))) {
+ CoorIDCode = CID_WrongPath;
+ return NULL;
+ }
+ return GetResidue ( modno,chname,sn,ic );
+
+ }
+
+
+ int CoorManager::GetResidueNo ( int modelNo,
+ const ChainID chainID,
+ int seqNo,
+ const InsCode insCode ) {
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->GetResidueNo ( chainID,seqNo,insCode );
+ }
+ return -3;
+ }
+
+ int CoorManager::GetResidueNo ( int modelNo, int chainNo,
+ int seqNo,
+ const InsCode insCode ) {
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->GetResidueNo ( chainNo,seqNo,insCode );
+ }
+ return -3;
+ }
+
+ void CoorManager::GetResidueTable ( PPResidue & resTable,
+ int & NumberOfResidues ) {
+ // resTable has to be NULL or it will be reallocated. The
+ // application is responsible for deallocating the resTable (but not
+ // of its residues!). This does not apply to other GetResidueTable
+ // functions.
+ PPChain chain;
+ PPResidue res;
+ int i,j,k,n,nChains,nResidues;
+
+ if (resTable) {
+ delete[] resTable;
+ resTable = NULL;
+ }
+
+ NumberOfResidues = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ model[i]->GetChainTable ( chain,nChains );
+ for (j=0;j<model[i]->nChains;j++)
+ if (chain[j]) {
+ chain[j]->GetResidueTable ( res,nResidues );
+ NumberOfResidues += nResidues;
+ }
+ }
+
+ if (NumberOfResidues>0) {
+ resTable = new PResidue[NumberOfResidues];
+ k = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ model[i]->GetChainTable ( chain,nChains );
+ for (j=0;j<model[i]->nChains;j++)
+ if (chain[j]) {
+ chain[j]->GetResidueTable ( res,nResidues );
+ for (n=0;n<nResidues;n++)
+ if (res[n]) resTable[k++] = res[n];
+ }
+ }
+ NumberOfResidues = k;
+ }
+
+ }
+
+ void CoorManager::GetResidueTable ( int modelNo,
+ const ChainID chainID,
+ PPResidue & resTable,
+ int & NumberOfResidues ) {
+ PChain chain;
+ resTable = NULL;
+ NumberOfResidues = 0;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ chain = model[modelNo-1]->GetChain ( chainID );
+ if (chain) {
+ resTable = chain->residue;
+ NumberOfResidues = chain->nResidues;
+ }
+ }
+ }
+ }
+
+ void CoorManager::GetResidueTable ( int modelNo, int chainNo,
+ PPResidue & resTable,
+ int & NumberOfResidues ) {
+ PChain chain;
+ resTable = NULL;
+ NumberOfResidues = 0;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ chain = model[modelNo-1]->GetChain ( chainNo );
+ if (chain) {
+ resTable = chain->residue;
+ NumberOfResidues = chain->nResidues;
+ }
+ }
+ }
+ }
+
+ void CoorManager::GetResidueTable ( cpstr CID,
+ PPResidue & resTable,
+ int & NumberOfResidues ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+ PChain chain;
+
+ resTable = NULL;
+ NumberOfResidues = 0;
+ CoorIDCode = CID_Ok;
+
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID))) {
+ CoorIDCode = CID_WrongPath;
+ return;
+ }
+
+ if ((0<modno) && (modno<=nModels)) {
+ if (model[modno-1]) {
+ chain = model[modno-1]->GetChain ( chname );
+ if (chain) {
+ resTable = chain->residue;
+ NumberOfResidues = chain->nResidues;
+ }
+ }
+ }
+
+ }
+
+
+ int CoorManager::DeleteResidue ( int modelNo,
+ const ChainID chainID,
+ int seqNo,
+ const InsCode insCode ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteResidue ( chainID,seqNo,insCode );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteResidue ( int modelNo,
+ const ChainID chainID,
+ int resNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteResidue ( chainID,resNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteResidue ( int modelNo, int chainNo,
+ int seqNo,
+ const InsCode insCode ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteResidue ( chainNo,seqNo,insCode );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteResidue ( int modelNo, int chainNo,
+ int resNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteResidue ( chainNo,resNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllResidues ( int modelNo,
+ const ChainID chainID ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllResidues ( chainID );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllResidues ( int modelNo, int chainNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllResidues ( chainNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllResidues ( int modelNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllResidues();
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllResidues() {
+ int i,k;
+ k = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) k += model[i]->DeleteAllResidues();
+ return k;
+ }
+
+ int CoorManager::AddResidue ( int modelNo, const ChainID chainID,
+ PResidue res ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->AddResidue ( chainID,res );
+ }
+ return 0;
+ }
+
+ int CoorManager::AddResidue ( int modelNo, int chainNo,
+ PResidue res ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->AddResidue ( chainNo,res );
+ }
+ return 0;
+ }
+
+
+
+ int CoorManager::GetNumberOfChains ( int modelNo ) {
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->nChains;
+ }
+ return 0;
+ }
+
+ int CoorManager::GetNumberOfChains ( cpstr CID ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & APATH_WC_ModelNo)) {
+ CoorIDCode = CID_WrongPath;
+ return 0;
+ }
+
+ if ((0<modno) && (modno<=nModels)) {
+ if (model[modno-1])
+ return model[modno-1]->nChains;
+ }
+
+ return 0;
+
+ }
+
+ int CoorManager::GetNumberOfResidues ( int modelNo,
+ const ChainID chainID ) {
+ PChain chain;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ chain = model[modelNo-1]->GetChain ( chainID );
+ if (chain) return chain->nResidues;
+ }
+ }
+ return 0;
+ }
+
+ int CoorManager::GetNumberOfResidues ( int modelNo, int chainNo ) {
+ PChain chain;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ if ((0<=chainNo) && (chainNo<model[modelNo-1]->nChains)) {
+ chain = model[modelNo-1]->chain[chainNo];
+ if (chain) return chain->nResidues;
+ }
+ }
+ }
+ return 0;
+ }
+
+ int CoorManager::GetNumberOfResidues ( cpstr CID ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+ PChain chain;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID))) {
+ CoorIDCode = CID_WrongPath;
+ return 0;
+ }
+
+ if ((0<modno) && (modno<=nModels)) {
+ if (model[modno-1]) {
+ chain = model[modno-1]->GetChain ( chname );
+ if (chain) return chain->nResidues;
+ }
+ }
+
+ return 0;
+
+ }
+
+
+ int CoorManager::GetNumberOfAtoms ( int modelNo,
+ const ChainID chainID,
+ int seqNo,
+ const InsCode insCode ) {
+ PChain chain;
+ PResidue res;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ chain = model[modelNo-1]->GetChain ( chainID );
+ if (chain) {
+ res = chain->GetResidue ( seqNo,insCode );
+ if (res) return res->nAtoms;
+ }
+ }
+ }
+ return 0;
+ }
+
+ int CoorManager::GetNumberOfAtoms ( int modelNo, int chainNo,
+ int seqNo,
+ const InsCode insCode ) {
+ PChain chain;
+ PResidue res;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ if ((0<=chainNo) && (chainNo<model[modelNo-1]->nChains)) {
+ chain = model[modelNo-1]->chain[chainNo];
+ if (chain) {
+ res = chain->GetResidue ( seqNo,insCode );
+ if (res) return res->nAtoms;
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+ int CoorManager::GetNumberOfAtoms ( int modelNo,
+ const ChainID chainID,
+ int resNo ) {
+ PChain chain;
+ PResidue res;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ chain = model[modelNo-1]->GetChain ( chainID );
+ if (chain) {
+ if ((0<=resNo) && (resNo<chain->nResidues)) {
+ res = chain->residue[resNo];
+ if (res) return res->nAtoms;
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+ int CoorManager::GetNumberOfAtoms ( int modelNo, int chainNo,
+ int resNo ) {
+ PChain chain;
+ PResidue res;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ if ((0<=chainNo) && (chainNo<model[modelNo-1]->nChains)) {
+ chain = model[modelNo-1]->chain[chainNo];
+ if (chain) {
+ if ((0<=resNo) && (resNo<chain->nResidues)) {
+ res = chain->residue[resNo];
+ if (res) return res->nAtoms;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+ int CoorManager::GetNumberOfAtoms ( cpstr CID ) {
+ // returns number of atoms in residues identified by CID
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+ PChain chain;
+ PResidue res;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
+ APATH_WC_SeqNum | APATH_WC_InsCode))) {
+ CoorIDCode = CID_WrongPath;
+ return 0;
+ }
+
+ if ((0<modno) && (modno<=nModels)) {
+ if (model[modno-1]) {
+ chain = model[modno-1]->GetChain ( chname );
+ if (chain) {
+ res = chain->GetResidue ( sn,ic );
+ if (res) return res->nAtoms;
+ }
+ }
+ }
+
+ return 0;
+
+ }
+
+
+ // -------------------- Extracting atoms -----------------------
+
+ PAtom CoorManager::GetAtom (
+ int modelNo, // model serial number 1...
+ const ChainID chID, // chain ID
+ int seqNo, // residue sequence number
+ const InsCode insCode, // residue insertion code
+ const AtomName aname, // atom name
+ const Element elmnt, // chemical element code or '*'
+ const AltLoc aloc // alternate location indicator
+ ) {
+ PModel mdl;
+ PChain chn;
+ PResidue res;
+ PAtom atm;
+
+ if ((1<=modelNo) && (modelNo<=nModels))
+ mdl = model[modelNo-1];
+ else mdl = NULL;
+ if (!mdl) {
+ CoorIDCode = CID_NoModel;
+ return NULL;
+ }
+
+ chn = mdl->GetChain ( chID );
+ if (!chn) {
+ CoorIDCode = CID_NoChain;
+ return NULL;
+ }
+
+ res = chn->GetResidue ( seqNo,insCode );
+ if (!res) {
+ CoorIDCode = CID_NoResidue;
+ return NULL;
+ }
+
+ atm = res->GetAtom ( aname,elmnt,aloc );
+ if (!atm) CoorIDCode = CID_NoAtom;
+ else CoorIDCode = CID_Ok;
+
+ return atm;
+
+ }
+
+ PAtom CoorManager::GetAtom (
+ int modelNo, // model serial number 1...
+ const ChainID chID, // chain ID
+ int seqNo, // residue sequence number
+ const InsCode insCode, // residue insertion code
+ int atomNo // atom number 0..
+ ) {
+ PModel mdl;
+ PChain chn;
+ PResidue res;
+ PAtom atm;
+
+ if ((1<=modelNo) && (modelNo<=nModels))
+ mdl = model[modelNo-1];
+ else mdl = NULL;
+ if (!mdl) {
+ CoorIDCode = CID_NoModel;
+ return NULL;
+ }
+
+ chn = mdl->GetChain ( chID );
+ if (!chn) {
+ CoorIDCode = CID_NoChain;
+ return NULL;
+ }
+
+ res = chn->GetResidue ( seqNo,insCode );
+ if (!res) {
+ CoorIDCode = CID_NoResidue;
+ return NULL;
+ }
+
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ atm = res->atom[atomNo];
+ else atm = NULL;
+ if (!atm) CoorIDCode = CID_NoAtom;
+ else CoorIDCode = CID_Ok;
+
+ return atm;
+
+ }
+
+ PAtom CoorManager::GetAtom (
+ int modelNo, // model serial number 1...
+ const ChainID chID, // chain ID
+ int resNo, // residue number 0..
+ const AtomName aname, // atom name
+ const Element elmnt, // chemical element code or '*'
+ const AltLoc aloc // alternate location indicator
+ ) {
+ PModel mdl;
+ PChain chn;
+ PResidue res;
+ PAtom atm;
+
+ if ((1<=modelNo) && (modelNo<=nModels))
+ mdl = model[modelNo-1];
+ else mdl = NULL;
+ if (!mdl) {
+ CoorIDCode = CID_NoModel;
+ return NULL;
+ }
+
+ chn = mdl->GetChain ( chID );
+ if (!chn) {
+ CoorIDCode = CID_NoChain;
+ return NULL;
+ }
+
+ if ((0<=resNo) && (resNo<chn->nResidues))
+ res = chn->residue[resNo];
+ else res = NULL;
+ if (!res) {
+ CoorIDCode = CID_NoResidue;
+ return NULL;
+ }
+
+ atm = res->GetAtom ( aname,elmnt,aloc );
+ if (!atm) CoorIDCode = CID_NoAtom;
+ else CoorIDCode = CID_Ok;
+
+ return atm;
+
+ }
+
+ PAtom CoorManager::GetAtom (
+ int modelNo, // model serial number 1...
+ const ChainID chID, // chain ID
+ int resNo, // residue number 0..
+ int atomNo // atom number 0..
+ ) {
+ PModel mdl;
+ PChain chn;
+ PResidue res;
+ PAtom atm;
+
+ if ((1<=modelNo) && (modelNo<=nModels))
+ mdl = model[modelNo-1];
+ else mdl = NULL;
+ if (!mdl) {
+ CoorIDCode = CID_NoModel;
+ return NULL;
+ }
+
+ chn = mdl->GetChain ( chID );
+ if (!chn) {
+ CoorIDCode = CID_NoChain;
+ return NULL;
+ }
+
+ if ((0<=resNo) && (resNo<chn->nResidues))
+ res = chn->residue[resNo];
+ else res = NULL;
+ if (!res) {
+ CoorIDCode = CID_NoResidue;
+ return NULL;
+ }
+
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ atm = res->atom[atomNo];
+ else atm = NULL;
+ if (!atm) CoorIDCode = CID_NoAtom;
+ else CoorIDCode = CID_Ok;
+
+ return atm;
+
+ }
+
+ PAtom CoorManager::GetAtom (
+ int modelNo, // model serial number 1...
+ int chNo, // chain number 0..
+ int seqNo, // residue sequence number
+ const InsCode insCode, // residue insertion code
+ const AtomName aname, // atom name
+ const Element elmnt, // chemical element code or '*'
+ const AltLoc aloc // alternate location indicator
+ ) {
+ PModel mdl;
+ PChain chn;
+ PResidue res;
+ PAtom atm;
+
+ if ((1<=modelNo) && (modelNo<=nModels))
+ mdl = model[modelNo-1];
+ else mdl = NULL;
+ if (!mdl) {
+ CoorIDCode = CID_NoModel;
+ return NULL;
+ }
+
+ if ((0<=chNo) && (chNo<mdl->nChains))
+ chn = mdl->chain[chNo];
+ else chn = NULL;
+ if (!chn) {
+ CoorIDCode = CID_NoChain;
+ return NULL;
+ }
+
+ res = chn->GetResidue ( seqNo,insCode );
+ if (!res) {
+ CoorIDCode = CID_NoResidue;
+ return NULL;
+ }
+
+ atm = res->GetAtom ( aname,elmnt,aloc );
+ if (!atm) CoorIDCode = CID_NoAtom;
+ else CoorIDCode = CID_Ok;
+
+ return atm;
+
+ }
+
+ PAtom CoorManager::GetAtom (
+ int modelNo, // model serial number 1...
+ int chNo, // chain number 0...
+ int seqNo, // residue sequence number
+ const InsCode insCode, // residue insertion code
+ int atomNo // atom number 0...
+ ) {
+ PModel mdl;
+ PChain chn;
+ PResidue res;
+ PAtom atm;
+
+ if ((1<=modelNo) && (modelNo<=nModels))
+ mdl = model[modelNo-1];
+ else mdl = NULL;
+ if (!mdl) {
+ CoorIDCode = CID_NoModel;
+ return NULL;
+ }
+
+ if ((0<=chNo) && (chNo<mdl->nChains))
+ chn = mdl->chain[chNo];
+ else chn = NULL;
+ if (!chn) {
+ CoorIDCode = CID_NoChain;
+ return NULL;
+ }
+
+ res = chn->GetResidue ( seqNo,insCode );
+ if (!res) {
+ CoorIDCode = CID_NoResidue;
+ return NULL;
+ }
+
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ atm = res->atom[atomNo];
+ else atm = NULL;
+ if (!atm) CoorIDCode = CID_NoAtom;
+ else CoorIDCode = CID_Ok;
+
+ return atm;
+
+ }
+
+ PAtom CoorManager::GetAtom (
+ int modelNo, // model serial number 1...
+ int chNo, // chain number 0...
+ int resNo, // residue number 0...
+ const AtomName aname, // atom name
+ const Element elmnt, // chemical element code or '*'
+ const AltLoc aloc // alternate location indicator
+ ) {
+ PModel mdl;
+ PChain chn;
+ PResidue res;
+ PAtom atm;
+
+ if ((1<=modelNo) && (modelNo<=nModels))
+ mdl = model[modelNo-1];
+ else mdl = NULL;
+ if (!mdl) {
+ CoorIDCode = CID_NoModel;
+ return NULL;
+ }
+
+ if ((0<=chNo) && (chNo<mdl->nChains))
+ chn = mdl->chain[chNo];
+ else chn = NULL;
+ if (!chn) {
+ CoorIDCode = CID_NoChain;
+ return NULL;
+ }
+
+ if ((0<=resNo) && (resNo<chn->nResidues))
+ res = chn->residue[resNo];
+ else res = NULL;
+ if (!res) {
+ CoorIDCode = CID_NoResidue;
+ return NULL;
+ }
+
+ atm = res->GetAtom ( aname,elmnt,aloc );
+ if (!atm) CoorIDCode = CID_NoAtom;
+ else CoorIDCode = CID_Ok;
+
+ return atm;
+
+ }
+
+ PAtom CoorManager::GetAtom (
+ int modelNo, // model serial number 1...
+ int chNo, // chain number 0...
+ int resNo, // residue number 0...
+ int atomNo // atom number 0...
+ ) {
+ PModel mdl;
+ PChain chn;
+ PResidue res;
+ PAtom atm;
+
+ if ((1<=modelNo) && (modelNo<=nModels))
+ mdl = model[modelNo-1];
+ else mdl = NULL;
+ if (!mdl) {
+ CoorIDCode = CID_NoModel;
+ return NULL;
+ }
+
+ if ((0<=chNo) && (chNo<mdl->nChains))
+ chn = mdl->chain[chNo];
+ else chn = NULL;
+ if (!chn) {
+ CoorIDCode = CID_NoChain;
+ return NULL;
+ }
+
+ if ((0<=resNo) && (resNo<chn->nResidues))
+ res = chn->residue[resNo];
+ else res = NULL;
+ if (!res) {
+ CoorIDCode = CID_NoResidue;
+ return NULL;
+ }
+
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ atm = res->atom[atomNo];
+ else atm = NULL;
+ if (!atm) CoorIDCode = CID_NoAtom;
+ else CoorIDCode = CID_Ok;
+
+ return atm;
+
+ }
+
+
+ PAtom CoorManager::GetAtom ( cpstr CID ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & APATH_Incomplete)) {
+ CoorIDCode = CID_WrongPath;
+ return NULL;
+ }
+
+ return GetAtom ( modno,chname,sn,ic,aname,elname,aloc );
+
+ }
+
+
+ void CoorManager::GetAtomTable ( PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ atomTable = atom;
+ NumberOfAtoms = nAtoms;
+ }
+
+ void CoorManager::GetAtomTable ( int modelNo,
+ const ChainID chainID,
+ int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ res = model[modelNo-1]->GetResidue ( chainID,seqNo,insCode );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+ }
+ }
+
+ void CoorManager::GetAtomTable ( int modelNo,
+ int chainNo,
+ int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ res = model[modelNo-1]->GetResidue ( chainNo,seqNo,insCode );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+ }
+ }
+
+ void CoorManager::GetAtomTable ( int modelNo,
+ const ChainID chainID,
+ int resNo,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ res = model[modelNo-1]->GetResidue ( chainID,resNo );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+ }
+ }
+
+ void CoorManager::GetAtomTable ( int modelNo, int chainNo,
+ int resNo, PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1]) {
+ res = model[modelNo-1]->GetResidue ( chainNo,resNo );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+ }
+ }
+
+ void CoorManager::GetAtomTable ( cpstr CID,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+ PResidue res;
+
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
+ APATH_WC_SeqNum | APATH_WC_InsCode))) {
+ CoorIDCode = CID_WrongPath;
+ return;
+ }
+
+ res = GetResidue ( modno,chname,sn,ic );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+
+ }
+
+
+ void CoorManager::GetAtomTable1 ( PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ int i,j;
+ if (atomTable) delete[] atomTable;
+ if (nAtoms>0) {
+ atomTable = new PAtom[nAtoms];
+ j = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter)
+ atomTable[j++] = atom[i];
+ }
+ NumberOfAtoms = j;
+ } else {
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void CoorManager::GetAtomTable1 ( int modelNo,
+ const ChainID chainID,
+ int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ res = NULL;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ res = model[modelNo-1]->GetResidue ( chainID,seqNo,insCode );
+ }
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void CoorManager::GetAtomTable1 ( int modelNo,
+ int chainNo,
+ int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ res = NULL;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ res = model[modelNo-1]->GetResidue ( chainNo,seqNo,insCode );
+ }
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void CoorManager::GetAtomTable1 ( int modelNo,
+ const ChainID chainID,
+ int resNo,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ res = NULL;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ res = model[modelNo-1]->GetResidue ( chainID,resNo );
+ }
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void CoorManager::GetAtomTable1 ( int modelNo, int chainNo,
+ int resNo,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ res = NULL;
+ if ((0<modelNo) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ res = model[modelNo-1]->GetResidue ( chainNo,resNo );
+ }
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void CoorManager::GetAtomTable1 ( cpstr CID, PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ int modno,sn,rc;
+ ChainID chname;
+ InsCode ic;
+ ResName resname;
+ AtomName aname;
+ Element elname;
+ AltLoc aloc;
+ PResidue res;
+
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+
+ CoorIDCode = CID_Ok;
+ rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+ aname,elname,aloc,&DefPath );
+ if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
+ APATH_WC_SeqNum | APATH_WC_InsCode))) {
+ CoorIDCode = CID_WrongPath;
+ return;
+ }
+
+ res = GetResidue ( modno,chname,sn,ic );
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+
+ }
+
+
+
+ int CoorManager::DeleteAtom ( int modelNo,
+ const ChainID chID,
+ int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAtom ( chID,seqNo,insCode,
+ aname,elmnt,aloc );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAtom ( int modelNo,
+ const ChainID chID,
+ int seqNo,
+ const InsCode insCode,
+ int atomNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAtom ( chID,seqNo,insCode,atomNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAtom ( int modelNo,
+ const ChainID chID,
+ int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAtom ( chID,resNo,
+ aname,elmnt,aloc );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAtom ( int modelNo,
+ const ChainID chID,
+ int resNo,
+ int atomNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAtom ( chID,resNo,atomNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAtom ( int modelNo, int chNo, int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAtom ( chNo,seqNo,insCode,
+ aname,elmnt,aloc );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAtom ( int modelNo, int chNo, int seqNo,
+ const InsCode insCode, int atomNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAtom ( chNo,seqNo,insCode,atomNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAtom ( int modelNo, int chNo, int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAtom ( chNo,resNo,
+ aname,elmnt,aloc );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAtom ( int modelNo, int chNo, int resNo,
+ int atomNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAtom ( chNo,resNo,atomNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllAtoms ( int modelNo,
+ const ChainID chID,
+ int seqNo,
+ const InsCode insCode ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllAtoms ( chID,seqNo,insCode );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllAtoms ( int modelNo, const ChainID chID,
+ int resNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllAtoms ( chID,resNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllAtoms ( int modelNo, const ChainID chID ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllAtoms ( chID );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllAtoms ( int modelNo, int chNo, int seqNo,
+ const InsCode insCode ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllAtoms ( chNo,seqNo,insCode );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllAtoms ( int modelNo, int chNo,
+ int resNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllAtoms ( chNo,resNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllAtoms ( int modelNo, int chNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllAtoms ( chNo );
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllAtoms ( int modelNo ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->DeleteAllAtoms();
+ }
+ return 0;
+ }
+
+ int CoorManager::DeleteAllAtoms() {
+ int i,k;
+ k = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) k += model[i]->DeleteAllAtoms();
+ return k;
+ }
+
+
+ /*
+ int CoorManager::DeleteAltLocs() {
+ // This function leaves only alternative location with maximal
+ // occupancy, if those are equal or unspecified, the one with
+ // "least" alternative location indicator.
+ // The function returns the number of deleted atoms and optimizes
+ // the atom index.
+ ChainID chID;
+ ResName rName;
+ InsCode iCode;
+ AtomName aname;
+ AltLoc aLoc,aL;
+ realtype occupancy,occ;
+ int seqNum;
+ int i,j,k,i1,i2,n;
+
+ k = 0;
+ n = 0;
+ i = 0;
+ while (i<nAtoms) {
+
+ if (atom[i]) {
+ seqNum = atom[i]->GetSeqNum ();
+ occupancy = atom[i]->GetOccupancy();
+ strcpy ( chID ,atom[i]->GetChainID() );
+ strcpy ( rName,atom[i]->GetResName() );
+ strcpy ( iCode,atom[i]->GetInsCode() );
+ strcpy ( aname,atom[i]->name );
+ strcpy ( aLoc ,atom[i]->altLoc );
+ j = i+1;
+ i1 = -1;
+ i2 = i;
+ while (j<nAtoms)
+ if (atom[j]) {
+ if ((atom[j]->GetSeqNum()==seqNum) &&
+ (!strcmp(atom[j]->name,aname)) &&
+ (!strcmp(atom[j]->GetInsCode(),iCode)) &&
+ (!strcmp(atom[j]->GetResName(),rName)) &&
+ (!strcmp(atom[j]->GetChainID(),chID ))) {
+ occ = atom[j]->GetOccupancy();
+ if (occ>occupancy) {
+ occupancy = occ;
+ i1 = j;
+ }
+ if (aLoc[0]) {
+ strcpy ( aL,atom[j]->altLoc );
+ if (!aL[0]) {
+ aLoc[0] = char(0);
+ i2 = j;
+ } else if (strcmp(aL,aLoc)<0) {
+ strcpy ( aLoc,aL );
+ i2 = j;
+ }
+ }
+ j++;
+ } else
+ break;
+ } else
+ j++;
+ if (i1<0) {
+ if (atom[i]->WhatIsSet & ASET_Occupancy) i1 = i;
+ else i1 = i2;
+ }
+ while (i<j) {
+ if (atom[i]) {
+ if (i!=i1) {
+ delete atom[i];
+ atom[i] = NULL;
+ n++;
+ } else {
+ if (k<i) {
+ atom[k] = atom[i];
+ atom[k]->index = k+1;
+ }
+ k++;
+ }
+ }
+ i++;
+ }
+
+ } else
+ i++;
+
+ }
+
+ nAtoms = k;
+ return n;
+
+ }
+ */
+
+ int CoorManager::DeleteAltLocs() {
+ // This function leaves only alternative location with maximal
+ // occupancy, if those are equal or unspecified, the one with
+ // "least" alternative location indicator.
+ // The function returns the number of deleted atoms. All tables
+ // remain untrimmed, so that explicit trimming or calling
+ // FinishStructEdit() at some point is required.
+ int i,n;
+
+ n = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) n += model[i]->DeleteAltLocs();
+
+ return n;
+
+ }
+
+ int CoorManager::AddAtom ( int modelNo,
+ const ChainID chID,
+ int seqNo,
+ const InsCode insCode,
+ PAtom atom ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->AddAtom ( chID,seqNo,insCode,atom );
+ }
+ return 0;
+ }
+
+ int CoorManager::AddAtom ( int modelNo, const ChainID chID,
+ int resNo, PAtom atom ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->AddAtom ( chID,resNo,atom );
+ }
+ return 0;
+ }
+
+ int CoorManager::AddAtom ( int modelNo, int chNo,
+ int seqNo, const InsCode insCode,
+ PAtom atom ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->AddAtom ( chNo,seqNo,insCode,atom );
+ }
+ return 0;
+ }
+
+ int CoorManager::AddAtom ( int modelNo, int chNo,
+ int resNo, PAtom atom ) {
+ if ((modelNo>0) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->AddAtom ( chNo,resNo,atom );
+ }
+ return 0;
+ }
+
+
+ void CoorManager::RemoveBricks() {
+ int i,j,k;
+ if (brick) {
+ for (i=0;i<nbrick_x;i++)
+ if (brick[i]) {
+ for (j=0;j<nbrick_y;j++)
+ if (brick[i][j]) {
+ for (k=0;k<nbrick_z;k++)
+ if (brick[i][j][k]) delete brick[i][j][k];
+ delete[] brick[i][j];
+ }
+ delete[] brick[i];
+ }
+ delete[] brick;
+ }
+ brick = NULL;
+ nbrick_x = 0;
+ nbrick_y = 0;
+ nbrick_z = 0;
+ }
+
+ void CoorManager::GetBrickCoor ( PAtom A,
+ int & nx, int & ny, int & nz ) {
+ nx = (int)floor((A->x-xbrick_0)/brick_size);
+ ny = (int)floor((A->y-ybrick_0)/brick_size);
+ nz = (int)floor((A->z-zbrick_0)/brick_size);
+ if ((ny<0) || (nz<0) || (nx>=nbrick_x) ||
+ (ny>=nbrick_y) || (nz>=nbrick_z)) nx = -1;
+ }
+
+ void CoorManager::GetBrickCoor ( realtype x, realtype y,
+ realtype z, int & nx,
+ int & ny, int & nz ) {
+ nx = (int)floor((x-xbrick_0)/brick_size);
+ ny = (int)floor((y-ybrick_0)/brick_size);
+ nz = (int)floor((z-zbrick_0)/brick_size);
+ if ((ny<0) || (nz<0) || (nx>=nbrick_x) ||
+ (ny>=nbrick_y) || (nz>=nbrick_z)) nx = -1;
+ }
+
+ void CoorManager::GetBrickDimension (
+ int & nxmax, int & nymax, int & nzmax ) {
+ if (!brick) {
+ nxmax = 0; nymax = 0; nzmax = 0;
+ } else {
+ nxmax = nbrick_x;
+ nymax = nbrick_y;
+ nzmax = nbrick_z;
+ }
+ }
+
+ PBrick CoorManager::GetBrick ( int nx, int ny, int nz ) {
+ if (!brick) return NULL;
+ if ((nx>=0) && (nx<nbrick_x) &&
+ (ny>=0) && (ny<nbrick_y) &&
+ (nz>=0) && (nz<nbrick_z)) {
+ if (!brick[nx]) return NULL;
+ if (!brick[nx][ny]) return NULL;
+ return brick[nx][ny][nz];
+ }
+ return NULL;
+ }
+
+ void CoorManager::MakeBricks ( PPAtom atmvec, int avlen,
+ realtype Margin,
+ realtype BrickSize ) {
+ // Makes bricking for atoms contained in vector atmvec of length
+ // avlen, with brick size BrickSize (in angstroms). The previous
+ // bricking, if there was any, is removed.
+ int i,j, nx,ny,nz, alen;
+ realtype x1,x2, y1,y2, z1,z2, dx,dy,dz;
+ PPAtom A;
+
+ RemoveBricks();
+
+ brick_size = BrickSize;
+
+ if (atmvec) {
+ A = atmvec;
+ alen = avlen;
+ } else {
+ A = atom;
+ alen = nAtoms;
+ }
+
+ if (alen>0) {
+ // find the range of coordinates
+ x1 = MaxReal;
+ x2 = -x1;
+ y1 = MaxReal;
+ y2 = -y1;
+ z1 = MaxReal;
+ z2 = -z1;
+ for (i=0;i<alen;i++)
+ if (A[i]) {
+ if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates)) {
+ if (A[i]->x<x1) x1 = A[i]->x;
+ if (A[i]->x>x2) x2 = A[i]->x;
+ if (A[i]->y<y1) y1 = A[i]->y;
+ if (A[i]->y>y2) y2 = A[i]->y;
+ if (A[i]->z<z1) z1 = A[i]->z;
+ if (A[i]->z>z2) z2 = A[i]->z;
+ }
+ }
+ if (x1<MaxReal) {
+ x1 -= Margin; x2 += Margin;
+ y1 -= Margin; y2 += Margin;
+ z1 -= Margin; z2 += Margin;
+ dx = x2-x1; nbrick_x = mround(dx/brick_size+0.0001)+1;
+ dy = y2-y1; nbrick_y = mround(dy/brick_size+0.0001)+1;
+ dz = z2-z1; nbrick_z = mround(dz/brick_size+0.0001)+1;
+ xbrick_0 = x1 - (nbrick_x*brick_size-dx)/2.0;
+ ybrick_0 = y1 - (nbrick_y*brick_size-dy)/2.0;
+ zbrick_0 = z1 - (nbrick_z*brick_size-dz)/2.0;
+ for (i=0;i<alen;i++)
+ if (A[i]) {
+ if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates)) {
+ GetBrickCoor ( A[i],nx,ny,nz );
+ if (nx>=0) {
+ if (!brick) {
+ brick = new PPPBrick[nbrick_x];
+ for (j=0;j<nbrick_x;j++)
+ brick[j] = NULL;
+ }
+ if (!brick[nx]) {
+ brick[nx] = new PPBrick[nbrick_y];
+ for (j=0;j<nbrick_y;j++)
+ brick[nx][j] = NULL;
+ }
+ if (!brick[nx][ny]) {
+ brick[nx][ny] = new PBrick[nbrick_z];
+ for (j=0;j<nbrick_z;j++)
+ brick[nx][ny][j] = NULL;
+ }
+ if (!brick[nx][ny][nz])
+ brick[nx][ny][nz] = new Brick();
+ brick[nx][ny][nz]->AddAtom ( A[i],i );
+ } else
+ printf ( " error in "
+ "CoorManager::MakeBricks!!!\n" );
+ }
+ }
+ }
+ }
+
+ }
+
+
+ void CoorManager::RemoveMBricks() {
+ int i,j,k;
+ if (mbrick) {
+ for (i=0;i<nmbrick_x;i++)
+ if (mbrick[i]) {
+ for (j=0;j<nmbrick_y;j++)
+ if (mbrick[i][j]) {
+ for (k=0;k<nmbrick_z;k++)
+ if (mbrick[i][j][k]) delete mbrick[i][j][k];
+ delete[] mbrick[i][j];
+ }
+ delete[] mbrick[i];
+ }
+ delete[] mbrick;
+ }
+ mbrick = NULL;
+ nmbrick_x = 0;
+ nmbrick_y = 0;
+ nmbrick_z = 0;
+ }
+
+ void CoorManager::GetMBrickCoor ( PAtom A,
+ int & nx, int & ny, int & nz ) {
+ nx = (int)floor((A->x-xmbrick_0)/mbrick_size);
+ ny = (int)floor((A->y-ymbrick_0)/mbrick_size);
+ nz = (int)floor((A->z-zmbrick_0)/mbrick_size);
+ if ((ny<0) || (nz<0) || (nx>=nmbrick_x) ||
+ (ny>=nmbrick_y) || (nz>=nmbrick_z)) nx = -nx-1;
+ }
+
+ void CoorManager::GetMBrickCoor (
+ realtype x, realtype y, realtype z,
+ int & nx, int & ny, int & nz ) {
+ nx = (int)floor((x-xmbrick_0)/mbrick_size);
+ ny = (int)floor((y-ymbrick_0)/mbrick_size);
+ nz = (int)floor((z-zmbrick_0)/mbrick_size);
+ if ((ny<0) || (nz<0) || (nx>=nmbrick_x) ||
+ (ny>=nmbrick_y) || (nz>=nmbrick_z)) nx = -nx-1;
+ }
+
+ void CoorManager::GetMBrickDimension (
+ int & nxmax, int & nymax, int & nzmax ) {
+ if (!brick) {
+ nxmax = 0; nymax = 0; nzmax = 0;
+ } else {
+ nxmax = nmbrick_x;
+ nymax = nmbrick_y;
+ nzmax = nmbrick_z;
+ }
+ }
+
+ PMBrick CoorManager::GetMBrick ( int nx, int ny, int nz ) {
+ if (!mbrick) return NULL;
+ if ((nx>=0) && (nx<nmbrick_x) &&
+ (ny>=0) && (ny<nmbrick_y) &&
+ (nz>=0) && (nz<nmbrick_z)) {
+ if (!mbrick[nx]) return NULL;
+ if (!mbrick[nx][ny]) return NULL;
+ return mbrick[nx][ny][nz];
+ }
+ return NULL;
+ }
+
+ void CoorManager::MakeMBricks ( PPAtom * atmvec, ivector avlen,
+ int nStructures, realtype Margin,
+ realtype BrickSize ) {
+ // Makes bricking for atoms contained in vectors atmvec with lengths
+ // given in avlen, with brick size BrickSize (in angstroms).
+ // The previous bricking, if there was any, is removed.
+ int i,j,k, nx,ny,nz;
+ realtype x1,x2, y1,y2, z1,z2, dx,dy,dz;
+ PAtom A;
+
+ RemoveMBricks();
+
+ mbrick_size = BrickSize;
+
+ // find the range of coordinates
+ x1 = MaxReal;
+ x2 = -x1;
+ y1 = MaxReal;
+ y2 = -y1;
+ z1 = MaxReal;
+ z2 = -z1;
+ for (i=0;i<nStructures;i++)
+ for (j=0;j<avlen[i];j++) {
+ A = atmvec[i][j];
+ if (A) {
+ if ((!A->Ter) && (A->WhatIsSet & ASET_Coordinates)) {
+ if (A->x<x1) x1 = A->x;
+ if (A->x>x2) x2 = A->x;
+ if (A->y<y1) y1 = A->y;
+ if (A->y>y2) y2 = A->y;
+ if (A->z<z1) z1 = A->z;
+ if (A->z>z2) z2 = A->z;
+ }
+ }
+ }
+ if (x1<MaxReal) {
+ x1 -= Margin; x2 += Margin;
+ y1 -= Margin; y2 += Margin;
+ z1 -= Margin; z2 += Margin;
+ dx = x2-x1; nmbrick_x = mround(dx/mbrick_size+0.0001)+1;
+ dy = y2-y1; nmbrick_y = mround(dy/mbrick_size+0.0001)+1;
+ dz = z2-z1; nmbrick_z = mround(dz/mbrick_size+0.0001)+1;
+ xmbrick_0 = x1 - (nmbrick_x*mbrick_size-dx)/2.0;
+ ymbrick_0 = y1 - (nmbrick_y*mbrick_size-dy)/2.0;
+ zmbrick_0 = z1 - (nmbrick_z*mbrick_size-dz)/2.0;
+ /*
+ mbrick = new PPPMBrick[nmbrick_x];
+ for (i=0;i<nmbrick_x;i++) {
+ mbrick[i] = new PPMBrick[nmbrick_y];
+ for (j=0;j<nmbrick_y;j++) {
+ mbrick[i][j] = new PMBrick[nmbrick_z];
+ for (k=0;k<nmbrick_z;k++)
+ mbrick[i][j][k] = new mbrick(nStructures);
+ }
+ }
+ */
+ for (i=0;i<nStructures;i++)
+ for (j=0;j<avlen[i];j++) {
+ A = atmvec[i][j];
+ if (A) {
+ if ((!A->Ter) && (A->WhatIsSet & ASET_Coordinates)) {
+ GetMBrickCoor ( A,nx,ny,nz );
+ if (nx>=0) {
+ if (!mbrick) {
+ mbrick = new PPPMBrick[nmbrick_x];
+ for (k=0;k<nmbrick_x;k++)
+ mbrick[k] = NULL;
+ }
+ if (!mbrick[nx]) {
+ mbrick[nx] = new PPMBrick[nmbrick_y];
+ for (k=0;k<nmbrick_y;k++)
+ mbrick[nx][k] = NULL;
+ }
+ if (!mbrick[nx][ny]) {
+ mbrick[nx][ny] = new PMBrick[nmbrick_z];
+ for (k=0;k<nmbrick_z;k++)
+ mbrick[nx][ny][k] = NULL;
+ }
+ if (!mbrick[nx][ny][nz])
+ mbrick[nx][ny][nz] = new MBrick(nStructures);
+ mbrick[nx][ny][nz]->AddAtom ( A,i,j );
+ } else
+ printf ( " error in "
+ "CoorManager::MakeMBricks!!!\n" );
+ }
+ }
+ }
+ }
+
+ }
+
+
+ int CoorManager::GenerateSymMates ( PGenSym genSym ) {
+ //
+ // The function generates symmetry mates according to symmetry
+ // operations found in GenSym. Results of first symmetry operation
+ // (number 0) always replaces the existing set of atoms, others
+ // are added as additional sets.
+ // If GenSym is set to NULL, the function generates all
+ // symmetry mates for the unit cell taking the symmetry information
+ // from cryst.SymOps.
+ // The newly generated chains are added to each model. These
+ // chains have many-character chain names, composed as 'x_n',
+ // where 'x' is the original name and 'n' is a unique number, which
+ // coincides with the symmetry operation (order) number; number '_0'
+ // (for the very first symmetry operatyion) is missing. Another
+ // side effect is the disorder in atoms' serial numbers.
+ // The hierarchy should therefore be cleaned after
+ // generating the symmetry mates. An appropriate way to do
+ // that is to issue the following call:
+ //
+ // PDBCleanup ( PDBCLEAN_TER | PDBCLEAN_ALTCODE_STRONG |
+ // PDBCLEAN_CHAIN_STRONG | PDBCLEAN_SERIAL );
+ //
+ PPCoorManager Mate;
+ int i,j,k,n,nMates,nMates1,nAtoms1;
+ PPAtom Atom1;
+ PPModel Model1;
+
+ if (genSym) nMates = genSym->GetNofSymOps();
+ else nMates = cryst.GetNumberOfSymOps();
+ if (nMates<=0) return GSM_NoSymOps;
+
+ if (!cryst.areMatrices()) return GSM_NoTransfMatrices;
+ if (!cryst.isCellParameters()) return GSM_NoCell;
+
+ nMates1 = nMates-1;
+ if (nMates1>0) {
+
+ // Generate symmetry mates in parallel hierarchies
+ Mate = new PCoorManager[nMates1];
+ for (i=0;i<nMates1;i++) {
+ Mate[i] = new CoorManager();
+ Mate[i]->Copy ( this );
+ Mate[i]->ApplySymTransform ( i+1,genSym );
+ }
+
+ // apply 1st symmetry operation:
+ if (genSym) ApplySymTransform ( 0,genSym );
+
+ // Gather all symmetry mates in 'this' hierarchy
+ nAtoms1 = nMates*nAtoms; // new number of atoms
+ Atom1 = new PAtom[nAtoms1]; // new array of atoms
+
+ if (nModels>0) Model1 = new PModel[nModels]; // new array of
+ else Model1 = NULL; // models
+
+ k = 0; // index of collected atoms
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ Model1[i] = newModel();
+ Model1[i]->SetMMDBManager ( PManager(this),i+1 );
+ for (j=0;j<model[i]->nChains;j++)
+ Model1[i]->MoveChain ( model[i]->chain[j],atom,Atom1,k,0 );
+ for (n=0;n<nMates1;n++)
+ for (j=0;j<model[i]->nChains;j++)
+ Model1[i]->MoveChain ( Mate[n]->model[i]->chain[j],
+ Mate[n]->atom,Atom1,k,n+1 );
+ } else
+ Model1[i] = NULL;
+
+ if (model) delete[] model;
+ model = Model1;
+
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) delete atom[i]; // should never happen
+ if (atom) delete[] atom;
+ atom = Atom1;
+ atmLen = nAtoms1; // length of Atom array
+ nAtoms = k;
+
+ // Dispose parallel hierarchies
+ for (i=0;i<nMates1;i++)
+ delete Mate[i];
+ delete[] Mate;
+
+ } else {
+ // just apply the only symmetry operation:
+ if (genSym) ApplySymTransform ( 0,genSym );
+ }
+
+ return GSM_Ok;
+
+ }
+
+ void CoorManager::ApplyTransform ( mat44 & TMatrix ) {
+ // simply transforms all coordinates by multiplying with matrix TMatrix
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter) atom[i]->Transform ( TMatrix );
+ }
+ }
+
+ void CoorManager::ApplySymTransform ( int SymOpNo, PGenSym genSym ) {
+ // This procedure applies the symmetry operation number SymOpNo
+ // (starting from 0 on) and renames chains as specified in
+ // GenSym.
+ // The chains don't have to be renamed. The number of chains
+ // to be renamed is obtained as GenSym->nChains[SymOpNo], their
+ // old names - as GenSym->chID1[SymOpNo][j], and their new names
+ // - as GenSym->chID2[SymOpNo][j], 0<=j<GenSym->nChains[SymOpNo].
+ mat44 tmat;
+ int i,j,k,nChn;
+ PPChain chain;
+ if (cryst.GetTMatrix(tmat,SymOpNo,0,0,0,PSymOps(genSym))
+ ==SYMOP_Ok) {
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter) atom[i]->Transform ( tmat );
+ }
+ if (genSym)
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ model[i]->GetChainTable ( chain,nChn );
+ for (j=0;j<genSym->nChains[SymOpNo];j++)
+ for (k=0;k<nChn;k++)
+ if (!strcmp(chain[k]->chainID,genSym->chID1[SymOpNo][j]))
+ chain[k]->SetChainID ( genSym->chID2[SymOpNo][j] );
+ }
+ }
+ }
+
+
+ void GetEulerRotMatrix ( mat33 & erm,
+ realtype alpha,
+ realtype beta,
+ realtype gamma ) {
+ // Calculates the Euler rotation matrix for rotation:
+ // 1) about z-axis by angle alpha (0..2*Pi)
+ // 2) about new y-axis by angle beta (0..Pi)
+ // 3) about new z-axis by angle gamma (0..2*Pi)
+ realtype ca,cb,cg, sa,sb,sg;
+
+ ca = cos(alpha);
+ sa = sin(alpha);
+ cb = cos(beta);
+ sb = sin(beta);
+ cg = cos(gamma);
+ sg = sin(gamma);
+
+ erm[0][0] = ca*cb*cg - sa*sg;
+ erm[0][1] = cb*cg*sa + ca*sg;
+ erm[0][2] = -cg*sb;
+
+ erm[1][0] = -cg*sa - ca*cb*sg;
+ erm[1][1] = ca*cg - cb*sa*sg;
+ erm[1][2] = sb*sg;
+
+ erm[2][0] = ca*sb;
+ erm[2][1] = sa*sb;
+ erm[2][2] = cb;
+
+ }
+
+
+
+ void GetEulerTMatrix ( mat44 & erm,
+ realtype alpha,
+ realtype beta,
+ realtype gamma,
+ realtype x0,
+ realtype y0,
+ realtype z0 ) {
+ // Calculates the Euler rotation-translation matrix for rotation:
+ // 1) about z-axis by angle alpha
+ // 2) about new y-axis by angle beta
+ // 3) about new z-axis by angle gamma
+ // Point (x0,y0,z0) is the center of rotation.
+ mat33 m;
+
+ m[0][0] = 1.0;
+ GetEulerRotMatrix ( m,alpha,beta,gamma );
+
+ erm[0][0] = m[0][0]; erm[0][1] = m[0][1]; erm[0][2] = m[0][2];
+ erm[1][0] = m[1][0]; erm[1][1] = m[1][1]; erm[1][2] = m[1][2];
+ erm[2][0] = m[2][0]; erm[2][1] = m[2][1]; erm[2][2] = m[2][2];
+ erm[3][0] = 0.0; erm[3][1] = 0.0; erm[3][2] = 0.0;
+
+ erm[3][3] = 1.0;
+
+ erm[0][3] = x0 - m[0][0]*x0 - m[0][1]*y0 - m[0][2]*z0;
+ erm[1][3] = y0 - m[1][0]*x0 - m[1][1]*y0 - m[1][2]*z0;
+ erm[2][3] = z0 - m[2][0]*x0 - m[2][1]*y0 - m[2][2]*z0;
+
+ }
+
+
+ void EulerRotation ( PPAtom A,
+ int nA,
+ realtype alpha,
+ realtype beta,
+ realtype gamma,
+ realtype x0,
+ realtype y0,
+ realtype z0 ) {
+ // Euler rotation: 1) about z-axis by angle alpha
+ // 2) about new y-axis by angle beta
+ // 3) about new z-axis by angle gamma
+ // Point (x0,y0,z0) is the center of rotation.
+ mat33 m;
+ realtype x,y,z;
+ int i;
+
+ m[0][0] = 1.0;
+ GetEulerRotMatrix ( m,alpha,beta,gamma );
+
+ for (i=0;i<nA;i++)
+ if (A[i]) {
+ if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates)) {
+ x = A[i]->x - x0;
+ y = A[i]->y - y0;
+ z = A[i]->z - z0;
+ A[i]->x = m[0][0]*x + m[0][1]*y + m[0][2]*z + x0;
+ A[i]->y = m[1][0]*x + m[1][1]*y + m[1][2]*z + y0;
+ A[i]->z = m[2][0]*x + m[2][1]*y + m[2][2]*z + z0;
+ }
+ }
+
+ }
+
+
+ void GetVecRotMatrix ( mat33 & vrm,
+ realtype alpha,
+ realtype vx,
+ realtype vy,
+ realtype vz ) {
+ // Calculates the rotation matrix for rotation by angle alpha about
+ // arbitrary vector directed as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
+ realtype ca,sa, rx,ry,rz, vl;
+
+ ca = cos(alpha);
+ sa = sin(alpha);
+
+ vl = sqrt ( vx*vx + vy*vy + vz*vz );
+ if (vl<=0.0) return;
+ rx = vx/vl;
+ ry = vy/vl;
+ rz = vz/vl;
+
+ vrm[0][0] = rx*rx*(1.0-ca) + ca;
+ vrm[0][1] = rx*ry*(1.0-ca) - rz*sa;
+ vrm[0][2] = rx*rz*(1.0-ca) + ry*sa;
+
+ vrm[1][0] = ry*rx*(1.0-ca) + rz*sa;
+ vrm[1][1] = ry*ry*(1.0-ca) + ca;
+ vrm[1][2] = ry*rz*(1.0-ca) - rx*sa;
+
+ vrm[2][0] = rz*rx*(1.0-ca) - ry*sa;
+ vrm[2][1] = rz*ry*(1.0-ca) + rx*sa;
+ vrm[2][2] = rz*rz*(1.0-ca) + ca;
+
+ }
+
+
+ void GetRotParameters ( mat33 & vrm,
+ realtype & alpha,
+ realtype & vx,
+ realtype & vy,
+ realtype & vz ) {
+ // Given the rotation matrix vrm, GetRotParameters(..)
+ // returns the rotation angle alpha and the normalized
+ // rotation axis vector (vx,vy,vz).
+ // The rotation angle and vector are determined up to
+ // their sign (however correlated, so that being substituted
+ // into GetVecRotMatrix(..) they yield the same rotation
+ // matrix).
+ // The function does not check for vrm to be a valid
+ // rotation matrix.
+ realtype ca,sa,vl;
+ ca = (vrm[0][0]+vrm[1][1]+vrm[2][2]-1.0)/2.0;
+ if (ca<-1.0) ca = -1.0; // does not work if rotation
+ if (ca>1.0) ca = 1.0; // matrix is correct
+ sa = sqrt(1.0-ca*ca);
+ if (sa>0.0) {
+ alpha = acos(ca);
+ // coefficient of 2 is corrected by normalization below
+ vx = (vrm[2][1]-vrm[1][2])/sa;
+ vy = (vrm[0][2]-vrm[2][0])/sa;
+ vz = (vrm[1][0]-vrm[0][1])/sa;
+ // the following code is formally redundant if rotation
+ // matrix is correct, however it eliminates the round-offs
+ vl = sqrt(vx*vx+vy*vy+vz*vz);
+ vx /= vl;
+ vy /= vl;
+ vz /= vl;
+ } else {
+ // zero rotation, arbitrary axis would do
+ alpha = 0.0;
+ vx = 1.0;
+ vy = 0.0;
+ vz = 0.0;
+ }
+ }
+
+
+ void GetVecTMatrix ( mat44 & vrm,
+ realtype alpha,
+ realtype vx,
+ realtype vy,
+ realtype vz,
+ realtype x0,
+ realtype y0,
+ realtype z0 ) {
+ // Calculates the rotation-translation matrix for rotation by angle
+ // alpha about arbitrary vector directed as (vx,vy,vz) =
+ // (vx2-vx1,vy2-vy1,vz2-vz1). Point (x0,y0,z0) is the center of
+ // rotation -- actually a point belonging to the rotation axis.
+ mat33 m;
+
+ GetVecRotMatrix ( m,alpha,vx,vy,vz );
+
+ vrm[0][0] = m[0][0]; vrm[0][1] = m[0][1]; vrm[0][2] = m[0][2];
+ vrm[1][0] = m[1][0]; vrm[1][1] = m[1][1]; vrm[1][2] = m[1][2];
+ vrm[2][0] = m[2][0]; vrm[2][1] = m[2][1]; vrm[2][2] = m[2][2];
+ vrm[3][0] = 0.0; vrm[3][1] = 0.0; vrm[3][2] = 0.0;
+
+ vrm[3][3] = 1.0;
+
+ vrm[0][3] = x0 - m[0][0]*x0 - m[0][1]*y0 - m[0][2]*z0;
+ vrm[1][3] = y0 - m[1][0]*x0 - m[1][1]*y0 - m[1][2]*z0;
+ vrm[2][3] = z0 - m[2][0]*x0 - m[2][1]*y0 - m[2][2]*z0;
+
+ }
+
+
+ void VectorRotation ( PPAtom A,
+ int nA,
+ realtype alpha,
+ realtype vx,
+ realtype vy,
+ realtype vz,
+ realtype x0,
+ realtype y0,
+ realtype z0 ) {
+ // Vector rotation is rotation by angle alpha about arbitrary
+ // vector directed as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
+ // Point (x0,y0,z0) is the center of rotation -- actually
+ // a point belonging to the rotation axis.
+ mat33 m;
+ realtype x,y,z;
+ int i;
+
+ GetVecRotMatrix ( m, alpha,vx,vy,vz );
+
+ for (i=0;i<nA;i++)
+ if (A[i]) {
+ if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates)) {
+ x = A[i]->x - x0;
+ y = A[i]->y - y0;
+ z = A[i]->z - z0;
+ A[i]->x = m[0][0]*x + m[0][1]*y + m[0][2]*z + x0;
+ A[i]->y = m[1][0]*x + m[1][1]*y + m[1][2]*z + y0;
+ A[i]->z = m[2][0]*x + m[2][1]*y + m[2][2]*z + z0;
+ }
+ }
+
+ }
+
+
+ void GetMassCenter ( PPAtom A, int nA,
+ realtype & xmc, realtype & ymc,
+ realtype & zmc ) {
+ realtype w,mass;
+ int i,k;
+
+ xmc = 0.0;
+ ymc = 0.0;
+ zmc = 0.0;
+ mass = 0.0;
+
+ for (i=0;i<nA;i++)
+ if (A[i]) {
+ if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates)) {
+ k = getElementNo ( A[i]->element );
+ if (k>=0) w = MolecWeight[k];
+ else w = 1.0;
+ xmc += w*A[i]->x;
+ ymc += w*A[i]->y;
+ zmc += w*A[i]->z;
+ mass += w;
+ }
+ }
+
+ if (mass>0.0) {
+ xmc /= mass;
+ ymc /= mass;
+ zmc /= mass;
+ }
+
+ }
+
+ int CoorManager::BringToUnitCell() {
+ // brings all chains into 0th unit cell
+ PChain chain;
+ PPAtom atom;
+ realtype x0,y0,z0, x,y,z, xf,yf,zf, sx,sy,sz;
+ realtype dx,dy,dz, d,d0;
+ int nAtoms;
+ int i,j,k,n,m,nt, ic,jc,kc, is,js,ks;
+
+ if (!cryst.areMatrices()) return -1;
+
+ is = 0; // this is only
+ js = 0; // to depress
+ ks = 0; // "uninitialized" worning
+
+ cryst.Frac2Orth ( 0.5,0.5,0.5, x0,y0,z0 );
+
+ nt = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ for (j=0;j<model[i]->nChains;j++) {
+ chain = model[i]->chain[j];
+ if (chain) {
+
+ x = 0.0;
+ y = 0.0;
+ z = 0.0;
+ m = 0;
+ for (k=0;k<chain->nResidues;k++)
+ if (chain->residue[k]) {
+ chain->residue[k]->GetAtomTable ( atom,nAtoms );
+ for (n=0;n<nAtoms;n++)
+ if (atom[n]) {
+ if (!atom[n]->Ter) {
+ x += atom[n]->x;
+ y += atom[n]->y;
+ z += atom[n]->z;
+ m++;
+ }
+ }
+ }
+ x /= m;
+ y /= m;
+ z /= m;
+
+ cryst.Orth2Frac ( x,y,z, xf,yf,zf );
+ sx = frac ( xf );
+ sy = frac ( yf );
+ sz = frac ( zf );
+ d0 = MaxReal;
+ for (ic=-3;ic<3;ic++)
+ for (jc=-3;jc<3;jc++)
+ for (kc=-3;kc<3;kc++) {
+ cryst.Frac2Orth ( sx+ic,sy+jc,sz+kc, dx,dy,dz );
+ dx -= x0;
+ dy -= y0;
+ dz -= z0;
+ d = dx*dx + dy*dy + dz*dz;
+ if (d<d0) {
+ d0 = d;
+ is = ic;
+ js = jc;
+ ks = kc;
+ }
+ }
+
+ sx = xf - (sx+is);
+ sy = yf - (sy+js);
+ sz = zf - (sz+ks);
+
+ if ((fabs(sx)>1.0e-10) || (fabs(sy)>1.0e-10)
+ || (fabs(sz)>1.0e-10)) {
+ nt++;
+ for (k=0;k<chain->nResidues;k++)
+ if (chain->residue[k]) {
+ chain->residue[k]->GetAtomTable ( atom,nAtoms );
+ for (n=0;n<nAtoms;n++)
+ if (atom[n]) {
+ if (!atom[n]->Ter) {
+ cryst.Orth2Frac ( atom[n]->x,atom[n]->y,
+ atom[n]->z,
+ xf,yf,zf );
+ cryst.Frac2Orth ( xf-sx,yf-sy,zf-sz,
+ atom[n]->x,atom[n]->y,
+ atom[n]->z );
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ return nt; // number of converted chains
+
+ }
+
+
+ bool CoorManager::Frac2Orth (
+ realtype xfrac, realtype yfrac, realtype zfrac,
+ realtype & xorth, realtype & yorth, realtype & zorth ) {
+ return cryst.Frac2Orth ( xfrac,yfrac,zfrac, xorth,yorth,zorth );
+ }
+
+ bool CoorManager::Orth2Frac (
+ realtype xorth, realtype yorth, realtype zorth,
+ realtype & xfrac, realtype & yfrac, realtype & zfrac ) {
+ return cryst.Orth2Frac ( xorth,yorth,zorth, xfrac,yfrac,zfrac );
+ }
+
+
+ bool CoorManager::Frac2Orth ( mat44 & F, mat44 & T ) {
+ return cryst.Frac2Orth ( F,T );
+ }
+
+ bool CoorManager::Orth2Frac ( mat44 & T, mat44 & F ) {
+ return cryst.Orth2Frac ( T,F );
+ }
+
+
+
+ // ------------------------ Contacts -------------------------------
+
+
+ #define CA_CA_Dist2 16.0
+
+ void CoorManager::FindSeqSection ( PAtom atom, int seqDist,
+ int & seq1, int & seq2 ) {
+ PAtom a;
+ PResidue res;
+ PChain chain;
+ realtype x0,y0,z0, x,y,z, dx,dy,dz, d2;
+ int i1;
+ bool B0,B;
+
+ x = 0.0;
+ y = 0.0;
+ z = 0.0;
+ x0 = 0.0;
+ y0 = 0.0;
+ z0 = 0.0;
+
+ res = atom->residue;
+ if ((!res) || (seqDist<=0)) {
+ seq1 = MaxInt4;
+ seq2 = MinInt4;
+ return;
+ }
+
+ chain = res->chain;
+ if (!chain) {
+ seq1 = MaxInt4;
+ seq2 = MinInt4;
+ return;
+ }
+
+ if (seqDist==1) {
+ seq1 = res->index;
+ seq2 = seq1;
+ return;
+ }
+
+ a = res->GetAtom ( pstr("CA"),pstr("C"),NULL );
+ if (a) {
+ x0 = a->x;
+ y0 = a->y;
+ z0 = a->z;
+ B0 = true;
+ } else
+ B0 = false;
+ if (B0) {
+ x = x0;
+ y = y0;
+ z = z0;
+ }
+
+ B = B0;
+ seq2 = res->index;
+ i1 = IMin(chain->nResidues,seq2+seqDist)-1;
+ while (seq2<i1) {
+ seq2++;
+ if (chain->residue[seq2]) {
+ a = chain->residue[seq2]->GetAtom ( pstr("CA"),pstr("C"),NULL );
+ if (a && B) {
+ dx = x-a->x;
+ dy = y-a->y;
+ dz = z-a->z;
+ d2 = dx*dx + dy*dy + dz*dz;
+ if (d2>CA_CA_Dist2) {
+ seq2--;
+ break;
+ }
+ }
+ if (a) {
+ x = a->x;
+ y = a->y;
+ z = a->z;
+ B = true;
+ } else
+ B = false;
+ }
+ }
+
+ if (B0) {
+ x = x0;
+ y = y0;
+ z = z0;
+ }
+ B = B0;
+ seq1 = res->index;
+ i1 = IMax(0,seq1-seqDist+1);
+ while (seq1>i1) {
+ seq1--;
+ if (chain->residue[seq1]) {
+ a = chain->residue[seq1]->GetAtom ( pstr("CA"),pstr("C"),NULL );
+ if (a && B) {
+ dx = x-a->x;
+ dy = y-a->y;
+ dz = z-a->z;
+ d2 = dx*dx + dy*dy + dz*dz;
+ if (d2>CA_CA_Dist2) {
+ seq1++;
+ break;
+ }
+ }
+ if (a) {
+ x = a->x;
+ y = a->y;
+ z = a->z;
+ B = true;
+ } else
+ B = false;
+ }
+ }
+
+ }
+
+
+ bool CoorManager::iContact ( PAtom a1, PAtom a2,
+ int seq1, int seq2,
+ realtype dd, realtype d12,
+ realtype d22, realtype & d2 ) {
+ // seq1..seq2 is forbidden region for residue sequence numbers
+ PResidue res1,res2;
+ PChain chain1,chain2;
+ realtype dx,dy,dz;
+
+ if (a2->Ter) return false;
+
+ dx = fabs(a2->x-a1->x);
+ if (dx<=dd) {
+ dy = fabs(a2->y-a1->y);
+ if (dy<=dd) {
+ dz = fabs(a2->z-a1->z);
+ if (dz<=dd) {
+ d2 = dx*dx + dy*dy + dz*dz;
+ if ((d12<=d2) && (d2<=d22)) {
+ if (seq1<=seq2) {
+ res1 = a1->residue;
+ res2 = a2->residue;
+ if (res1 && res2) {
+ chain1 = res1->chain;
+ chain2 = res2->chain;
+ if (chain1 && chain2) {
+ if (!strcmp(chain1->chainID,chain2->chainID)) {
+ if ((seq1<=res2->index) && (res2->index<=seq2))
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+
+ }
+
+ bool CoorManager::iContact ( realtype x, realtype y,
+ realtype z, PAtom a2,
+ realtype dd, realtype d12,
+ realtype d22, realtype & d2 ) {
+ realtype dx,dy,dz;
+
+ if (a2->Ter) return false;
+
+ dx = fabs(a2->x-x);
+ if (dx<=dd) {
+ dy = fabs(a2->y-y);
+ if (dy<=dd) {
+ dz = fabs(a2->z-z);
+ if (dz<=dd) {
+ d2 = dx*dx + dy*dy + dz*dz;
+ if ((d12<=d2) && (d2<=d22)) return true;
+ }
+ }
+ }
+
+ return false;
+
+ }
+
+
+ void CoorManager::SeekContacts ( PPAtom AIndex,
+ int ilen,
+ int atomNum,
+ realtype dist1,
+ realtype dist2,
+ int seqDist,
+ RPContact contact,
+ int & ncontacts,
+ int maxlen,
+ long group ) {
+ PContactIndex contactIndex;
+ realtype d12,d22,d2;
+ int i,seq1,seq2;
+
+ if (!AIndex) return;
+ if (dist2<dist1) return;
+ if (!AIndex[atomNum]) return;
+ if (AIndex[atomNum]->Ter) return;
+
+ contactIndex = new ContactIndex ( contact,maxlen,ncontacts,ilen );
+
+ FindSeqSection ( AIndex[atomNum],seqDist,seq1,seq2 );
+
+ d12 = dist1*dist1;
+ d22 = dist2*dist2;
+
+ for (i=0;i<ilen;i++)
+ if ((i!=atomNum) && AIndex[i]) {
+ if (iContact(AIndex[atomNum],AIndex[i],seq1,seq2,dist2,
+ d12,d22,d2))
+ contactIndex->AddContact ( atomNum,i,sqrt(d2),group );
+ }
+
+ contactIndex->GetIndex ( contact,ncontacts );
+
+ delete contactIndex;
+
+ }
+
+
+ void CoorManager::SeekContacts ( PAtom A,
+ PPAtom AIndex,
+ int ilen,
+ realtype dist1,
+ realtype dist2,
+ int seqDist,
+ RPContact contact,
+ int & ncontacts,
+ int maxlen,
+ long group
+ ) {
+ PContactIndex contactIndex;
+ realtype d12,d22,d2;
+ int i,seq1,seq2;
+
+ if (!AIndex) return;
+ if (dist2<dist1) return;
+ if (!A) return;
+ if (A->Ter) return;
+
+ contactIndex = new ContactIndex ( contact,maxlen,ncontacts,ilen );
+
+ FindSeqSection ( A,seqDist,seq1,seq2 );
+
+ d12 = dist1*dist1;
+ d22 = dist2*dist2;
+
+ for (i=0;i<ilen;i++)
+ if ((AIndex[i]!=A) && AIndex[i]) {
+ if (iContact(A,AIndex[i],seq1,seq2,dist2,d12,d22,d2))
+ contactIndex->AddContact ( -1,i,sqrt(d2),group );
+ }
+
+ contactIndex->GetIndex ( contact,ncontacts );
+
+ delete contactIndex;
+
+ }
+
+
+ void CoorManager::SeekContacts ( PPAtom AIndex1,
+ int ilen1,
+ PPAtom AIndex2,
+ int ilen2,
+ realtype dist1,
+ realtype dist2,
+ int seqDist,
+ RPContact contact,
+ int & ncontacts,
+ int maxlen,
+ mat44 * TMatrix,
+ long group,
+ int bricking,
+ bool doSqrt
+ ) {
+ // It is Ok to have NULL pointers in AIndex1 and AIndex2
+ PContactIndex contactIndex;
+ PPAtom A1,A2;
+ rvector sx0,sy0,sz0;
+ rvector dx0,dy0,dz0;
+ realtype d12,d22,d2, eps;
+ int l1,l2, i,j, nx,ny,nz, dn;
+ int ix1,ix2, iy1,iy2, iz1,iz2, ix,iy,iz;
+ int seq1,seq2;
+ PBrick B;
+ bool swap,UnitT;
+
+ if ((dist2<dist1) || (!AIndex1) || (!AIndex2)) return;
+
+ contactIndex = new ContactIndex ( contact,maxlen,ncontacts,
+ ilen1*ilen2 );
+
+ sx0 = NULL;
+ sy0 = NULL;
+ sz0 = NULL;
+ dx0 = NULL;
+ dy0 = NULL;
+ dz0 = NULL;
+ UnitT = true;
+ if (TMatrix) {
+ // Transformation matrix is given. Check that that is not
+ // the unit one.
+ eps = 1.0e-6;
+ for (i=0;(i<3) && UnitT;i++)
+ for (j=0;(j<4) && UnitT;j++)
+ if (i==j) UnitT = fabs(1.0-(*TMatrix)[i][j])<eps;
+ else UnitT = fabs((*TMatrix)[i][j])<eps;
+ if (!UnitT) {
+ // A non-unit transformation to AIndex2 is required.
+ // As AIndex1 and AIndex2 may overlap, we have to save
+ // the original AIndex1 coordinates
+ GetVectorMemory ( sx0,ilen1,0 );
+ GetVectorMemory ( sy0,ilen1,0 );
+ GetVectorMemory ( sz0,ilen1,0 );
+ for (i=0;i<ilen1;i++)
+ if (AIndex1[i]) {
+ sx0[i] = AIndex1[i]->x;
+ sy0[i] = AIndex1[i]->y;
+ sz0[i] = AIndex1[i]->z;
+ }
+ // Save original AIndex2 coordinates and modify the index
+ GetVectorMemory ( dx0,ilen2,0 );
+ GetVectorMemory ( dy0,ilen2,0 );
+ GetVectorMemory ( dz0,ilen2,0 );
+ for (i=0;i<ilen2;i++)
+ if (AIndex2[i]) {
+ dx0[i] = AIndex2[i]->x;
+ dy0[i] = AIndex2[i]->y;
+ dz0[i] = AIndex2[i]->z;
+ AIndex2[i]->Transform ( *TMatrix );
+ }
+ }
+ }
+
+ // choose A2 as the largest atom set convenient for
+ // bricking (bricking on larger set is more efficient)
+ if (bricking & BRICK_ON_1) {
+ A1 = AIndex2;
+ A2 = AIndex1;
+ l1 = ilen2;
+ l2 = ilen1;
+ swap = true;
+ } else if (bricking & BRICK_ON_2) {
+ A1 = AIndex1;
+ A2 = AIndex2;
+ l1 = ilen1;
+ l2 = ilen2;
+ swap = false;
+ } else if (ilen1<=ilen2) {
+ A1 = AIndex1;
+ A2 = AIndex2;
+ l1 = ilen1;
+ l2 = ilen2;
+ swap = false;
+ } else {
+ A1 = AIndex2;
+ A2 = AIndex1;
+ l1 = ilen2;
+ l2 = ilen1;
+ swap = true;
+ }
+
+ d12 = dist1*dist1;
+ d22 = dist2*dist2;
+
+ if (((bricking & BRICK_READY)==0) || (!brick))
+ MakeBricks ( A2,l2,dist2*1.5 );
+
+ dn = mround(dist2/brick_size)+1;
+
+ if (brick)
+ for (i=0;i<l1;i++)
+ if (A1[i]) {
+ if (!A1[i]->Ter) {
+ if (UnitT) {
+ // No transformation -- AIndex1 and AIndex2 are unmodified.
+ // Calculate the forbidden sequence region
+ FindSeqSection ( A1[i],seqDist,seq1,seq2 );
+ // And the brick location
+ GetBrickCoor ( A1[i],nx,ny,nz );
+ } else {
+ // AIndex2 and AIndex1 are modified, but the sequence
+ // distance does not apply to physically different chains
+ // (meaning that transformation of A2 effectively makes
+ // a different chain). Use unmodified atom coordinates
+ // of 1st set for calculating the brick location.
+ if (swap) GetBrickCoor ( A1[i],nx,ny,nz ); // A1 is AIndex2
+ else GetBrickCoor ( sx0[i],sy0[i],sz0[i],nx,ny,nz );
+ }
+ if (nx>=0) {
+ ix1 = IMax ( 0,nx-dn );
+ iy1 = IMax ( 0,ny-dn );
+ iz1 = IMax ( 0,nz-dn );
+ ix2 = IMin ( nbrick_x,nx+dn+1 );
+ iy2 = IMin ( nbrick_y,ny+dn+1 );
+ iz2 = IMin ( nbrick_z,nz+dn+1 );
+ if (UnitT) {
+ // AIndex1 unmodified, use it
+ for (ix=ix1;ix<ix2;ix++)
+ if (brick[ix])
+ for (iy=iy1;iy<iy2;iy++)
+ if (brick[ix][iy])
+ for (iz=iz1;iz<iz2;iz++) {
+ B = brick[ix][iy][iz];
+ if (B)
+ for (j=0;j<B->nAtoms;j++)
+ if (B->atom[j]!=A1[i]) {
+ if (iContact(A1[i],B->atom[j],seq1,seq2,
+ dist2,d12,d22,d2)) {
+ if (doSqrt) d2 = sqrt(d2);
+ if (swap) contactIndex->AddContact (
+ B->id[j],i,d2,group );
+ else contactIndex->AddContact (
+ i,B->id[j],d2,group );
+ }
+ }
+ }
+ } else if (swap) {
+ // A1 stands for AIndex2, it is modified and we need to use
+ // the modified coordinates
+ for (ix=ix1;ix<ix2;ix++)
+ if (brick[ix])
+ for (iy=iy1;iy<iy2;iy++)
+ if (brick[ix][iy])
+ for (iz=iz1;iz<iz2;iz++) {
+ B = brick[ix][iy][iz];
+ if (B)
+ for (j=0;j<B->nAtoms;j++)
+ if (iContact(A1[i]->x,A1[i]->y,A1[i]->z,
+ B->atom[j], dist2,d12,d22,d2)) {
+ if (doSqrt) d2 = sqrt(d2);
+ contactIndex->AddContact ( B->id[j],i,d2,group );
+ }
+ }
+ } else {
+ // A1 stands for AIndex1, it may be modified (if AIndex1
+ // and AIndex2 overlap) -- use its unmodified coordinates
+ // instead.
+ for (ix=ix1;ix<ix2;ix++)
+ if (brick[ix])
+ for (iy=iy1;iy<iy2;iy++)
+ if (brick[ix][iy])
+ for (iz=iz1;iz<iz2;iz++) {
+ B = brick[ix][iy][iz];
+ if (B)
+ for (j=0;j<B->nAtoms;j++)
+ if (iContact(sx0[i],sy0[i],sz0[i],
+ B->atom[j],dist2,d12,d22,d2)) {
+ if (doSqrt) d2 = sqrt(d2);
+ contactIndex->AddContact ( i,B->id[j],d2,group );
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ if (!UnitT) {
+ // restore original coordinates
+ for (i=0;i<ilen1;i++)
+ if (AIndex1[i]) {
+ AIndex1[i]->x = sx0[i];
+ AIndex1[i]->y = sy0[i];
+ AIndex1[i]->z = sz0[i];
+ }
+ for (i=0;i<ilen2;i++)
+ if (AIndex2[i]) {
+ AIndex2[i]->x = dx0[i];
+ AIndex2[i]->y = dy0[i];
+ AIndex2[i]->z = dz0[i];
+ }
+ FreeVectorMemory ( sx0,0 );
+ FreeVectorMemory ( sy0,0 );
+ FreeVectorMemory ( sz0,0 );
+ FreeVectorMemory ( dx0,0 );
+ FreeVectorMemory ( dy0,0 );
+ FreeVectorMemory ( dz0,0 );
+ }
+
+ contactIndex->GetIndex ( contact,ncontacts );
+
+ delete contactIndex;
+
+ }
+
+
+ void CoorManager::SeekContacts ( PPAtom AIndex1,
+ int ilen1,
+ PPAtom AIndex2,
+ int ilen2,
+ realtype contDist,
+ PContact contact,
+ int & ncontacts,
+ int bricking
+ ) {
+ // Simplified optimized for speed version:
+ // - no NULL pointers and Ters in AIndex1 and AIndex2
+ // - no checks for identity atoms in AIndex1 and AIndex2
+ // - contact must be pre-allocated with at least ilen1*ilen2 elements
+ // - contact returns square distances
+ // - ncontacts is always reset
+ PPAtom A1,A2;
+ realtype contDist2, dx,dy,dz, d2;
+ int l1,l2, i,j, nx,ny,nz, dn;
+ int ix1,ix2, iy1,iy2, iz1,iz2, ix,iy,iz;
+ PBrick B;
+ bool swap;
+
+ // choose A2 as the largest atom set convenient for
+ // bricking (bricking on larger set is more efficient)
+ if (bricking & BRICK_ON_1) {
+ A1 = AIndex2;
+ A2 = AIndex1;
+ l1 = ilen2;
+ l2 = ilen1;
+ swap = true;
+ } else if (bricking & BRICK_ON_2) {
+ A1 = AIndex1;
+ A2 = AIndex2;
+ l1 = ilen1;
+ l2 = ilen2;
+ swap = false;
+ } else if (ilen1<=ilen2) {
+ A1 = AIndex1;
+ A2 = AIndex2;
+ l1 = ilen1;
+ l2 = ilen2;
+ swap = false;
+ } else {
+ A1 = AIndex2;
+ A2 = AIndex1;
+ l1 = ilen2;
+ l2 = ilen1;
+ swap = true;
+ }
+
+ contDist2 = contDist*contDist;
+
+ if (((bricking & BRICK_READY)==0) || (!brick))
+ MakeBricks ( A2,l2,contDist*1.5 );
+
+ ncontacts = 0;
+
+ if (!brick) return;
+
+ dn = (int)floor(contDist/brick_size)+1;
+
+ if (swap) {
+
+ for (i=0;i<l1;i++)
+ if (A1[i]) {
+ // Find brick location
+ GetBrickCoor ( A1[i],nx,ny,nz );
+ if (nx>=0) {
+ ix1 = IMax ( 0,nx-dn );
+ iy1 = IMax ( 0,ny-dn );
+ iz1 = IMax ( 0,nz-dn );
+ ix2 = IMin ( nbrick_x,nx+dn+1 );
+ iy2 = IMin ( nbrick_y,ny+dn+1 );
+ iz2 = IMin ( nbrick_z,nz+dn+1 );
+ for (ix=ix1;ix<ix2;ix++)
+ if (brick[ix])
+ for (iy=iy1;iy<iy2;iy++)
+ if (brick[ix][iy])
+ for (iz=iz1;iz<iz2;iz++) {
+ B = brick[ix][iy][iz];
+ if (B)
+ for (j=0;j<B->nAtoms;j++) {
+ dx = A1[i]->x - B->atom[j]->x;
+ dy = A1[i]->y - B->atom[j]->y;
+ dz = A1[i]->z - B->atom[j]->z;
+ d2 = dx*dx + dy*dy + dz*dz;
+ if (d2<=contDist2) {
+ contact[ncontacts].id1 = B->id[j];
+ contact[ncontacts].id2 = i;
+ contact[ncontacts].dist = d2;
+ ncontacts++;
+ }
+ }
+ }
+ }
+ }
+
+ } else {
+
+ for (i=0;i<l1;i++)
+ if (A1[i]) {
+ // Find brick location
+ GetBrickCoor ( A1[i],nx,ny,nz );
+ if (nx>=0) {
+ ix1 = IMax ( 0,nx-dn );
+ iy1 = IMax ( 0,ny-dn );
+ iz1 = IMax ( 0,nz-dn );
+ ix2 = IMin ( nbrick_x,nx+dn+1 );
+ iy2 = IMin ( nbrick_y,ny+dn+1 );
+ iz2 = IMin ( nbrick_z,nz+dn+1 );
+ for (ix=ix1;ix<ix2;ix++)
+ if (brick[ix])
+ for (iy=iy1;iy<iy2;iy++)
+ if (brick[ix][iy])
+ for (iz=iz1;iz<iz2;iz++) {
+ B = brick[ix][iy][iz];
+ if (B)
+ for (j=0;j<B->nAtoms;j++) {
+ dx = A1[i]->x - B->atom[j]->x;
+ dy = A1[i]->y - B->atom[j]->y;
+ dz = A1[i]->z - B->atom[j]->z;
+ d2 = dx*dx + dy*dy + dz*dz;
+ if (d2<=contDist2) {
+ contact[ncontacts].id1 = i;
+ contact[ncontacts].id2 = B->id[j];
+ contact[ncontacts].dist = d2;
+ ncontacts++;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ }
+
+
+ void CoorManager::SeekContacts ( PPAtom AIndex1,
+ int ilen1,
+ PPAtom * AIndex2,
+ ivector ilen2,
+ int nStructures,
+ realtype dist1,
+ realtype dist2,
+ PPMContact & contact,
+ int bricking
+ ) {
+ // It is Ok to have NULL pointers in AIndex1 and AIndex2
+ PMBrick B;
+ PAtom A;
+ realtype d12,d22,d2;
+ int dn, i,j,k, nx,ny,nz, ix1,iy1,iz1, ix2,iy2,iz2;
+ int ix,iy,iz;
+
+ if (dist2<dist1) return;
+ if ((!AIndex1) || (!AIndex2)) return;
+
+ d12 = dist1*dist1;
+ d22 = dist2*dist2;
+
+ if (((bricking & BRICK_READY)==0) || (!mbrick))
+ MakeMBricks ( AIndex2,ilen2,nStructures,dist2*1.5 );
+
+ contact = new PMContact[ilen1];
+
+ dn = mround(dist2/brick_size)+1;
+
+ if (mbrick)
+ for (i=0;i<ilen1;i++) {
+ A = AIndex1[i];
+ contact[i] = NULL;
+ if (A) {
+ if (!A->Ter) {
+ contact[i] = new MContact(nStructures);
+ contact[i]->contactID = i;
+ // Calculate the brick location
+ GetMBrickCoor ( A,nx,ny,nz );
+ if (nx>=0) {
+ ix1 = IMax ( 0,nx-dn );
+ iy1 = IMax ( 0,ny-dn );
+ iz1 = IMax ( 0,nz-dn );
+ ix2 = IMin ( nmbrick_x,nx+dn+1 );
+ iy2 = IMin ( nmbrick_y,ny+dn+1 );
+ iz2 = IMin ( nmbrick_z,nz+dn+1 );
+ for (ix=ix1;ix<ix2;ix++)
+ if (mbrick[ix])
+ for (iy=iy1;iy<iy2;iy++)
+ if (mbrick[ix][iy])
+ for (iz=iz1;iz<iz2;iz++) {
+ B = mbrick[ix][iy][iz];
+ if (B)
+ for (j=0;j<nStructures;j++)
+ for (k=0;k<B->nAtoms[j];k++)
+ if (B->atom[j][k]!=A) {
+ if (iContact(A,B->atom[j][k],
+ MaxInt4,MinInt4,
+ dist2,d12,d22,d2))
+ contact[i]->AddContact (
+ B->atom[j][k],j,B->id[j][k] );
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ for (i=0;i<ilen1;i++)
+ contact[i] = NULL;
+
+ }
+
+
+
+ DefineClass(QSortContacts)
+
+ class QSortContacts : public QuickSort {
+ public :
+ QSortContacts() : QuickSort() {}
+ int Compare ( int i, int j );
+ void Swap ( int i, int j );
+ void Sort ( PContact contact, int ncontacts, int sortmode );
+ protected :
+ int mode;
+ };
+
+ int QSortContacts::Compare ( int i, int j ) {
+ bool gt,lt;
+ switch (mode) {
+ default :
+ case CNSORT_1INC : gt = (((PContact)data)[i].id1 >
+ ((PContact)data)[j].id1);
+ lt = (((PContact)data)[i].id1 <
+ ((PContact)data)[j].id1);
+ break;
+ case CNSORT_1DEC : gt = (((PContact)data)[j].id1 >
+ ((PContact)data)[i].id1);
+ lt = (((PContact)data)[j].id1 <
+ ((PContact)data)[i].id1);
+ break;
+ case CNSORT_2INC : gt = (((PContact)data)[i].id2 >
+ ((PContact)data)[j].id2);
+ lt = (((PContact)data)[i].id2 <
+ ((PContact)data)[j].id2);
+ break;
+ case CNSORT_2DEC : gt = (((PContact)data)[j].id2 >
+ ((PContact)data)[i].id2);
+ lt = (((PContact)data)[j].id2 <
+ ((PContact)data)[i].id2);
+ break;
+ case CNSORT_DINC : gt = (((PContact)data)[i].dist >
+ ((PContact)data)[j].dist);
+ lt = (((PContact)data)[i].dist <
+ ((PContact)data)[j].dist);
+ break;
+ case CNSORT_DDEC : gt = (((PContact)data)[j].dist >
+ ((PContact)data)[i].dist);
+ lt = (((PContact)data)[j].dist <
+ ((PContact)data)[i].dist);
+ break;
+ }
+ if (gt) return 1;
+ if (lt) return -1;
+ return 0;
+ }
+
+ void QSortContacts::Swap ( int i, int j ) {
+ ((PContact)data)[i].Swap ( ((PContact)data)[j] );
+ }
+
+
+ void QSortContacts::Sort ( PContact contact, int ncontacts,
+ int sortmode ) {
+ mode = sortmode;
+ if (mode!=CNSORT_OFF)
+ QuickSort::Sort ( &(contact[0]),ncontacts );
+ }
+
+
+ void SortContacts ( PContact contact, int ncontacts,
+ CNSORT_DIR sortmode ) {
+ QSortContacts SC;
+ if (sortmode!=CNSORT_OFF)
+ SC.Sort ( contact,ncontacts,sortmode );
+ }
+
+
+ // ------------------- Stream functions ----------------------
+
+ void CoorManager::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ Root::write ( f );
+ f.WriteInt ( &CoorIDCode );
+ f.WriteReal ( &brick_size );
+ f.WriteReal ( &xbrick_0 );
+ f.WriteReal ( &ybrick_0 );
+ f.WriteReal ( &zbrick_0 );
+ f.WriteInt ( &nbrick_x );
+ f.WriteInt ( &nbrick_y );
+ f.WriteInt ( &nbrick_z );
+ }
+
+ void CoorManager::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ Root::read ( f );
+ f.ReadInt ( &CoorIDCode );
+ f.ReadReal ( &brick_size );
+ f.ReadReal ( &xbrick_0 );
+ f.ReadReal ( &ybrick_0 );
+ f.ReadReal ( &zbrick_0 );
+ f.ReadInt ( &nbrick_x );
+ f.ReadInt ( &nbrick_y );
+ f.ReadInt ( &nbrick_z );
+ }
+
+
+ MakeStreamFunctions(CoorManager);
+
+
+
+
+ // ===================================================================
+
+ int SuperposeAtoms ( mat44 & T, PPAtom A1, int nA, PPAtom A2,
+ ivector C ) {
+ realtype xc1,yc1,zc1, xc2,yc2,zc2, det,B;
+ rmatrix A,U,V;
+ rvector W,RV1;
+ vect3 vc1,vc2;
+ int i,j,k,i1,i2,nat;
+
+
+ // 1. Set unit matrix as "default" return
+
+ for (i=0;i<4;i++) {
+ for (j=0;j<4;j++)
+ T[i][j] = 0.0;
+ T[i][i] = 1.0;
+ }
+
+
+ // 2. Calculate mass centers
+
+ xc1 = 0.0;
+ yc1 = 0.0;
+ zc1 = 0.0;
+ xc2 = 0.0;
+ yc2 = 0.0;
+ zc2 = 0.0;
+
+ nat = 0;
+ if (C) {
+
+ for (i1=0;i1<nA;i1++)
+ if (!A1[i1]->Ter) {
+ i2 = C[i1];
+ if (i2>=0) {
+ xc1 += A1[i1]->x;
+ yc1 += A1[i1]->y;
+ zc1 += A1[i1]->z;
+ xc2 += A2[i2]->x;
+ yc2 += A2[i2]->y;
+ zc2 += A2[i2]->z;
+ nat++;
+ }
+ }
+
+ } else {
+
+ for (i=0;i<nA;i++)
+ if ((!A1[i]->Ter) && (!A2[i]->Ter)) {
+ xc1 += A1[i]->x;
+ yc1 += A1[i]->y;
+ zc1 += A1[i]->z;
+ xc2 += A2[i]->x;
+ yc2 += A2[i]->y;
+ zc2 += A2[i]->z;
+ nat++;
+ }
+
+ }
+
+ if (nat>1) {
+ xc1 /= nat;
+ yc1 /= nat;
+ zc1 /= nat;
+ xc2 /= nat;
+ yc2 /= nat;
+ zc2 /= nat;
+ } else if (nat>0) {
+ T[0][3] = xc2 - xc1;
+ T[1][3] = yc2 - yc1;
+ T[2][3] = zc2 - zc1;
+ return SPOSEAT_Ok;
+ } else
+ return SPOSEAT_NoAtoms;
+
+
+ // 3. Calculate the correlation matrix
+
+ GetMatrixMemory ( A,3,3,1,1 );
+
+ for (i=1;i<=3;i++)
+ for (j=1;j<=3;j++)
+ A[i][j] = 0.0;
+
+ if (C) {
+
+ for (i1=0;i1<nA;i1++)
+ if (!A1[i1]->Ter) {
+ i2 = C[i1];
+ if (i2>=0) {
+ vc1[0] = A1[i1]->x - xc1;
+ vc1[1] = A1[i1]->y - yc1;
+ vc1[2] = A1[i1]->z - zc1;
+ vc2[0] = A2[i2]->x - xc2;
+ vc2[1] = A2[i2]->y - yc2;
+ vc2[2] = A2[i2]->z - zc2;
+ for (i=1;i<=3;i++)
+ for (j=1;j<=3;j++)
+ A[i][j] += vc1[j-1]*vc2[i-1];
+ }
+ }
+
+ } else {
+
+ for (k=0;k<nA;k++)
+ if ((!A1[k]->Ter) && (!A2[k]->Ter)) {
+ vc1[0] = A1[k]->x - xc1;
+ vc1[1] = A1[k]->y - yc1;
+ vc1[2] = A1[k]->z - zc1;
+ vc2[0] = A2[k]->x - xc2;
+ vc2[1] = A2[k]->y - yc2;
+ vc2[2] = A2[k]->z - zc2;
+ for (i=1;i<=3;i++)
+ for (j=1;j<=3;j++)
+ A[i][j] += vc1[j-1]*vc2[i-1];
+ }
+
+ }
+
+
+ // 4. Calculate transformation matrix (to be applied to A1)
+
+ det = A[1][1]*A[2][2]*A[3][3] +
+ A[1][2]*A[2][3]*A[3][1] +
+ A[2][1]*A[3][2]*A[1][3] -
+ A[1][3]*A[2][2]*A[3][1] -
+ A[1][1]*A[2][3]*A[3][2] -
+ A[3][3]*A[1][2]*A[2][1];
+
+ // 4.1 SV-decompose the correlation matrix
+
+ GetMatrixMemory ( U ,3,3,1,1 );
+ GetMatrixMemory ( V ,3,3,1,1 );
+ GetVectorMemory ( W ,3,1 );
+ GetVectorMemory ( RV1,3,1 );
+
+ math::SVD ( 3,3,3,A,U,V,W,RV1,true,true,i );
+
+ if (i!=0) {
+ FreeVectorMemory ( RV1,1 );
+ FreeVectorMemory ( W ,1 );
+ FreeMatrixMemory ( V ,3,1,1 );
+ FreeMatrixMemory ( U ,3,1,1 );
+ FreeMatrixMemory ( A ,3,1,1 );
+ return SPOSEAT_SVD_Fail;
+ }
+
+ // 4.2 Check for parasite inversion and fix it if found
+
+ if (det<=0.0) {
+ k = 0;
+ B = MaxReal;
+ for (j=1;j<=3;j++)
+ if (W[j]<B) {
+ B = W[j];
+ k = j;
+ }
+ for (j=1;j<=3;j++)
+ V[j][k] = -V[j][k];
+ }
+
+ // 4.3 Calculate rotational part of T
+
+ for (j=1;j<=3;j++)
+ for (k=1;k<=3;k++) {
+ B = 0.0;
+ for (i=1;i<=3;i++)
+ B += U[j][i]*V[k][i];
+ T[j-1][k-1] = B;
+ }
+
+
+ // 4.4 Add translational part to T
+
+ T[0][3] = xc2 - T[0][0]*xc1 - T[0][1]*yc1 - T[0][2]*zc1;
+ T[1][3] = yc2 - T[1][0]*xc1 - T[1][1]*yc1 - T[1][2]*zc1;
+ T[2][3] = zc2 - T[2][0]*xc1 - T[2][1]*yc1 - T[2][2]*zc1;
+
+
+ // 5. Release memory and quit
+
+ FreeVectorMemory ( RV1,1 );
+ FreeVectorMemory ( W ,1 );
+ FreeMatrixMemory ( V ,3,1,1 );
+ FreeMatrixMemory ( U ,3,1,1 );
+ FreeMatrixMemory ( A ,3,1,1 );
+
+ return SPOSEAT_Ok;
+
+ }
+
+ realtype getPhi ( PPAtom A ) {
+ //
+ // A0 A1 A2 A3
+ // o-----o-----o-----o
+ // |
+ // Phi
+ //
+ // -Pi <= Phi <= +Pi
+ //
+ vect3 U,W,V, a,b,c;
+ realtype Wmag,S,T;
+
+ U[0] = A[0]->x - A[1]->x;
+ U[1] = A[0]->y - A[1]->y;
+ U[2] = A[0]->z - A[1]->z;
+
+ W[0] = A[2]->x - A[1]->x;
+ W[1] = A[2]->y - A[1]->y;
+ W[2] = A[2]->z - A[1]->z;
+
+ V[0] = A[3]->x - A[2]->x;
+ V[1] = A[3]->y - A[2]->y;
+ V[2] = A[3]->z - A[2]->z;
+
+ a[0] = U[1]*W[2] - W[1]*U[2];
+ a[1] = U[2]*W[0] - W[2]*U[0];
+ a[2] = U[0]*W[1] - W[0]*U[1];
+
+ b[0] = V[1]*W[2] - W[1]*V[2];
+ b[1] = V[2]*W[0] - W[2]*V[0];
+ b[2] = V[0]*W[1] - W[0]*V[1];
+
+ c[0] = a[1]*b[2] - b[1]*a[2];
+ c[1] = a[2]*b[0] - b[2]*a[0];
+ c[2] = a[0]*b[1] - b[0]*a[1];
+
+ Wmag = sqrt(W[0]*W[0]+W[1]*W[1]+W[2]*W[2]);
+
+ S = c[0]*W[0] + c[1]*W[1] + c[2]*W[2];
+ T = a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
+ T *= Wmag;
+
+ if ((S==0.0) && (T==0.0)) return NO_TORSION;
+ else return atan2(S,T);
+
+ }
+
+ realtype getPsi ( PPAtom A ) {
+ vect3 v1,v2;
+ realtype l1,l2;
+
+ v1[0] = A[0]->x - A[1]->x;
+ v1[1] = A[0]->y - A[1]->y;
+ v1[2] = A[0]->z - A[1]->z;
+
+ v2[0] = A[2]->x - A[1]->x;
+ v2[1] = A[2]->y - A[1]->y;
+ v2[2] = A[2]->z - A[1]->z;
+
+ l1 = v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2];
+ if (l1==0.0) l1 = 1.0;
+ l2 = v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2];
+ if (l2==0.0) l2 = 1.0;
+
+ return acos((v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])/sqrt(l1*l2));
+
+ }
+
+ const realtype NO_TORSION = -MaxReal;
+
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_coormngr.h b/mmdb2/mmdb_coormngr.h
new file mode 100644
index 0000000..c493169
--- /dev/null
+++ b/mmdb2/mmdb_coormngr.h
@@ -0,0 +1,959 @@
+// $Id: mmdb_coormngr.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 14.07.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_coormngr <interface>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Brick ( space brick )
+// ~~~~~~~~~ mmdb::CoorManager ( MMDB atom coordinate manager )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_CoorMngr__
+#define __MMDB_CoorMngr__
+
+#include "mmdb_root.h"
+
+namespace mmdb {
+
+ // =========================== Brick ==============================
+
+ // bricking control
+ enum BRICK_STATE {
+ BRICK_ON_1 = 0x00000001,
+ BRICK_ON_2 = 0x00000002,
+ BRICK_READY = 0x00000004
+ };
+
+ DefineClass(Brick);
+ typedef PPBrick * PPPBrick;
+
+ class Brick {
+
+ public :
+ int nAtoms; // number of atoms hit into brick
+ PPAtom atom; // pointers to atoms
+ ivector id; // atom ids (in present realization, these are
+ // indices of atoms from the bricked array)
+
+ Brick ();
+ ~Brick();
+
+ void Clear ();
+ void AddAtom ( PAtom A, int atomid );
+
+ protected :
+ int nAllocAtoms;
+ void InitBrick();
+
+ };
+
+
+ // =========================== MBrick =============================
+
+ // Bricking multiple structures
+
+ DefineClass(MBrick);
+ typedef PPMBrick * PPPMBrick;
+
+ class MBrick {
+
+ public :
+ ivector nAtoms; // number of atoms in the brick
+ PPAtom *atom; // pointers to atoms
+ imatrix id; // atom ids (in present realization, these are
+ // indices of atoms from the bricked array)
+
+ MBrick ( int nStructures );
+ ~MBrick();
+
+ void Clear ();
+ void AddAtom ( PAtom A, int structNo, int atomid );
+
+ protected :
+ ivector nAlloAtoms;
+ int nStruct;
+ void InitMBrick ( int nStructures );
+
+ };
+
+
+
+ // ==================== GenSym ========================
+
+ DefineClass(GenSym);
+ DefineStreamFunctions(GenSym);
+
+ class GenSym : public SymOps {
+
+ friend class CoorManager;
+
+ public :
+
+ GenSym ();
+ GenSym ( io::RPStream Object );
+ ~GenSym();
+
+ void FreeMemory();
+
+ int AddSymOp ( cpstr XYZOperation );
+ // the number of just added operation may be obtained as
+ // Nop = GenSym::GetNofSymOps()-1 .
+
+ int AddRenChain ( int Nop, const ChainID ch1, const ChainID ch2 );
+
+ void Copy ( PSymOps genSym );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ PChainID * chID1; // pairs of chains to rename from chID1[n][i]
+ PChainID * chID2; // to chID2[n][i] for each operation n<Nops
+ ivector nChains; // number of chains to rename for each oper-n
+
+ void InitGenSym();
+
+ private :
+ int nOpAlloc; // number of allocated operations
+
+ };
+
+
+ // ========================= Contact =============================
+
+ DefineStructure(Contact);
+
+ struct Contact {
+ int id1,id2;
+ long group;
+ realtype dist;
+ void Copy ( RContact c );
+ void Swap ( RContact c );
+ };
+
+
+ // ======================== MContact =============================
+
+ DefineClass(MContact);
+
+ class MContact : public io::Stream {
+
+ public :
+ int nStruct,contactID;
+ ivector nAtoms;
+ PPAtom * atom;
+ imatrix id;
+
+ MContact ( int nStructures );
+ ~MContact();
+
+ void AddContact ( PAtom A, int structNo, int atomid );
+
+ protected:
+ ivector nAlloc;
+
+ };
+
+ extern void DeleteMContacts ( PPMContact & mcontact, int nContacts );
+
+
+ // ====================== CoorManager =========================
+
+ DefineClass(CoorManager);
+ DefineStreamFunctions(CoorManager);
+
+ // ---- Atom extraction return
+ enum CID_RC {
+ CID_Ok = 0,
+ CID_NoModel = 1,
+ CID_NoChain = 2,
+ CID_NoResidue = 3,
+ CID_NoAtom = 4,
+ CID_WrongPath = 5
+ };
+
+ // ---- generate symmetry mates return codes
+ enum GSM_RC {
+ GSM_Ok = 0,
+ GSM_NoSymOps = 1,
+ GSM_NoTransfMatrices = 2,
+ GSM_NoCell = 3
+ };
+
+ class CoorManager : public Root {
+
+ public :
+
+ int CoorIDCode; // last return from atom extraction procedure
+
+ CoorManager ();
+ CoorManager ( io::RPStream Object );
+ ~CoorManager();
+
+
+ // ----------------------------------------------------------
+
+ int SetDefaultCoorID ( cpstr CID );
+
+
+ // ---------------- Bricking ------------------------------
+
+ void RemoveBricks ();
+ bool areBricks () { return (brick!=NULL); }
+ void MakeBricks ( PPAtom atmvec, int avlen,
+ realtype Margin, realtype BrickSize=6.0 );
+ void GetBrickDimension (
+ int & nxmax, int & nymax, int & nzmax );
+ void GetBrickCoor ( PAtom A, int & nx, int & ny, int & nz );
+ void GetBrickCoor ( realtype x, realtype y, realtype z,
+ int & nx, int & ny, int & nz );
+ PBrick GetBrick ( int nx, int ny, int nz );
+
+ void RemoveMBricks ();
+ bool areMBricks () { return (mbrick!=NULL); }
+ void MakeMBricks ( PPAtom * atmvec, ivector avlen,
+ int nStructures, realtype Margin,
+ realtype BrickSize=6.0 );
+ void GetMBrickDimension (
+ int & nxmax, int & nymax, int & nzmax );
+ void GetMBrickCoor ( PAtom A, int & nx, int & ny, int & nz );
+ void GetMBrickCoor ( realtype x, realtype y, realtype z,
+ int & nx, int & ny, int & nz );
+ PMBrick GetMBrick ( int nx, int ny, int nz );
+
+ // ---------------- Extracting models ---------------------
+
+ int GetNumberOfModels () { return nModels; }
+ int GetFirstModelNum ();
+ PModel GetFirstDefinedModel();
+ PModel GetModel ( int modelNo ); // 1<=modelNo<=nModels
+ PModel GetModel ( cpstr CID );
+ void GetModelTable ( PPModel & modTable,
+ int & NumberOfModels );
+
+ // ---------------- Deleting models -----------------------
+
+ int DeleteModel ( cpstr CID );
+ int DeleteModel ( int modelNo ); // 1<=modelNo<=nOfModels
+
+ // ---------------- Adding/Inserting models ---------------
+
+ int AddModel ( PModel mdl );
+ int InsModel ( PModel mdl, int modelNo );
+ void RotateModels ( int modelNo1, int modelNo2, int rotdir );
+ void SwapModels ( int modelNo1, int modelNo2 );
+
+ // ---------------- Extracting chains ---------------------
+
+ int GetNumberOfChains ( int modelNo );
+ int GetNumberOfChains ( cpstr CID );
+ PChain GetChain ( int modelNo, const ChainID chainID );
+ PChain GetChain ( int modelNo, int chainNo );
+ PChain GetChain ( cpstr CID );
+ void GetChainTable ( int modelNo, PPChain & chainTable,
+ int & NumberOfChains );
+ void GetChainTable ( cpstr CID, PPChain & chainTable,
+ int & NumberOfChains );
+
+ // ----------------- Deleting chains ----------------------
+
+ int DeleteChain ( int modelNo, const ChainID chID );
+ int DeleteChain ( int modelNo, int chainNo );
+ int DeleteAllChains ( int modelNo );
+ int DeleteAllChains ();
+
+ // ------------------ Adding chains -----------------------
+
+ int AddChain ( int modelNo, PChain chain );
+
+ // ---------------- Extracting residues -------------------
+
+ int GetNumberOfResidues ( int modelNo, const ChainID chainID );
+ int GetNumberOfResidues ( int modelNo, int chainNo );
+ int GetNumberOfResidues ( cpstr CID );
+ PResidue GetResidue ( int modelNo, const ChainID chainID,
+ int seqNo, const InsCode insCode );
+ PResidue GetResidue ( int modelNo, int chainNo,
+ int seqNo, const InsCode insCode );
+ PResidue GetResidue ( int modelNo, const ChainID chainID,
+ int resNo );
+ PResidue GetResidue ( int modelNo, int chainNo, int resNo );
+ PResidue GetResidue ( cpstr CID );
+ int GetResidueNo ( int modelNo, const ChainID chainID,
+ int seqNo, const InsCode insCode );
+ int GetResidueNo ( int modelNo, int chainNo,
+ int seqNo, const InsCode insCode );
+ void GetResidueTable ( PPResidue & resTable,
+ int & NumberOfResidues );
+ void GetResidueTable ( int modelNo, const ChainID chainID,
+ PPResidue & resTable,
+ int & NumberOfResidues );
+ void GetResidueTable ( int modelNo, int chainNo,
+ PPResidue & resTable,
+ int & NumberOfResidues );
+ void GetResidueTable ( cpstr CID, PPResidue & resTable,
+ int & NumberOfResidues );
+
+
+ // ----------------- Deleting residues -----------------------
+
+ int DeleteResidue ( int modelNo, const ChainID chainID,
+ int seqNo, const InsCode insCode );
+ int DeleteResidue ( int modelNo, const ChainID chainID,
+ int resNo );
+ int DeleteResidue ( int modelNo, int chainNo,
+ int seqNo, const InsCode insCode );
+ int DeleteResidue ( int modelNo, int chainNo, int resNo );
+ int DeleteAllResidues ( int modelNo, const ChainID chainID );
+ int DeleteAllResidues ( int modelNo, int chainNo );
+ int DeleteAllResidues ( int modelNo );
+ int DeleteAllResidues ();
+ int DeleteSolvent ();
+
+ // ------------------- Adding residues -----------------------
+
+ int AddResidue ( int modelNo, const ChainID chainID,
+ PResidue res );
+ int AddResidue ( int modelNo, int chainNo, PResidue res );
+
+ // -------------------- Extracting atoms ----------------------
+
+ int GetNumberOfAtoms () { return nAtoms; }
+ int GetNumberOfAtoms ( int modelNo, const ChainID chainID,
+ int seqNo, const InsCode insCode );
+ int GetNumberOfAtoms ( int modelNo, int chainNo,
+ int seqNo, const InsCode insCode );
+ int GetNumberOfAtoms ( int modelNo, const ChainID chainID,
+ int resNo );
+ int GetNumberOfAtoms ( int modelNo, int chainNo, int resNo );
+ int GetNumberOfAtoms ( cpstr CID );
+
+ PAtom GetAtom (
+ int modelNo, // model serial number 1...
+ const ChainID chID, // chain ID
+ int seqNo, // residue sequence number
+ const InsCode insCode, // residue insertion code
+ const AtomName aname, // atom name
+ const Element elmnt, // chemical element code or '*'
+ const AltLoc aloc // alternate location indicator
+ );
+
+ PAtom GetAtom (
+ int modelNo, // model serial number 1...
+ const ChainID chID, // chain ID
+ int seqNo, // residue sequence number
+ const InsCode insCode, // residue insertion code
+ int atomNo // atom number 0..
+ );
+
+ PAtom GetAtom (
+ int modelNo, // model serial number 1...
+ const ChainID chID, // chain ID
+ int resNo, // residue number 0..
+ const AtomName aname, // atom name
+ const Element elmnt, // chemical element code or '*'
+ const AltLoc aloc // alternate location indicator
+ );
+
+ PAtom GetAtom (
+ int modelNo, // model serial number 1...
+ const ChainID chID, // chain ID
+ int resNo, // residue number 0..
+ int atomNo // atom number 0..
+ );
+
+ PAtom GetAtom (
+ int modelNo, // model serial number 1...
+ int chNo, // chain number 0..
+ int seqNo, // residue sequence number
+ const InsCode insCode, // residue insertion code
+ const AtomName aname, // atom name
+ const Element elmnt, // chemical element code or '*'
+ const AltLoc aloc // alternate location indicator
+ );
+
+ PAtom GetAtom (
+ int modelNo, // model serial number 1...
+ int chNo, // chain number 0...
+ int seqNo, // residue sequence number
+ const InsCode insCode, // residue insertion code
+ int atomNo // atom number 0...
+ );
+
+ PAtom GetAtom (
+ int modelNo, // model serial number 1...
+ int chNo, // chain number 0...
+ int resNo, // residue number 0...
+ const AtomName aname, // atom name
+ const Element elmnt, // chemical element code or '*'
+ const AltLoc aloc // alternate location indicator
+ );
+
+ PAtom GetAtom (
+ int modelNo, // model serial number 1...
+ int chNo, // chain number 0...
+ int resNo, // residue number 0...
+ int atomNo // atom number 0...
+ );
+
+
+ // GetAtom(CID) returns atom answering to the following
+ // CID pattern:
+ // /mdl/chn/seq(res).i/atm[elm]:a
+ // where
+ // mdl - model number (mandatory); at least model #1 is always
+ // present
+ // chn - chain identifier ( mandatory)
+ // seq - residue sequence number (mandatory)
+ // (res) - residue name in round brackets (may be omitted)
+ // .i - insert code after a dot; if '.i' or 'i' is missing
+ // then residue without an insertion code is looked
+ // for
+ // atm - atom name (mandatory)
+ // [elm] - chemical element code in square brackets; it may
+ // be omitted but could be helpful for e.g.
+ // distinguishing C_alpha and CA
+ // :a - alternate location indicator after colon; if
+ // ':a' or 'a' is missing then an atom without
+ // alternate location indicator is looked for.
+ // All spaces are ignored, all identifiers should be in capital
+ // letters (comparisons are case-sensitive).
+ PAtom GetAtom ( cpstr CID );
+
+
+ void GetAtomTable ( PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable ( int modelNo, const ChainID chainID,
+ int seqNo, const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable ( int modelNo, int chainNo,
+ int seqNo, const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable ( int modelNo, const ChainID chainID, int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable ( int modelNo, int chainNo, int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable ( cpstr CID, PPAtom & atomTable,
+ int & NumberOfAtoms );
+
+
+ // GetAtomTable1(..) returns atom table without TER atoms and
+ // without NULL atom pointers. NumberOfAtoms returns the actual
+ // number of atom pointers in atomTable.
+ // atomTable is allocated within the function. If it was
+ // not set to NULL before calling the function, the function will
+ // attempt to deallocate it first.
+ // The application is responsible for deleting atomTable,
+ // however it must not touch atom pointers, i.e. use simply
+ // "delete atomTable;". Never pass atomTable from GetAtomTable(..)
+ // into this function, unless you set it to NULL before doing that.
+ void GetAtomTable1 ( PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable1 ( int modelNo, const ChainID chainID,
+ int seqNo, const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable1 ( int modelNo, int chainNo,
+ int seqNo, const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable1 ( int modelNo, const ChainID chainID, int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable1 ( int modelNo, int chainNo, int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable1 ( cpstr CID, PPAtom & atomTable,
+ int & NumberOfAtoms );
+
+
+ // -------------------- Deleting atoms -----------------------
+
+ int DeleteAtom ( int modelNo,
+ const ChainID chID,
+ int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( int modelNo,
+ const ChainID chID,
+ int seqNo,
+ const InsCode insCode,
+ int atomNo );
+ int DeleteAtom ( int modelNo,
+ const ChainID chID,
+ int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( int modelNo, const ChainID chID,
+ int resNo, int atomNo );
+ int DeleteAtom ( int modelNo, int chNo, int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( int modelNo, int chNo, int seqNo,
+ const InsCode insCode, int atomNo );
+ int DeleteAtom ( int modelNo, int chNo, int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( int modelNo, int chNo, int resNo, int atomNo );
+
+ int DeleteAllAtoms ( int modelNo, const ChainID chID,
+ int seqNo, const InsCode insCode );
+ int DeleteAllAtoms ( int modelNo, const ChainID chID, int resNo );
+ int DeleteAllAtoms ( int modelNo, const ChainID chID );
+ int DeleteAllAtoms ( int modelNo, int chNo, int seqNo,
+ const InsCode insCode );
+ int DeleteAllAtoms ( int modelNo, int chNo, int resNo );
+ int DeleteAllAtoms ( int modelNo, int chNo );
+ int DeleteAllAtoms ( int modelNo );
+ int DeleteAllAtoms ();
+
+ // This function leaves only alternative location with maximal
+ // occupancy, if those are equal or unspecified, the one with
+ // "least" alternative location indicator.
+ // The function returns the number of deleted atoms and optimizes
+ // the atom index.
+ int DeleteAltLocs ();
+
+
+ // --------------------- Adding atoms ------------------------
+
+ int AddAtom ( int modelNo, const ChainID chID,
+ int seqNo, const InsCode insCode, PAtom atom );
+ int AddAtom ( int modelNo, const ChainID chID, int resNo,
+ PAtom atom );
+ int AddAtom ( int modelNo, int chNo, int seqNo,
+ const InsCode insCode, PAtom atom );
+ int AddAtom ( int modelNo, int chNo, int resNo, PAtom atom );
+
+
+ // -------------------- Transformations -----------------------
+
+ int GenerateSymMates ( PGenSym genSym=NULL );
+ // 1: no Sym operations,
+ // 2: no fract/orth matrices
+ // 3: no cell parameters
+ // 0: Ok
+
+ void ApplyTransform ( mat44 & TMatrix ); // simply transforms all
+ // coordinates by multiplying
+ // with matrix TMatrix
+
+ int BringToUnitCell(); // brings all chains into 0th unit cell
+
+ // Frac2Orth(..) and Orth2Frac(..) transform between fractional
+ // and orthogonal coordinates, if areMatrices() returns true.
+ // If the transformation matrices were not set, the functions just
+ // copy the coordinates. Returns true if the transformation was
+ // done; False return means that transformation matrices were not
+ // calculated
+ bool Frac2Orth (
+ realtype xfrac, realtype yfrac, realtype zfrac,
+ realtype & xorth, realtype & yorth, realtype & zorth );
+ bool Orth2Frac (
+ realtype xorth, realtype yorth, realtype zorth,
+ realtype & xfrac, realtype & yfrac, realtype & zfrac );
+
+
+ // Below, F and T are transformation matrices in fractional and
+ // orthogonal coordinates, respectively.
+ bool Frac2Orth ( mat44 & F, mat44 & T );
+ bool Orth2Frac ( mat44 & T, mat44 & F );
+
+ // ==================== Seeking contacts ======================
+
+ void SeekContacts (
+ PPAtom AIndex, // index of atoms [0..ilen-1]
+ int ilen, // length of index
+ int atomNum, // number of 1st contact atom
+ // in the index. All other atoms
+ // are checked for contact with
+ // 1st atom
+ realtype dist1, // minimal contact distance
+ realtype dist2, // maximal contact distance
+ int seqDist, // the sequence distance to neglect.
+ // If seqDist==0, all atoms are
+ // checked for contact. If
+ // seqDist==1, the atoms belonging
+ // to the same residue as atom
+ // AIndex[atomNum], are neglected.
+ // If seqDist>1, all atoms belonging
+ // to residues closer than
+ // +/-(seqDist-1) around that of
+ // atom AIndex[atomNum], are
+ // neglected. If chain is broken
+ // (has a gap) on section
+ // [-(seqDist-1)..seqDist-1], the
+ // section of neglection is
+ // shortened to that gap.
+ RPContact contact, // indices of contacting atoms
+ // [0..ncontacts-1]. contact[i].id1
+ // is set to atomNum and
+ // contact[i].id2 is set to the
+ // index of 2nd contacting atom
+ // in vector AIndex
+ int & ncontacts, // number of contacts found. If
+ // ncontacts>0 on input, it is
+ // assumed that new contacts that
+ // newly found contacts should be
+ // appended to those already
+ // existing
+ int maxlen=0, // if <=0, then vector contact is
+ // allocated dynamically. If
+ // contact!=NULL, then it is
+ // appended with new contacts.
+ // The application is responsible
+ // for deallocation of contact
+ // after use.
+ // If maxlen>0 then vector contact
+ // is prohibited of dynamical
+ // allocation/deallocation. In this
+ // case, not more than maxlen
+ // contacts will be returned.
+ long group=0 // a contact group ID, which will be
+ // simply stored in contact[i].group
+ // fields. This ID may be useful
+ // if contacts are obtained in
+ // multiple calls of the function
+ );
+
+ void SeekContacts (
+ PAtom A, // 1st atom in contact
+ PPAtom AIndex, // index of atoms [0..ilen-1] to
+ // check for contact with 1st atom
+ int ilen, // length of index
+ realtype dist1, // minimal contact distance
+ realtype dist2, // maximal contact distance
+ int seqDist, // the sequence distance to neglect.
+ // If seqDist==0, all atoms are
+ // checked for contact. If
+ // seqDist==1, the atoms belonging
+ // to the same residue as atom
+ // A, are neglected. If seqDist>1,
+ // all atoms belonging to residues
+ // closer than +/-(seqDist-1) around
+ // that of atom A, are neglected. If
+ // chain is broken (has a gap) on
+ // section
+ // [-(seqDist-1)..seqDist-1], the
+ // section of neglection is
+ // shortened to that gap.
+ RPContact contact, // indices of contacting atoms
+ // [0..ncontacts-1]. contact[i].id1
+ // is set to -1, and contact[i].id2
+ // is set to the index of 2nd
+ // contacting atom in vector AIndex
+ int & ncontacts, // number of contacts found. If
+ // ncontacts>0 on input, it is
+ // assumed that new contacts that
+ // newly found contacts should be
+ // appended those already existing
+ int maxlen=0, // if <=0, then vector contact is
+ // allocated dynamically. If
+ // contact!=NULL, then it is
+ // appended with new contacts.
+ // The application is responsible
+ // for deallocation of contact
+ // after use.
+ // If maxlen>0 then vector contact
+ // is prohibited of dynamical
+ // allocation/deallocation. In this
+ // case, not more than maxlen
+ // contacts will be returned.
+ long group=0 // a contact group ID, which will be
+ // simply stored in contact[i].group
+ // fields. This ID may be useful
+ // if contacts are obtained in
+ // multiple calls of the function
+ );
+
+ void SeekContacts (
+ PPAtom AIndex1, // 1st atom index [0..ilen1-1]
+ int ilen1, // length of 1st index
+ PPAtom AIndex2, // 2nd atom index [0..ilen2-1] to
+ // check for contact with 1st index
+ int ilen2, // length of 2nd index
+ realtype dist1, // minimal contact distance
+ realtype dist2, // maximal contact distance
+ int seqDist, // the sequence distance to
+ // neglect.
+ // If seqDist==0, all atoms are
+ // checked for contact.
+ // If seqDist==1, the atoms
+ // belonging to the same residue
+ // are neglected.
+ // If seqDist>1, all atoms
+ // belonging to residues closer than
+ // +/-(seqDist-1) to each other,
+ // are neglected. If chain is broken
+ // (has a gap) on section
+ // [-(seqDist-1)..seqDist-1], the
+ // section of neglection is
+ // shortened to that gap.
+ RPContact contact, // indices of contacting atoms
+ // [0..ncontacts-1]. contact[i].id1
+ // contains number of atom from 1st
+ // index, and contact[i].id2
+ // contains number of atom from 2nd
+ // index, contacting with the former
+ // one
+ int & ncontacts, // number of contacts found. If
+ // ncontacts>0 on input, it is
+ // assumed that newly found
+ // contacts should be appended to
+ // those already existing
+ int maxlen=0, // if <=0, then vector contact is
+ // allocated dynamically. If
+ // contact!=NULL, then it is
+ // appended with new contacts.
+ // The application is responsible
+ // for deallocation of contact
+ // after use.
+ // If maxlen>0 then vector contact
+ // is prohibited of dynamical
+ // allocation/deallocation. In this
+ // case, not more than maxlen
+ // contacts will be returned.
+ mat44 * TMatrix=NULL, // transformation matrix for 2nd
+ // set of atoms (AIndex2)
+ long group=0, // a contact group ID, which will
+ // be stored in contact[i].group
+ // fields. This ID may be useful
+ // if contacts are obtained in
+ // multiple calls of the function
+ int bricking=0, // bricking control; may be a
+ // combination of BRICK_ON_1 or
+ // BRICK_ON_2 with BRICK_READY
+ bool doSqrt=true // if False, then Contact contains
+ // square distances
+ );
+
+ // Simplified optimized for speed version:
+ // - no NULL pointers and Ters in AIndex1 and AIndex2
+ // - no checks for identity atoms in AIndex1 and AIndex2
+ // - contact must be pre-allocated with at least ilen1*ilen2
+ // elements
+ // - contact returns square distances
+ // - ncontacts is always reset
+ void SeekContacts (
+ PPAtom AIndex1, // 1st atom index [0..ilen1-1]
+ int ilen1, // length of 1st index
+ PPAtom AIndex2, // 2nd atom index [0..ilen2-1] to
+ // check for contact with 1st index
+ int ilen2, // length of 2nd index
+ realtype contDist, // maximal contact distance
+ PContact contact, // indices of contacting atoms
+ // [0..ncontacts-1]. contact[i].id1
+ // contains number of atom from 1st
+ // index, and contact[i].id2
+ // contains number of atom from 2nd
+ // index, contacting with the former
+ // one. Must be pre-allocated
+ int & ncontacts, // number of contacts found
+ int bricking=0 // bricking control; may be a
+ // combination of BRICK_ON_1 or
+ // BRICK_ON_2 with BRICK_READY
+ );
+
+ void SeekContacts (
+ PPAtom AIndex1, // 1st atom index [0..ilen1-1]
+ int ilen1, // length of 1st index
+ PPAtom * AIndex2, // indexes of atoms to be checked
+ // for contact with each atom from
+ // Aindex1; dimension
+ // [0..nStructures-1][0..ilen2[i]-1]
+ ivector ilen2, // lengths of indexes AIndex2
+ int nStructures, // number of indexes AIndex2
+ realtype dist1, // minimal contact distance
+ realtype dist2, // maximal contact distance
+ PPMContact & contact, // resulting contacts, one structure
+ // per each position in AIndex1. If
+ // AIndex1[i] is NULL, contact[i] is
+ // also NULL. "contact" is always
+ // allocated, no re-use or
+ // re-allocation is attempted.
+ int bricking=0 // bricking control; may be
+ // BRICK_READY if AIndex2 does not
+ // change
+ );
+
+ protected :
+
+ // bricks
+ realtype brick_size, xbrick_0,ybrick_0,zbrick_0;
+ int nbrick_x,nbrick_y,nbrick_z;
+ PPPBrick * brick;
+
+ realtype mbrick_size, xmbrick_0,ymbrick_0,zmbrick_0;
+ int nmbrick_x,nmbrick_y,nmbrick_z;
+ PPPMBrick * mbrick;
+
+ // --------------- Stream I/O -----------------------------
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ void InitMMDBCoorManager();
+
+ void ApplySymTransform ( int SymMatrixNo, PGenSym genSym=NULL );
+
+ void ResetManager ();
+
+ void FindSeqSection ( PAtom atom, int seqDist,
+ int & seq1, int & seq2 );
+ bool iContact ( PAtom a1, PAtom a2,
+ int seq1, int seq2,
+ realtype dd, realtype d12,
+ realtype d22, realtype & d2 );
+ bool iContact ( realtype x, realtype y,
+ realtype z, PAtom a2,
+ realtype dd, realtype d12,
+ realtype d22, realtype & d2 );
+
+ };
+
+
+
+ // ===================================================================
+
+
+
+ // GetEulerRotMatrix(..) calculates the Euler rotation matrix
+ // for rotation:
+ // 1) about z-axis by angle alpha
+ // 2) about new y-axis by angle beta
+ // 3) about new z-axis by angle gamma
+ extern void GetEulerRotMatrix ( mat33 & erm, realtype alpha,
+ realtype beta, realtype gamma );
+
+ // GetEulerTMatrix(..) calculates the Euler rotation-translation
+ // matrix for rotation:
+ // 1) about z-axis by angle alpha
+ // 2) about new y-axis by angle beta
+ // 3) about new z-axis by angle gamma
+ // Point (x0,y0,z0) is the center of rotation.
+ extern void GetEulerTMatrix ( mat44 & erm, realtype alpha,
+ realtype beta, realtype gamma,
+ realtype x0, realtype y0, realtype z0 );
+
+ // Euler rotation: 1) about z-axis by angle alpha
+ // 2) about new y-axis by angle beta
+ // 3) about new z-axis by angle gamma
+ // Point (x0,y0,z0) is the center of rotation.
+ extern void EulerRotation ( PPAtom A, int nA,
+ realtype alpha, realtype beta, realtype gamma,
+ realtype x0, realtype y0, realtype z0 );
+
+ // GetVecRotMatrix(..) calculates the rotation matrix for
+ // rotation by angle alpha about arbitrary vector directed
+ // as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
+ extern void GetVecRotMatrix ( mat33 & vrm, realtype alpha,
+ realtype vx, realtype vy, realtype vz );
+
+
+ // Given the rotation matrix vrm, GetRotParameters(..)
+ // returns the rotation angle alpha and the normalized
+ // rotation axis vector (vx,vy,vz).
+ // The rotation angle and vector are determined up to
+ // their sign (however correlated, so that being substituted
+ // into GetVecRotMatrix(..) they yield the same rotation
+ // matrix).
+ // The function does not check for vrm to be a valid
+ // rotation matrix.
+ extern void GetRotParameters ( mat33 & vrm, realtype & alpha,
+ realtype & vx, realtype & vy, realtype & vz );
+
+
+ // GetVecTMatrix(..) calculates the rotation-translation matrix
+ // for rotation by angle alpha about arbitrary vector directed as
+ // (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1). Point (x0,y0,z0) is
+ // the center of rotation -- actually a point belonging to the
+ // rotation axis.
+ extern void GetVecTMatrix ( mat44 & vrm, realtype alpha,
+ realtype vx, realtype vy, realtype vz,
+ realtype x0, realtype y0, realtype z0 );
+
+ // Vector rotation is rotation by angle alpha about arbitrary
+ // vector directed as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
+ // Point (x0,y0,z0) is the center of rotation -- actually
+ // a point belonging to the rotation axis.
+ extern void VectorRotation ( PPAtom A, int nA, realtype alpha,
+ realtype vx, realtype vy, realtype vz,
+ realtype x0, realtype y0, realtype z0 );
+
+ extern void GetMassCenter ( PPAtom A, int nA,
+ realtype & xmc, realtype & ymc, realtype & zmc );
+
+
+ enum SPOSEAT_RC {
+ SPOSEAT_Ok = 0,
+ SPOSEAT_NoAtoms = 1,
+ SPOSEAT_SVD_Fail = 2
+ };
+
+ // Given two sets of atoms, A1 and A2, SuperposeAtoms(...) calculates
+ // the rotational-translational matrix T such that |T*A1 - A2| is
+ // minimal in least-square terms.
+ // If vector C is not given (default), all nA atoms of set A1 are
+ // considered as corresponding to nA first atoms of set A2,
+ // A1[i] <-> A2[i], 0<=i<nA .
+ // If vector C is given, then the correspondence of atoms is
+ // established as A1[i] <-> A2[C[i]] only for those i that C[i]>=0.
+ // The default option (C==NULL) is thus identical to C[i]==i, 0<=i<nA.
+ // Upon normal completion, the procedure returns SPOSEAT_Ok.
+
+ extern int SuperposeAtoms ( mat44 & T, PPAtom A1, int nA, PPAtom A2,
+ ivector C=NULL );
+
+ enum CNSORT_DIR {
+ CNSORT_OFF = 0,
+ CNSORT_1INC = 1,
+ CNSORT_1DEC = 2,
+ CNSORT_2INC = 3,
+ CNSORT_2DEC = 4,
+ CNSORT_DINC = 5,
+ CNSORT_DDEC = 6
+ };
+
+ extern void SortContacts ( PContact contact, int ncontacts,
+ CNSORT_DIR sortmode );
+
+
+ extern const realtype NO_TORSION;
+
+ extern realtype getPhi ( PPAtom A ); // A[0] - A[3] used
+ extern realtype getPsi ( PPAtom A ); // A[0] - A[2] used
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_cryst.cpp b/mmdb2/mmdb_cryst.cpp
new file mode 100644
index 0000000..5ad924c
--- /dev/null
+++ b/mmdb2/mmdb_cryst.cpp
@@ -0,0 +1,2312 @@
+// $Id: mmdb_cryst.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 21.11.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Cryst <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::CrystContainer ( container for cryst. data )
+// ~~~~~~~~~ mmdb::NCSMatrix ( non-cryst. symm. matrix class )
+// mmdb::TVect ( translation vector class )
+// mmdb::Cryst ( MMDB cryst. section class )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "mmdb_cryst.h"
+#include "mmdb_defs.h"
+#include "mmdb_cifdefs.h"
+
+namespace mmdb {
+
+ // ============== CrystContainer ====================
+
+ PContainerClass CrystContainer::MakeContainerClass ( int ClassID ) {
+ switch (ClassID) {
+ default :
+ case ClassID_Template :
+ return ClassContainer::MakeContainerClass(ClassID);
+ case ClassID_NCSMatrix : return new NCSMatrix();
+ case ClassID_TVect : return new TVect ();
+ }
+ }
+
+ ERROR_CODE CrystContainer::AddMTRIXLine ( cpstr S ) {
+ int i;
+ ERROR_CODE RC;
+ RC = Error_NCSM_WrongSerial;
+ for (i=0;i<length;i++) {
+ RC = PNCSMatrix(Container[i])->ConvertPDBASCII(S);
+ if (RC==0) break;
+ if (RC!=Error_NCSM_WrongSerial) break;
+ }
+ return RC;
+ }
+
+ MakeStreamFunctions(CrystContainer)
+
+
+ // ================ NCSMatrix ===================
+
+ NCSMatrix::NCSMatrix() : ContainerClass() {
+ Init();
+ }
+
+ NCSMatrix::NCSMatrix ( cpstr S ) : ContainerClass() {
+ Init();
+ ConvertPDBASCII ( S );
+ }
+
+ NCSMatrix::NCSMatrix ( io::RPStream Object )
+ : ContainerClass(Object) {
+ Init();
+ }
+
+ NCSMatrix::~NCSMatrix() {}
+
+ void NCSMatrix::Init() {
+ int i,j;
+ serNum = -1;
+ iGiven = -1;
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ m[i][j] = 0.0;
+ m[i][i] = 1.0;
+ v[i] = 0.0;
+ }
+ WhatIsSet = 0; // nothing is set
+ }
+
+ bool NCSMatrix::PDBASCIIDump1 ( io::RFile f ) {
+ // makes the ASCII PDB MATRIXn lines if all
+ // of them were set.
+ char S[100];
+ int i,j;
+
+ if ((WhatIsSet & NCSMSET_All)==NCSMSET_All)
+ for (i=0;i<3;i++) {
+ sprintf ( S,"MTRIX%1i %3i",i+1,serNum );
+ PadSpaces ( S,80 );
+ for (j=0;j<3;j++)
+ PutRealF ( &(S[10+j*10]),m[i][j],10,6 );
+ PutRealF ( &(S[45]),v[i],10,5 );
+ if (iGiven) S[59] = '1';
+ f.WriteLine ( S );
+ }
+
+ return true; // container should use this virtual
+
+ }
+
+ ERROR_CODE NCSMatrix::ConvertPDBASCII ( cpstr S ) {
+ realtype m0,m1,m2,v0;
+ int sN,iG;
+
+ if (!(GetInteger(sN,&(S[7]) ,3 ) &&
+ GetReal (m0,&(S[10]),10) &&
+ GetReal (m1,&(S[20]),10) &&
+ GetReal (m2,&(S[30]),10) &&
+ GetReal (v0,&(S[45]),10)))
+ return Error_NCSM_Unrecognized;
+
+ if (S[59]=='1') iG = 1;
+ else iG = 0;
+
+ if (WhatIsSet & NCSMSET_All) {
+ if (sN!=serNum) return Error_NCSM_WrongSerial;
+ if (iG!=iGiven) return Error_NCSM_UnmatchIG;
+ }
+
+ if (!strncmp(S,"MTRIX1",6)) {
+
+ if (WhatIsSet & NCSMSET_Matrix1) return Error_NCSM_AlreadySet;
+ serNum = sN;
+ iGiven = iG;
+ m[0][0] = m0;
+ m[0][1] = m1;
+ m[0][2] = m2;
+ v[0] = v0;
+ WhatIsSet |= NCSMSET_Matrix1;
+
+ } else if (!strncmp(S,"MTRIX2",6)) {
+
+ if (WhatIsSet & NCSMSET_Matrix2) return Error_NCSM_AlreadySet;
+ serNum = sN;
+ iGiven = iG;
+ m[1][0] = m0;
+ m[1][1] = m1;
+ m[1][2] = m2;
+ v[1] = v0;
+ WhatIsSet |= NCSMSET_Matrix2;
+
+ } else if (!strncmp(S,"MTRIX3",6)) {
+
+ if (WhatIsSet & NCSMSET_Matrix3) return Error_NCSM_AlreadySet;
+ serNum = sN;
+ iGiven = iG;
+ m[2][0] = m0;
+ m[2][1] = m1;
+ m[2][2] = m2;
+ v[2] = v0;
+ WhatIsSet |= NCSMSET_Matrix3;
+
+ } else
+ return Error_WrongSection;
+
+ return Error_NoError;
+
+ }
+
+ void NCSMatrix::MakeCIF ( mmcif::PData CIF, int N ) {
+ mmcif::PLoop Loop;
+ int RC;
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_NCS_OPER,Loop );
+ if ((RC!=mmcif::CIFRC_Ok) || (N==0)) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_MATRIX11 );
+ Loop->AddLoopTag ( CIFTAG_MATRIX12 );
+ Loop->AddLoopTag ( CIFTAG_MATRIX13 );
+ Loop->AddLoopTag ( CIFTAG_VECTOR1 );
+ Loop->AddLoopTag ( CIFTAG_MATRIX21 );
+ Loop->AddLoopTag ( CIFTAG_MATRIX22 );
+ Loop->AddLoopTag ( CIFTAG_MATRIX23 );
+ Loop->AddLoopTag ( CIFTAG_VECTOR2 );
+ Loop->AddLoopTag ( CIFTAG_MATRIX31 );
+ Loop->AddLoopTag ( CIFTAG_MATRIX32 );
+ Loop->AddLoopTag ( CIFTAG_MATRIX33 );
+ Loop->AddLoopTag ( CIFTAG_VECTOR3 );
+ Loop->AddLoopTag ( CIFTAG_CODE );
+ }
+ Loop->AddInteger ( serNum );
+ if (WhatIsSet & NCSMSET_Matrix1) {
+ Loop->AddReal ( m[0][0] );
+ Loop->AddReal ( m[0][1] );
+ Loop->AddReal ( m[0][2] );
+ Loop->AddReal ( v[0] );
+ } else {
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ }
+ if (WhatIsSet & NCSMSET_Matrix2) {
+ Loop->AddReal ( m[1][0] );
+ Loop->AddReal ( m[1][1] );
+ Loop->AddReal ( m[1][2] );
+ Loop->AddReal ( v[1] );
+ } else {
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ }
+ if (WhatIsSet & NCSMSET_Matrix3) {
+ Loop->AddReal ( m[2][0] );
+ Loop->AddReal ( m[2][1] );
+ Loop->AddReal ( m[2][2] );
+ Loop->AddReal ( v[2] );
+ } else {
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ Loop->AddString ( NULL );
+ }
+ if (iGiven==1) Loop->AddString ( pstr("generated") );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+ }
+
+ ERROR_CODE NCSMatrix::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ char Code[100];
+ ERROR_CODE rc;
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_NCS_OPER );
+ if (!Loop) {
+ n = -1; // signal to finish processing of this structure
+ return Error_EmptyCIF;
+ }
+
+ if (n>=Loop->GetLoopLength()) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+ WhatIsSet = 0;
+ rc = CIFGetInteger ( serNum,Loop,CIFTAG_ID,n );
+ if (rc!=Error_NoError) return rc;
+ if (CIFGetString(Code,Loop,CIFTAG_CODE,n,sizeof(Code),
+ pstr("")))
+ iGiven = MinInt4;
+ else if (!strcasecmp(Code,"generated"))
+ iGiven = 1;
+ else
+ iGiven = MinInt4;
+
+
+ rc = CIFGetReal ( m[0][0],Loop,CIFTAG_MATRIX11,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal ( m[0][1],Loop,CIFTAG_MATRIX12,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal ( m[0][2],Loop,CIFTAG_MATRIX13,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal ( v[0] ,Loop,CIFTAG_VECTOR1 ,n );
+ if (rc!=Error_NoError) return rc;
+ WhatIsSet |= NCSMSET_Matrix1;
+
+ rc = CIFGetReal ( m[1][0],Loop,CIFTAG_MATRIX21,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal ( m[1][1],Loop,CIFTAG_MATRIX22,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal ( m[1][2],Loop,CIFTAG_MATRIX23,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal ( v[1] ,Loop,CIFTAG_VECTOR2 ,n );
+ if (rc!=Error_NoError) return rc;
+ WhatIsSet |= NCSMSET_Matrix2;
+
+ rc = CIFGetReal ( m[2][0],Loop,CIFTAG_MATRIX31,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal ( m[2][1],Loop,CIFTAG_MATRIX32,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal ( m[2][2],Loop,CIFTAG_MATRIX33,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal ( v[2] ,Loop,CIFTAG_VECTOR3 ,n );
+ if (rc!=Error_NoError) return rc;
+ WhatIsSet |= NCSMSET_Matrix3;
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+ void NCSMatrix::SetNCSMatrix ( int serialNum,
+ mat33 & ncs_m, vect3 & ncs_v,
+ int i_Given ) {
+ int i,j;
+ serNum = serialNum;
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ m[i][j] = ncs_m[i][j];
+ v[i] = ncs_v[i];
+ }
+ iGiven = i_Given;
+ WhatIsSet |= NCSMSET_All;
+ }
+
+ void NCSMatrix::Copy ( PContainerClass NCSMatrix ) {
+ int i,j;
+
+ serNum = PNCSMatrix(NCSMatrix)->serNum;
+ iGiven = PNCSMatrix(NCSMatrix)->iGiven;
+
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ m[i][j] = PNCSMatrix(NCSMatrix)->m[i][j];
+ v[i] = PNCSMatrix(NCSMatrix)->v[i];
+ }
+
+ WhatIsSet = PNCSMatrix(NCSMatrix)->WhatIsSet;
+
+ }
+
+ void NCSMatrix::write ( io::RFile f ) {
+ int i,j;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &serNum );
+ f.WriteInt ( &iGiven );
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ f.WriteReal ( &(m[i][j]) );
+ f.WriteReal ( &(v[i]) );
+ }
+ f.WriteWord ( &WhatIsSet );
+ }
+
+ void NCSMatrix::read ( io::RFile f ) {
+ int i,j;
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &serNum );
+ f.ReadInt ( &iGiven );
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ f.ReadReal ( &(m[i][j]) );
+ f.ReadReal ( &(v[i]) );
+ }
+ f.ReadWord ( &WhatIsSet );
+ }
+
+ MakeStreamFunctions(NCSMatrix)
+
+
+
+ // ================ TVect ===================
+
+ TVect::TVect() : ContainerClass() {
+ Init();
+ }
+
+ TVect::TVect ( cpstr S ) : ContainerClass() {
+ Init();
+ ConvertPDBASCII ( S );
+ }
+
+ TVect::TVect ( io::RPStream Object ) : ContainerClass(Object) {
+ Init();
+ }
+
+ TVect::~TVect() {
+ if (comment) delete[] comment;
+ }
+
+ void TVect::Init() {
+ serNum = -1;
+ t[0] = 0.0;
+ t[1] = 0.0;
+ t[2] = 0.0;
+ comment = NULL;
+ }
+
+ void TVect::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+ // makes the ASCII PDB TVECT line number N
+ sprintf ( S,"TVECT %3i",serNum );
+ PadSpaces ( S,80 );
+ PutRealF ( &(S[10]),t[0],10,5 );
+ PutRealF ( &(S[20]),t[1],10,5 );
+ PutRealF ( &(S[30]),t[2],10,5 );
+ if (comment)
+ strncpy ( &(S[40]),comment,IMin(30,strlen(comment)) );
+ }
+
+ ERROR_CODE TVect::ConvertPDBASCII ( cpstr S ) {
+ GetInteger ( serNum ,&(S[7]) ,3 );
+ GetReal ( t[0] ,&(S[10]),10 );
+ GetReal ( t[1] ,&(S[20]),10 );
+ GetReal ( t[2] ,&(S[30]),10 );
+ CreateCopy ( comment,&(S[40]) );
+ return Error_NoError;
+
+ }
+
+ void TVect::MakeCIF ( mmcif::PData CIF, int N ) {
+ mmcif::PLoop Loop;
+ int RC;
+ RC = CIF->AddLoop ( CIFCAT_DATABASE_PDB_TVECT,Loop );
+ if ((RC!=mmcif::CIFRC_Ok) || (N==0)) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_VECTOR1 );
+ Loop->AddLoopTag ( CIFTAG_VECTOR2 );
+ Loop->AddLoopTag ( CIFTAG_VECTOR3 );
+ Loop->AddLoopTag ( CIFTAG_DETAILS );
+ }
+ Loop->AddInteger ( serNum );
+ Loop->AddReal ( t[0] );
+ Loop->AddReal ( t[1] );
+ Loop->AddReal ( t[2] );
+ Loop->AddString ( comment );
+ }
+
+ ERROR_CODE TVect::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ ERROR_CODE rc;
+
+ Loop = CIF->GetLoop ( CIFCAT_DATABASE_PDB_TVECT );
+ if (!Loop) {
+ n = -1; // signal to finish processing of this structure
+ return Error_EmptyCIF;
+ }
+
+ if (n>=Loop->GetLoopLength()) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+ rc = CIFGetInteger(serNum,Loop,CIFTAG_ID,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal(t[0],Loop,CIFTAG_VECTOR1,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal(t[1],Loop,CIFTAG_VECTOR2,n );
+ if (rc!=Error_NoError) return rc;
+ rc = CIFGetReal(t[2],Loop,CIFTAG_VECTOR3,n );
+ if (rc!=Error_NoError) return rc;
+ Loop->GetString ( comment,CIFTAG_DETAILS,n,true );
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+
+ void TVect::Copy ( PContainerClass TVect ) {
+ int i;
+ serNum = PTVect(TVect)->serNum;
+ for (i=0;i<3;i++)
+ t[i] = PTVect(TVect)->t[i];
+ CreateCopy ( comment,PTVect(TVect)->comment );
+ }
+
+ void TVect::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &serNum );
+ for (i=0;i<3;i++)
+ f.WriteReal ( &(t[i]) );
+ f.CreateWrite ( comment );
+ }
+
+ void TVect::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &serNum );
+ for (i=0;i<3;i++)
+ f.ReadReal ( &(t[i]) );
+ f.CreateRead ( comment );
+ }
+
+ MakeStreamFunctions(TVect)
+
+
+
+ // ===================== Cryst =======================
+
+ Cryst::Cryst() : io::Stream() {
+ Init ( true );
+ }
+
+ Cryst::Cryst ( io::RPStream Object ) : io::Stream(Object) {
+ Init ( true );
+ }
+
+ void Cryst::Init ( bool fullInit ) {
+ int i,j,k;
+
+ WhatIsSet = 0; // nothing is set
+ a = 1.0;
+ b = 1.0;
+ c = 1.0;
+ alpha = 90.0;
+ beta = 90.0;
+ gamma = 90.0;
+ strcpy ( spaceGroup ,"" );
+ strcpy ( spaceGroupFix,"" );
+ Z = 1;
+ CellCheck = CCHK_NoCell;
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++) {
+ o[i][j] = 0.0;
+ s[i][j] = 0.0;
+ for (k=0;k<6;k++)
+ RR[k][i][j] = 0.0;
+ }
+ o[i][i] = 1.0;
+ s[i][i] = 1.0;
+ t[i] = 0.0;
+ u[i] = 0.0;
+ for (k=0;k<6;k++)
+ RR[k][i][i] = 1.0;
+ }
+ for (i=0;i<4;i++) {
+ for (j=0;j<4;j++) {
+ RO [i][j] = 0.0;
+ RF [i][j] = 0.0;
+ ROU[i][j] = 0.0;
+ RFU[i][j] = 0.0;
+ }
+ RO [i][i] = 1.0;
+ RF [i][i] = 1.0;
+ ROU[i][i] = 1.0;
+ RFU[i][i] = 1.0;
+ }
+ Vol = 0.0;
+ VolChk = 0.0;
+ VolErr = 0.0;
+ as = 1.0;
+ bs = 1.0;
+ cs = 1.0;
+ alphas = 90.0;
+ betas = 90.0;
+ gammas = 90.0;
+
+ for (k=0;k<6;k++)
+ AC[k] = 0.0;
+
+ NCode = 0;
+
+ if (fullInit) {
+ syminfo_lib = NULL;
+ ignoreScalei = false; // flag to ignore SCALEi cards
+ processSG = true; // flag to process space group at file read
+ fixSpaceGroup = true; // flag to fix space group at file read
+ }
+
+ }
+
+ Cryst::~Cryst() {
+ FreeMemory();
+ if (syminfo_lib) delete[] syminfo_lib;
+ }
+
+ void Cryst::FreeMemory() {
+ ncsMatrix.FreeContainer();
+ tVect .FreeContainer();
+ symOps .FreeMemory ();
+ }
+
+ void Cryst::Reset() {
+ FreeMemory();
+ Init ( false );
+ }
+
+ cpstr rhombohedral[] = {
+ cpstr("R 3" ),
+ cpstr("R 3" ),
+ cpstr("R 3 2"),
+ cpstr("R 3 2")
+ };
+
+ cpstr short_mono[] = {
+ cpstr("P 2" ),
+ cpstr("P 21"),
+ cpstr("C 2" ),
+ cpstr("A 2" ),
+ cpstr("B 2" ),
+ cpstr("I 2" )
+ };
+
+ cpstr special[] = {
+ cpstr("A1" ),
+ cpstr("Hall: P 1 (-x,-1/2*y+1/2*z,1/2*y+1/2*z)" ),
+ cpstr("C1211" ),
+ cpstr("Hall: C 2y (x+1/4,y+1/4,z)" ),
+ cpstr("C21" ),
+ cpstr("Hall: C 2y (x+1/4,y+1/4,z)" ),
+ cpstr("I1211" ),
+ cpstr("Hall: C 2y (x+1/4,y+1/4,-x+z-1/4)" ),
+ cpstr("I21" ),
+ cpstr("Hall: C 2y (x+1/4,y+1/4,-x+z-1/4)" ),
+ cpstr("P21212A"),
+ cpstr("Hall: P 2 2ab (x+1/4,y+1/4,z)" ),
+ cpstr("F422" ),
+ cpstr("Hall: I 4 2 (1/2*x+1/2*y,-1/2*x+1/2*y,z)" ),
+ cpstr("C4212" ),
+ cpstr("Hall: P 4 2 (1/2*x+1/2*y-1/4,-1/2*x+1/2*y-1/4,z)")
+ };
+
+
+
+ int Cryst::FixSpaceGroup() {
+ // This function attempts to clean up the Brookhaven mess in space
+ // group naming, by checking the space group symbol with cell
+ // parameters. Returns:
+ //
+ // 0 - space group symbol is correct, spaceGroupFix receives
+ // a copy of spaceGroup
+ // 1 - space group symbol does not agree with cell parameters,
+ // and fixed successfully. spaceGroupFix receives
+ // the appropriate space group symbol
+ // -1 - space group symbol does not agree with cell parameters,
+ // however fix is not possible. spaceGroupFix receives
+ // a copy of spaceGroup
+ // -2 - any checks are not possible because cell parameters
+ // are not found, spaceGroupFix receives a copy of
+ // spaceGroup
+ //
+ realtype eps,m1,m2;
+ SymGroup s;
+ int i,k;
+ char c;
+
+ strcpy ( spaceGroupFix,spaceGroup );
+
+ if ((WhatIsSet & CSET_CellParams)!=CSET_CellParams) return -2;
+
+ eps = 0.01;
+
+ k = -1;
+ for (i=0;(i<4) && (k<0);i++)
+ if (!strcmp(spaceGroup,rhombohedral[i])) k = i;
+
+ if (k>=0) {
+ c = 'N';
+ if ((fabs(a-b)<=eps) && (fabs(alpha-90.0)<=eps) &&
+ (fabs(beta-90.0)<=eps) && (fabs(gamma-120.0)<=eps))
+ c = 'H';
+ else {
+ m1 = (a+b+c)/3.0;
+ m2 = (alpha+beta+gamma)/3.0;
+ if ((fabs(a-m1)<=eps) && (fabs(b-m1)<=eps) &&
+ (fabs(c-m1)<=eps) &&
+ (fabs(alpha-m2)<=eps) && (fabs(beta-m2)<=eps) &&
+ (fabs(gamma-m2)<=eps))
+ c = 'R';
+ }
+ if (c!=spaceGroup[0]) {
+ if (c!='N') {
+ spaceGroupFix[0] = c;
+ return 1;
+ }
+ return -1;
+ }
+ return 0;
+ }
+
+ for (i=0;(i<6) && (k<0);i++)
+ if (!strcmp(spaceGroup,short_mono[i])) k = i;
+
+ if (k>=0) {
+ if ((fabs(alpha-90.0)<=eps) && (fabs(gamma-90.0)<=eps)) {
+ if (spaceGroup[0]=='B') return -1;
+ sprintf ( spaceGroupFix,"%c 1 %s 1",spaceGroup[0],
+ &(spaceGroup[2]) );
+ return 1;
+ }
+ if ((fabs(alpha-90.0)<=eps) && (fabs(beta-90.0)<=eps)) {
+ if (spaceGroup[0]=='C') return -1;
+ sprintf ( spaceGroupFix,"%c 1 1 %s",spaceGroup[0],
+ &(spaceGroup[2]) );
+ return 1;
+ }
+ return -1;
+ }
+
+ i = 0;
+ k = 0;
+ while (spaceGroup[i]) {
+ if (spaceGroup[i]!=' ') s[k++] = spaceGroup[i];
+ i++;
+ }
+ s[k] = char(0);
+
+ k = -1;
+ for (i=0;(i<16) && (k<0);i+=2)
+ if (!strcmp(s,special[i])) k = i;
+
+ if (k>=0) {
+ strcpy ( spaceGroupFix,special[k+1] );
+ return 1;
+ }
+
+ return 0;
+
+ }
+
+ ERROR_CODE Cryst::ConvertPDBString ( pstr PDBString ) {
+ // Interprets the ASCII PDB line and fills the corresponding fields.
+ // Returns zero if the line was converted, otherwise returns a
+ // non-negative value of Error_XXXX.
+ // PDBString must be not shorter than 81 characters.
+ PNCSMatrix ncsMtx;
+ PTVect tV;
+ ERROR_CODE RC;
+
+ // pad input line with spaces, if necessary
+ PadSpaces ( PDBString,80 );
+
+ if (!strncmp(PDBString,"CRYST",5)) {
+ // Here we check for "CRYST" and not for "CRYST1" keyword.
+ // As seems, people tend to not differentiating them.
+ if (GetReal(a,&(PDBString[6]) ,9) &&
+ GetReal(b,&(PDBString[15]),9) &&
+ GetReal(c,&(PDBString[24]),9))
+ WhatIsSet |= CSET_CellParams1;
+
+ if (GetReal(alpha,&(PDBString[33]),7) &&
+ GetReal(beta ,&(PDBString[40]),7) &&
+ GetReal(gamma,&(PDBString[47]),7))
+ WhatIsSet |= CSET_CellParams2;
+
+ GetString ( spaceGroup,&(PDBString[55]),11 );
+ CutSpaces ( spaceGroup,SCUTKEY_BEGEND );
+ if (fixSpaceGroup) FixSpaceGroup();
+ else strcpy ( spaceGroupFix,spaceGroup );
+ if (spaceGroupFix[0] && processSG) {
+ if (symOps.SetGroup(spaceGroupFix,syminfo_lib)==SYMOP_Ok)
+ WhatIsSet |= CSET_SpaceGroup;
+ }
+
+ if (GetInteger(Z,&(PDBString[66]),4))
+ WhatIsSet |= CSET_ZValue;
+
+ WhatIsSet &= 0xFBFF;
+
+ if ((a*b*c*alpha*beta*gamma==0.0) ||
+ ((a==1.0) && (b==1.0) && (c==1.0) &&
+ (alpha==90.0) && (beta==90.0) && (gamma==90.0) &&
+ (!strcmp(spaceGroup,"P 1")))) {
+ WhatIsSet &= ~(CSET_CellParams1 | CSET_CellParams2 |
+ CSET_SpaceGroup);
+ WhatIsSet |= CSET_DummyCell;
+ }
+
+ } else if (!strncmp(PDBString,"ORIGX1",6)) {
+
+ if (GetReal(o[0][0],&(PDBString[10]),10) &&
+ GetReal(o[0][1],&(PDBString[20]),10) &&
+ GetReal(o[0][2],&(PDBString[30]),10) &&
+ GetReal(t[0] ,&(PDBString[45]),10))
+ WhatIsSet |= CSET_OrigMatrix1;
+
+ } else if (!strncmp(PDBString,"ORIGX2",6)) {
+
+ if (GetReal(o[1][0],&(PDBString[10]),10) &&
+ GetReal(o[1][1],&(PDBString[20]),10) &&
+ GetReal(o[1][2],&(PDBString[30]),10) &&
+ GetReal(t[1] ,&(PDBString[45]),10))
+ WhatIsSet |= CSET_OrigMatrix2;
+
+ } else if (!strncmp(PDBString,"ORIGX3",6)) {
+
+ if (GetReal(o[2][0],&(PDBString[10]),10) &&
+ GetReal(o[2][1],&(PDBString[20]),10) &&
+ GetReal(o[2][2],&(PDBString[30]),10) &&
+ GetReal(t[2] ,&(PDBString[45]),10))
+ WhatIsSet |= CSET_OrigMatrix3;
+
+ } else if (!strncmp(PDBString,"SCALE1",6)) {
+
+ if (GetReal(s[0][0],&(PDBString[10]),10) &&
+ GetReal(s[0][1],&(PDBString[20]),10) &&
+ GetReal(s[0][2],&(PDBString[30]),10) &&
+ GetReal(u[0] ,&(PDBString[45]),10))
+ WhatIsSet |= CSET_ScaleMatrix1;
+ WhatIsSet &= 0xFBFF;
+ CellCheck |= CCHK_Unchecked;
+
+ } else if (!strncmp(PDBString,"SCALE2",6)) {
+
+ if (GetReal(s[1][0],&(PDBString[10]),10) &&
+ GetReal(s[1][1],&(PDBString[20]),10) &&
+ GetReal(s[1][2],&(PDBString[30]),10) &&
+ GetReal(u[1] ,&(PDBString[45]),10))
+ WhatIsSet |= CSET_ScaleMatrix2;
+ WhatIsSet &= 0xFBFF;
+ CellCheck |= CCHK_Unchecked;
+
+ } else if (!strncmp(PDBString,"SCALE3",6)) {
+
+ if (GetReal(s[2][0],&(PDBString[10]),10) &&
+ GetReal(s[2][1],&(PDBString[20]),10) &&
+ GetReal(s[2][2],&(PDBString[30]),10) &&
+ GetReal(u[2] ,&(PDBString[45]),10))
+ WhatIsSet |= CSET_ScaleMatrix3;
+ WhatIsSet &= 0xFBFF;
+ CellCheck |= CCHK_Unchecked;
+
+ } else if (!strncmp(PDBString,"MTRIX",5)) {
+
+ RC = ncsMatrix.AddMTRIXLine ( PDBString );
+ if (RC==Error_NCSM_WrongSerial) {
+ ncsMtx = new NCSMatrix();
+ RC = ncsMtx->ConvertPDBASCII ( PDBString );
+ if (RC==0) ncsMatrix.AddData ( ncsMtx );
+ else delete ncsMtx;
+ }
+ return RC;
+
+ } else if (!strncmp(PDBString,"TVECT ",6)) {
+
+ tV = new TVect();
+ RC = tV->ConvertPDBASCII(PDBString);
+ if (RC==0) tVect.AddData ( tV );
+ else delete tV;
+ return RC;
+
+ } else
+ return Error_WrongSection;
+
+ return Error_NoError;
+
+ }
+
+ void Cryst::PDBASCIIDump ( io::RFile f ) {
+ int i,j;
+ char S[100];
+
+ if (WhatIsSet & (CSET_CrystCard | CSET_DummyCell)) {
+ strcpy ( S,"CRYST1" );
+ PadSpaces ( S,80 );
+ if (WhatIsSet & CSET_CellParams1) {
+ PutRealF ( &(S[6 ]),a,9,3 );
+ PutRealF ( &(S[15]),b,9,3 );
+ PutRealF ( &(S[24]),c,9,3 );
+ }
+ if (WhatIsSet & CSET_CellParams2) {
+ PutRealF ( &(S[33]),alpha,7,2 );
+ PutRealF ( &(S[40]),beta ,7,2 );
+ PutRealF ( &(S[47]),gamma,7,2 );
+ }
+ if ((WhatIsSet & CSET_SpaceGroup) || (spaceGroup[0]))
+ strncpy ( &(S[55]),spaceGroup,IMin(11,strlen(spaceGroup)) );
+ if (WhatIsSet & CSET_ZValue)
+ PutInteger ( &(S[66]),Z,4 );
+ f.WriteLine ( S );
+ }
+
+ if ((WhatIsSet & CSET_OrigMatrix)==CSET_OrigMatrix)
+ for (i=0;i<3;i++) {
+ sprintf ( S,"ORIGX%1i",i+1);
+ PadSpaces ( S,80 );
+ for (j=0;j<3;j++)
+ PutRealF ( &(S[10+j*10]),o[i][j],10,6 );
+ PutRealF ( &(S[45]),t[i],10,5 );
+ f.WriteLine ( S );
+ }
+
+ if ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix)
+ for (i=0;i<3;i++) {
+ sprintf ( S,"SCALE%1i",i+1);
+ PadSpaces ( S,80 );
+ for (j=0;j<3;j++)
+ PutRealF ( &(S[10+j*10]),s[i][j],10,6 );
+ PutRealF ( &(S[45]),u[i],10,5 );
+ f.WriteLine ( S );
+ }
+
+ ncsMatrix.PDBASCIIDump ( f );
+ tVect .PDBASCIIDump ( f );
+
+ }
+
+
+ ERROR_CODE Cryst::GetCIF ( mmcif::PData CIF ) {
+ mmcif::PStruct cifStruct;
+ ERROR_CODE RC;
+
+ WhatIsSet = 0;
+
+ cifStruct = CIF->GetStructure ( CIFCAT_CELL );
+
+ if (cifStruct) {
+
+ RC = CIFGetReal ( a,cifStruct,CIFTAG_LENGTH_A );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( b,cifStruct,CIFTAG_LENGTH_B );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( c,cifStruct,CIFTAG_LENGTH_C );
+ if (RC==Error_UnrecognizedReal) return RC;
+ if (RC==Error_NoError) WhatIsSet |= CSET_CellParams1;
+
+ RC = CIFGetReal ( alpha,cifStruct,CIFTAG_ANGLE_ALPHA );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( beta,cifStruct,CIFTAG_ANGLE_BETA );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( gamma,cifStruct,CIFTAG_ANGLE_GAMMA );
+ if (RC==Error_UnrecognizedReal) return RC;
+ if (RC==Error_NoError) WhatIsSet |= CSET_CellParams2;
+
+ RC = CIFGetInteger ( Z,cifStruct,CIFTAG_Z_PDB );
+ if (RC==Error_UnrecognizedReal) return RC;
+ if (RC==Error_NoError) WhatIsSet |= CSET_ZValue;
+
+ }
+
+ cifStruct = CIF->GetStructure ( CIFCAT_SYMMETRY );
+ if (cifStruct) {
+ CIFGetString ( spaceGroup,cifStruct,CIFTAG_SPACE_GROUP_NAME_H_M,
+ sizeof(spaceGroup),pstr("") );
+ CutSpaces ( spaceGroup,SCUTKEY_BEGEND );
+ if (fixSpaceGroup) FixSpaceGroup();
+ else strcpy ( spaceGroupFix,spaceGroup );
+ /*
+ if (fixSpaceGroup) {
+ if (!strcasecmp(spaceGroup,"P 21"))
+ strcpy ( spaceGroup,"P 1 21 1" );
+ else if (!strcasecmp(spaceGroup,"C 2"))
+ strcpy ( spaceGroup,"C 1 2 1" );
+ }
+ */
+ if (spaceGroupFix[0] && processSG) {
+ if (symOps.SetGroup(spaceGroupFix,syminfo_lib)==SYMOP_Ok)
+ WhatIsSet |= CSET_SpaceGroup;
+ }
+ }
+
+ if ((a*b*c*alpha*beta*gamma==0.0) ||
+ ((a==1.0) && (b==1.0) && (c==1.0) &&
+ (alpha==90.0) && (beta==90.0) && (gamma==90.0) &&
+ (!strcmp(spaceGroup,"P 1")))) {
+ WhatIsSet &= ~(CSET_CellParams1 | CSET_CellParams2 |
+ CSET_SpaceGroup);
+ WhatIsSet |= CSET_DummyCell;
+ }
+
+ cifStruct = CIF->GetStructure ( CIFCAT_DATABASE_PDB_MATRIX );
+ if (cifStruct) {
+ RC = CIFGetReal ( o[0][0],cifStruct,CIFTAG_ORIGX11 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( o[0][1],cifStruct,CIFTAG_ORIGX12 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( o[0][2],cifStruct,CIFTAG_ORIGX13 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( o[1][0],cifStruct,CIFTAG_ORIGX21 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( o[1][1],cifStruct,CIFTAG_ORIGX22 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( o[1][2],cifStruct,CIFTAG_ORIGX23 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( o[2][0],cifStruct,CIFTAG_ORIGX31 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( o[2][1],cifStruct,CIFTAG_ORIGX32 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( o[2][2],cifStruct,CIFTAG_ORIGX33 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( t[0],cifStruct,CIFTAG_ORIGX_VECTOR1 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( t[1],cifStruct,CIFTAG_ORIGX_VECTOR2 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal ( t[2],cifStruct,CIFTAG_ORIGX_VECTOR3 );
+ if (RC!=Error_NoError) return RC;
+ WhatIsSet |= CSET_OrigMatrix;
+ }
+
+ cifStruct = CIF->GetStructure ( CIFCAT_ATOM_SITES );
+ if (cifStruct) {
+ RC = CIFGetReal ( s[0][0],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX11 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal(s[0][1],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX12);
+ if (RC==Error_NoError)
+ RC = CIFGetReal(s[0][2],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX13);
+ if (RC==Error_NoError)
+ RC = CIFGetReal(s[1][0],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX21);
+ if (RC==Error_NoError)
+ RC = CIFGetReal(s[1][1],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX22);
+ if (RC==Error_NoError)
+ RC = CIFGetReal(s[1][2],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX23);
+ if (RC==Error_NoError)
+ RC = CIFGetReal(s[2][0],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX31);
+ if (RC==Error_NoError)
+ RC = CIFGetReal(s[2][1],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX32);
+ if (RC==Error_NoError)
+ RC = CIFGetReal(s[2][2],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX33);
+ if (RC==Error_NoError)
+ RC = CIFGetReal(u[0] ,cifStruct,CIFTAG_FRACT_TRANSF_VECTOR1 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal(u[1] ,cifStruct,CIFTAG_FRACT_TRANSF_VECTOR2 );
+ if (RC==Error_NoError)
+ RC = CIFGetReal(u[2] ,cifStruct,CIFTAG_FRACT_TRANSF_VECTOR3 );
+ if (RC!=Error_NoError) return RC;
+ WhatIsSet |= CSET_ScaleMatrix;
+ }
+
+ RC = ncsMatrix.GetCIF(CIF,ClassID_NCSMatrix);
+ if (RC!=Error_NoError) return RC;
+
+ RC = tVect.GetCIF(CIF,ClassID_TVect);
+ return RC;
+
+ }
+
+ void Cryst::MakeCIF ( mmcif::PData CIF ) {
+ mmcif::PStruct cifStruct;
+ char S[200];
+
+ if (WhatIsSet & (CSET_CellParams1 | CSET_DummyCell)) {
+ CIF->AddStructure ( CIFCAT_CELL,cifStruct );
+ cifStruct->PutReal ( a,CIFTAG_LENGTH_A,8 );
+ cifStruct->PutReal ( b,CIFTAG_LENGTH_B,8 );
+ cifStruct->PutReal ( c,CIFTAG_LENGTH_C,8 );
+ }
+
+ if (WhatIsSet & (CSET_CellParams2 | CSET_DummyCell)) {
+ CIF->AddStructure ( CIFCAT_CELL,cifStruct );
+ cifStruct->PutReal ( alpha,CIFTAG_ANGLE_ALPHA,8 );
+ cifStruct->PutReal ( beta ,CIFTAG_ANGLE_BETA, 8 );
+ cifStruct->PutReal ( gamma,CIFTAG_ANGLE_GAMMA,8 );
+ }
+
+ if ((WhatIsSet & (CSET_SpaceGroup | CSET_DummyCell)) ||
+ (spaceGroup[0]))
+ CIF->PutString ( strcpy_cs(S,spaceGroup),CIFCAT_SYMMETRY,
+ CIFTAG_SPACE_GROUP_NAME_H_M );
+
+ if (WhatIsSet & (CSET_ZValue | CSET_DummyCell))
+ CIF->PutInteger ( Z,CIFCAT_CELL,CIFTAG_Z_PDB );
+
+
+ if ((WhatIsSet & CSET_OrigMatrix)==CSET_OrigMatrix) {
+ CIF->AddStructure ( CIFCAT_DATABASE_PDB_MATRIX,cifStruct );
+ cifStruct->PutReal ( o[0][0],CIFTAG_ORIGX11 ,8 );
+ cifStruct->PutReal ( o[0][1],CIFTAG_ORIGX12 ,8 );
+ cifStruct->PutReal ( o[0][2],CIFTAG_ORIGX13 ,8 );
+ cifStruct->PutReal ( o[1][0],CIFTAG_ORIGX21 ,8 );
+ cifStruct->PutReal ( o[1][1],CIFTAG_ORIGX22 ,8 );
+ cifStruct->PutReal ( o[1][2],CIFTAG_ORIGX23 ,8 );
+ cifStruct->PutReal ( o[2][0],CIFTAG_ORIGX31 ,8 );
+ cifStruct->PutReal ( o[2][1],CIFTAG_ORIGX32 ,8 );
+ cifStruct->PutReal ( o[2][2],CIFTAG_ORIGX33 ,8 );
+ cifStruct->PutReal ( t[0] ,CIFTAG_ORIGX_VECTOR1,8 );
+ cifStruct->PutReal ( t[1] ,CIFTAG_ORIGX_VECTOR2,8 );
+ cifStruct->PutReal ( t[2] ,CIFTAG_ORIGX_VECTOR3,8 );
+ }
+
+ if ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix) {
+ CIF->AddStructure ( CIFCAT_ATOM_SITES,cifStruct );
+ cifStruct->PutReal ( s[0][0],CIFTAG_FRACT_TRANSF_MATRIX11,8 );
+ cifStruct->PutReal ( s[0][1],CIFTAG_FRACT_TRANSF_MATRIX12,8 );
+ cifStruct->PutReal ( s[0][2],CIFTAG_FRACT_TRANSF_MATRIX13,8 );
+ cifStruct->PutReal ( s[1][0],CIFTAG_FRACT_TRANSF_MATRIX21,8 );
+ cifStruct->PutReal ( s[1][1],CIFTAG_FRACT_TRANSF_MATRIX22,8 );
+ cifStruct->PutReal ( s[1][2],CIFTAG_FRACT_TRANSF_MATRIX23,8 );
+ cifStruct->PutReal ( s[2][0],CIFTAG_FRACT_TRANSF_MATRIX31,8 );
+ cifStruct->PutReal ( s[2][1],CIFTAG_FRACT_TRANSF_MATRIX32,8 );
+ cifStruct->PutReal ( s[2][2],CIFTAG_FRACT_TRANSF_MATRIX33,8 );
+ cifStruct->PutReal ( u[0] ,CIFTAG_FRACT_TRANSF_VECTOR1 ,8 );
+ cifStruct->PutReal ( u[1] ,CIFTAG_FRACT_TRANSF_VECTOR2 ,8 );
+ cifStruct->PutReal ( u[2] ,CIFTAG_FRACT_TRANSF_VECTOR3 ,8 );
+ }
+
+ ncsMatrix.MakeCIF ( CIF );
+ tVect .MakeCIF ( CIF );
+
+ }
+
+
+
+ cpstr OrthCode[6] = {
+ cpstr("A/X0, C*/Z0"), // (standard brookhaven)
+ cpstr("B/X0, A*/Z0"),
+ cpstr("C/X0, B*/Z0"),
+ cpstr("HEX A+B/X0, C*/Z0"),
+ cpstr("A*/X0, C/Z0 (rollett)"),
+ cpstr("A/X0, B*/Y0")
+ };
+
+ cpstr getOrthCodeName ( int NCode ) {
+ if ((NCode>0) && (NCode<=6)) return OrthCode[NCode-1];
+ return cpstr("CUSTOM");
+ }
+
+ void Cryst::CalcCoordTransforms() {
+ realtype rChk1,rChk2,Fac;
+ int i,j,k;
+
+ WhatIsSet &= ~CSET_Transforms; // clear the flag
+
+ if ((WhatIsSet & CSET_CellParams)==CSET_CellParams) {
+ // The 'cryst1' card was supplied. Calculate
+ // standard orthogonalizations.
+
+ CalcOrthMatrices();
+ if (NCode<0) NCode = 0;
+
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ RO[i][j] = RR[NCode][i][j];
+ RO[i][3] = 0.0;
+ RO[3][i] = 0.0;
+ }
+ RO[3][3] = 1.0;
+ Mat4Inverse ( RO,RF );
+
+ WhatIsSet |= CSET_Transforms;
+
+ if (ignoreScalei)
+ CellCheck = CCHK_Ok;
+ else if ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix) {
+ // All 'scalei' cards were supplied. Calculate
+ // rotation and translation matrices and check
+ // if they are in consistence with the cell.
+
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ RF[i][j] = s[i][j];
+ RF[i][3] = u[i];
+ RF[3][i] = 0.0;
+ }
+ RF[3][3] = 1.0;
+ Mat4Inverse ( RF,RO );
+
+ // Find orthogonalisation type
+ VolChk = RO[0][0]*(RO[1][1]*RO[2][2] - RO[1][2]*RO[2][1]) +
+ RO[0][1]*(RO[1][2]*RO[2][0] - RO[1][0]*RO[2][2]) +
+ RO[0][2]*(RO[1][0]*RO[2][1] - RO[1][1]*RO[2][0]);
+
+ CellCheck = CCHK_Ok;
+ if (Vol>0.0) {
+ VolErr = fabs(VolChk-Vol)/Vol;
+ if (VolErr>0.02) CellCheck |= CCHK_Error;
+ else if (VolErr>0.1) CellCheck |= CCHK_Disagreement;
+ } else
+ CellCheck |= CCHK_NoCell;
+
+ // try to find NCode
+ NCode = -1;
+ for (k=0;(k<6) && (NCode<0);k++) {
+ NCode = k;
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++) {
+ rChk1 = RO[i][j] + RR[k][i][j];
+ rChk2 = RO[i][j] - RR[k][i][j];
+ if (fabs(rChk1)>=0.1) {
+ if (fabs(rChk2/rChk1)>0.01)
+ NCode = -1;
+ }
+ }
+ }
+
+ // Correct inaccuracy of SCALEi input due to FORMAT,
+ // replace RF,RO with RR[NCode][][] if possible.
+
+ if (NCode>=0) {
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++)
+ RO[i][j] = RR[NCode][i][j];
+ Mat4Inverse ( RO,RF );
+ } else
+ CellCheck |= CCHK_NoOrthCode;
+
+ if ((u[0]!=0.0) || (u[1]!=0.0) || (u[2]!=0.0))
+ CellCheck |= CCHK_Translations;
+
+ }
+
+ // Generate ROU and RFU for AnisoU stuff
+ RFU[3][3] = 1.0;
+ for (i=0;i<3;i++) {
+ Fac = sqrt(RF[i][0]*RF[i][0] + RF[i][1]*RF[i][1] +
+ RF[i][2]*RF[i][2]);
+ RFU[i][0] = RF[i][0]/Fac;
+ RFU[i][1] = RF[i][1]/Fac;
+ RFU[i][2] = RF[i][2]/Fac;
+ RFU[i][3] = 0.0;
+ RFU[3][i] = 0.0;
+ }
+ RFU[3][3] = 1.0;
+ Mat4Inverse ( RFU,ROU );
+
+ } else
+ CellCheck |= CCHK_NoCell;
+
+ }
+
+
+ void Cryst::RWBROOKReadPrintout() {
+ int i,j;
+
+ if ((WhatIsSet & CSET_CellParams)==CSET_CellParams) {
+ printf ( " MATRICES DERIVED FROM CRYST1"
+ " CARD IN COORDINATE FILE\n\n\n"
+ " RF "
+ " RO\n\n" );
+ for (i=0;i<4;i++) {
+ printf ( " " );
+ for (j=0;j<4;j++)
+ printf ( "%8.3f",RF[i][j] );
+ printf ( " " );
+ for (j=0;j<4;j++)
+ printf ( "%8.3f",RO[i][j] );
+ printf ( "\n" );
+ }
+ printf ( "\n" );
+ } else
+ printf ( "\n $WARNING: NO CRYST CARDS READ$\n" );
+
+ if ((WhatIsSet & CSET_ScaleMatrix)!=CSET_ScaleMatrix)
+ printf ( "\n $WARNING: NO SCALE CARDS READ$\n" );
+
+ }
+
+
+ void Cryst::CalcOrthMatrices() {
+ // Calculates matrices for standard orthogonalizations
+ // and the cell volume.
+ // The matrices are stored in array RR
+ realtype Conv,Alph,Bet,Gamm,Sum,V;
+ realtype sinA,cosA,sinB,cosB,sinG,cosG;
+ realtype sinAS,cosAS,sinBS,cosBS,sinGS,cosGS;
+ int i,j,k;
+
+ if ((WhatIsSet & CSET_CellParams)!=CSET_CellParams) return;
+
+ Conv = Pi/180.0;
+
+ Alph = alpha*Conv;
+ Bet = beta *Conv;
+ Gamm = gamma*Conv;
+
+ Sum = (Alph+Bet+Gamm)*0.5;
+
+ V = sqrt(sin(Sum-Alph)*sin(Sum-Bet)*sin(Sum-Gamm)*sin(Sum));
+
+ Vol = 2.0*a*b*c*V;
+
+ // Precaution measure for erratic use of the library
+ if ((fabs(Alph)<1.0e-6) || (fabs(Bet)<1.0e-6) ||
+ (fabs(Gamm)<1.0e-6)) {
+ as = 0.0;
+ bs = 0.0;
+ cs = 0.0;
+ alphas = 0.0;
+ betas = 0.0;
+ gammas = 0.0;
+ for (k=0;k<6;k++) {
+ AC[k] = 0.0;
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ RR[k][i][j] = 0.0;
+ RR[k][i][i] = 1.0;
+ }
+ }
+ return;
+ }
+
+ sinA = sin(Alph);
+ cosA = cos(Alph);
+ sinB = sin(Bet);
+ cosB = cos(Bet);
+ sinG = sin(Gamm);
+ cosG = cos(Gamm);
+
+ cosAS = (cosG*cosB-cosA) / (sinB*sinG);
+ sinAS = sqrt(1.0-cosAS*cosAS);
+ cosBS = (cosA*cosG-cosB) / (sinA*sinG);
+ sinBS = sqrt(1.0-cosBS*cosBS);
+ cosGS = (cosA*cosB-cosG) / (sinA*sinB);
+ sinGS = sqrt(1.0-cosGS*cosGS);
+
+ as = b*c*sinA/Vol;
+ bs = c*a*sinB/Vol;
+ cs = a*b*sinG/Vol;
+ alphas = atan2(sinAS,cosAS)/Conv;
+ betas = atan2(sinBS,cosBS)/Conv;
+ gammas = atan2(sinGS,cosGS)/Conv;
+
+ // ---- Set useful things for calculating dstar
+
+ AC[0] = as*as;
+ AC[1] = bs*bs;
+ AC[2] = cs*cs;
+ AC[3] = 2.0*bs*cs*cosAS;
+ AC[4] = 2.0*cs*as*cosBS;
+ AC[5] = 2.0*as*bs*cosGS;
+
+ // ---- Zero matrices
+
+ for (k=0;k<6;k++)
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++)
+ RR[k][i][j] = 0.0;
+
+ // ---- Calculate matrices
+
+ // ---- XO along a Zo along c*
+
+ RR[0][0][0] = a;
+ RR[0][0][1] = b*cosG;
+ RR[0][0][2] = c*cosB;
+ RR[0][1][1] = b*sinG;
+ RR[0][1][2] = -c*sinB*cosAS;
+ RR[0][2][2] = c*sinB*sinAS;
+
+ // ---- XO along b Zo along a*
+
+ RR[1][0][0] = a*cosG;
+ RR[1][0][1] = b;
+ RR[1][0][2] = c*cosA;
+ RR[1][1][0] = -a*sinG*cosBS;
+ RR[1][1][2] = c*sinA;
+ RR[1][2][0] = a*sinG*sinBS;
+
+ // ---- XO along c Zo along b*
+
+ RR[2][0][0] = a*cosB;
+ RR[2][0][1] = b*cosA;
+ RR[2][0][2] = c;
+ RR[2][1][0] = a*sinB;
+ RR[2][1][1] = -b*sinA*cosGS;
+ RR[2][2][1] = b*sinA*sinGS;
+
+ // ---- trigonal only - XO along a+b YO alon a-b Zo along c*
+
+ RR[3][0][0] = a/2.0;
+ RR[3][0][1] = a/2.0;
+ RR[3][1][0] = -a*sinG;
+ RR[3][1][1] = a*sinG;
+ RR[3][2][2] = c;
+
+ // ---- XO along a*, ZO along c
+
+ RR[4][0][0] = a*sinB*sinGS;
+ RR[4][1][0] = -a*sinB*cosGS;
+ RR[4][1][1] = b*sinA;
+ RR[4][2][0] = a*cosB;
+ RR[4][2][1] = b*cosA;
+ RR[4][2][2] = c;
+
+ // ---- Grr*! to Gerard Bricogne - his setting for P1 in SKEW.
+ // XO along a, Y0 along b*
+
+ RR[5][0][0] = a;
+ RR[5][0][1] = b*cosG;
+ RR[5][0][2] = c*cosB;
+ RR[5][1][1] = b*sinG*sinAS;
+ RR[5][2][1] = -b*sinG*cosAS;
+ RR[5][2][2] = c*sinB;
+
+ }
+
+
+ bool Cryst::areMatrices() {
+ // returns true if the orthogonal-to-fractional and
+ // fractional-to-orthogonal matrices are defined
+ return (WhatIsSet & CSET_Transforms)!=0x0000;
+ }
+
+
+ bool Cryst::Frac2Orth (
+ realtype x, realtype y, realtype z,
+ realtype & xx, realtype & yy, realtype & zz ) {
+ if (areMatrices()) {
+ xx = RO[0][0]*x + RO[0][1]*y + RO[0][2]*z + RO[0][3];
+ yy = RO[1][0]*x + RO[1][1]*y + RO[1][2]*z + RO[1][3];
+ zz = RO[2][0]*x + RO[2][1]*y + RO[2][2]*z + RO[2][3];
+ return true;
+ } else {
+ xx = x;
+ yy = y;
+ zz = z;
+ return false;
+ }
+ }
+
+ bool Cryst::Orth2Frac (
+ realtype x, realtype y, realtype z,
+ realtype & xx, realtype & yy, realtype & zz ) {
+ if (areMatrices()) {
+ xx = RF[0][0]*x + RF[0][1]*y + RF[0][2]*z + RF[0][3];
+ yy = RF[1][0]*x + RF[1][1]*y + RF[1][2]*z + RF[1][3];
+ zz = RF[2][0]*x + RF[2][1]*y + RF[2][2]*z + RF[2][3];
+ return true;
+ } else {
+ xx = x;
+ yy = y;
+ zz = z;
+ return false;
+ }
+ }
+
+
+ bool Cryst::Frac2Orth ( mat44 & F, mat44 & T ) {
+ mat44 A;
+ if (areMatrices()) {
+ Mat4Mult ( A,F,RF );
+ Mat4Mult ( T,RO,A );
+ return true;
+ } else {
+ Mat4Init ( T );
+ return false;
+ }
+ }
+
+
+ bool Cryst::Orth2Frac ( mat44 & T, mat44 & F ) {
+ mat44 A;
+ if (areMatrices()) {
+ Mat4Mult ( A,T,RO );
+ Mat4Mult ( F,RF,A );
+ return true;
+ } else {
+ Mat4Init ( F );
+ return false;
+ }
+ }
+
+
+ int Cryst::GetNumberOfSymOps() {
+ return symOps.GetNofSymOps();
+ }
+
+ pstr Cryst::GetSymOp ( int Nop ) {
+ return symOps.GetSymOp ( Nop );
+ }
+
+
+ int Cryst::GetTMatrix ( mat44 & TMatrix, int Nop,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c, PSymOps symOpers ) {
+ //
+ // GetTMatrix(..) calculates and returns the coordinate transformation
+ // matrix, which converts orthogonal coordinates according to the
+ // symmetry operation Nop and places them into unit cell shifted by
+ // cellshift_a a's, cellshift_b b's and cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ //
+ mat44 fm;
+ int i,j,k;
+
+ if (cellshift_a<=-MaxInt4) {
+ k = GetFractMatrix ( fm,Nop,0,0,0,symOpers );
+ fm[0][3] = frac(fm[0][3]);
+ fm[1][3] = frac(fm[1][3]);
+ fm[2][3] = frac(fm[2][3]);
+ } else
+ k = GetFractMatrix ( fm,Nop,cellshift_a,cellshift_b,cellshift_c,
+ symOpers );
+
+ if (k) {
+ Mat4Init ( TMatrix );
+ return k;
+ }
+
+ // transformation back to orthogonal coordinates
+ for (i=0;i<3;i++) {
+ for (j=0;j<4;j++) {
+ TMatrix[i][j] = 0.0;
+ for (k=0;k<3;k++)
+ TMatrix[i][j] += RO[i][k]*fm[k][j];
+ }
+ TMatrix[i][3] += RO[i][3];
+ }
+
+ TMatrix[3][0] = 0.0;
+ TMatrix[3][1] = 0.0;
+ TMatrix[3][2] = 0.0;
+ TMatrix[3][3] = 1.0;
+
+ return 0;
+
+ }
+
+
+ int Cryst::GetUCTMatrix ( mat44 & TMatrix, int Nop,
+ realtype x, realtype y, realtype z,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c, PSymOps symOpers ) {
+ //
+ // GetUCTMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts orthogonal coordinates
+ // according to the symmetry operation Nop. Translation part of
+ // the matrix is being chosen such that point (x,y,z) has least
+ // distance to the center of primary (333) unit cell, and then
+ // it is shifted by cellshift_a a's, cellshift_b b's and
+ // cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ //
+ mat44 fm,tm;
+ vect3 ft;
+ realtype x0,y0,z0, dx,dy,dz, d,d0;
+ int i,j,k, ic,jc,kc;
+
+ k = GetFractMatrix ( fm,Nop,0,0,0,symOpers );
+ if (k) {
+ Mat4Init ( TMatrix );
+ return k;
+ }
+
+ fm[0][3] = frac(fm[0][3]) + cellshift_a;
+ fm[1][3] = frac(fm[1][3]) + cellshift_b;
+ fm[2][3] = frac(fm[2][3]) + cellshift_c;
+
+ Frac2Orth ( cellshift_a+0.5,cellshift_b+0.5,cellshift_c+0.5,
+ x0,y0,z0 );
+
+ // transformation back to orthogonal coordinates
+
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++) {
+ tm[i][j] = 0.0;
+ for (k=0;k<3;k++)
+ tm[i][j] += RO[i][k]*fm[k][j];
+ }
+ tm[3][0] = 0.0;
+ tm[3][1] = 0.0;
+ tm[3][2] = 0.0;
+ tm[3][3] = 1.0;
+
+ d0 = MaxReal;
+ for (ic=-3;ic<3;ic++)
+ for (jc=-3;jc<3;jc++)
+ for (kc=-3;kc<3;kc++) {
+ ft[0] = fm[0][3] + ic;
+ ft[1] = fm[1][3] + jc;
+ ft[2] = fm[2][3] + kc;
+ for (i=0;i<3;i++) {
+ tm[i][3] = 0.0;
+ for (k=0;k<3;k++)
+ tm[i][3] += RO[i][k]*ft[k];
+ tm[i][3] += RO[i][3];
+ }
+ dx = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + tm[0][3] - x0;
+ dy = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + tm[1][3] - y0;
+ dz = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + tm[2][3] - z0;
+ d = dx*dx + dy*dy + dz*dz;
+ if (d<d0) {
+ d0 = d;
+ Mat4Copy ( tm,TMatrix );
+ }
+ }
+
+ return 0;
+
+ }
+
+
+ int Cryst::GetFractMatrix ( mat44 & TMatrix, int Nop,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c,
+ PSymOps symOpers ) {
+ //
+ // GetFractMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts fractional coordinates
+ // according to the symmetry operation Nop and places them into
+ // unit cell shifted by cellshift_a a's, cellshift_b b's and
+ // cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ //
+ mat44 tm;
+ int i,j,k;
+
+ k = 0;
+ if (symOpers) k = symOpers->GetTMatrix ( tm,Nop );
+ else k = symOps.GetTMatrix ( tm,Nop );
+ if (!k) {
+ if (!areMatrices()) k = 2;
+ if (!isCellParameters()) k = 3;
+ } else
+ k = 1;
+
+ if (k) {
+ Mat4Init ( TMatrix );
+ return k;
+ }
+
+ // transformation to fractional coordinates + symmetry operation
+ for (i=0;i<3;i++) {
+ for (j=0;j<4;j++) {
+ TMatrix[i][j] = 0.0;
+ for (k=0;k<3;k++)
+ TMatrix[i][j] += tm[i][k]*RF[k][j];
+ }
+ TMatrix[i][3] += tm[i][3]; // symmetry operation shift
+ }
+
+ // cell shift
+ TMatrix[0][3] += cellshift_a;
+ TMatrix[1][3] += cellshift_b;
+ TMatrix[2][3] += cellshift_c;
+
+ TMatrix[3][0] = 0.0;
+ TMatrix[3][1] = 0.0;
+ TMatrix[3][2] = 0.0;
+ TMatrix[3][3] = 1.0;
+
+ return 0;
+
+ }
+
+ int Cryst::GetSymOpMatrix ( mat44 & TMatrix, int Nop ) {
+ //
+ // GetSymOpMatrix(..) returns the transformation matrix for
+ // Nop-th symmetry operator in the space group
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ //
+ return symOps.GetTMatrix ( TMatrix,Nop );
+ }
+
+
+ bool Cryst::Cryst2Orth ( rvector U ) {
+ mat33 A,AT,Tmp,TmpMat;
+ realtype BB;
+ int i,j,k;
+
+ if (areMatrices()) {
+
+ Tmp[0][0] = U[0];
+ Tmp[1][1] = U[1];
+ Tmp[2][2] = U[2];
+ Tmp[0][1] = U[3];
+ Tmp[1][0] = U[3];
+ Tmp[0][2] = U[4];
+ Tmp[2][0] = U[4];
+ Tmp[1][2] = U[5];
+ Tmp[2][1] = U[5];
+
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++) {
+ A [j][i] = ROU[j][i];
+ AT[i][j] = ROU[j][i];
+ }
+
+ // TmpMat = Tmp*AT
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++) {
+ BB = 0.0;
+ for (k=0;k<3;k++)
+ BB += Tmp[i][k]*AT[k][j];
+ TmpMat[i][j] = BB;
+ }
+
+ // Tmp = A*TmpMat
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++) {
+ BB = 0.0;
+ for (k=0;k<3;k++)
+ BB += A[i][k]*TmpMat[k][j];
+ Tmp[i][j] = BB;
+ }
+
+ U[0] = Tmp[0][0];
+ U[1] = Tmp[1][1];
+ U[2] = Tmp[2][2];
+ U[3] = Tmp[0][1];
+ U[4] = Tmp[0][2];
+ U[5] = Tmp[1][2];
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+
+ bool Cryst::Orth2Cryst ( rvector U ) {
+ mat33 A,AT,Tmp,TmpMat;
+ realtype BB;
+ int i,j,k;
+
+ if (areMatrices()) {
+
+ Tmp[0][0] = U[0];
+ Tmp[1][1] = U[1];
+ Tmp[2][2] = U[2];
+ Tmp[0][1] = U[3];
+ Tmp[1][0] = U[3];
+ Tmp[0][2] = U[4];
+ Tmp[2][0] = U[4];
+ Tmp[1][2] = U[5];
+ Tmp[2][1] = U[5];
+
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++) {
+ A [j][i] = RFU[j][i];
+ AT[i][j] = RFU[j][i];
+ }
+
+ // TmpMat = Tmp*AT
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++) {
+ BB = 0.0;
+ for (k=0;k<3;k++)
+ BB += Tmp[i][k]*AT[k][j];
+ TmpMat[i][j] = BB;
+ }
+
+ // Tmp = A*TmpMat
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++) {
+ BB = 0.0;
+ for (k=0;k<3;k++)
+ BB += A[i][k]*TmpMat[k][j];
+ Tmp[i][j] = BB;
+ }
+
+ U[0] = Tmp[0][0];
+ U[1] = Tmp[1][1];
+ U[2] = Tmp[2][2];
+ U[3] = Tmp[0][1];
+ U[4] = Tmp[0][2];
+ U[5] = Tmp[1][2];
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+
+ void Cryst::SetCell ( realtype cell_a,
+ realtype cell_b,
+ realtype cell_c,
+ realtype cell_alpha,
+ realtype cell_beta,
+ realtype cell_gamma,
+ int OrthCode ) {
+ // this function should be used for changing the cell parameters
+ int i,j;
+
+ if ((cell_a>0.0) && (cell_b>0.0) && (cell_c>0.0) &&
+ (cell_alpha!=0.0) && (cell_beta!=0.0) && (cell_gamma!=0.0)) {
+
+ if (OrthCode>0) NCode = OrthCode-1;
+ else NCode = 0;
+
+ a = cell_a;
+ b = cell_b;
+ c = cell_c;
+ alpha = cell_alpha;
+ beta = cell_beta;
+ gamma = cell_gamma;
+
+ WhatIsSet |= CSET_CellParams;
+
+ // calculate matrices
+
+ for (i=0;i<4;i++) {
+ for (j=0;j<4;j++) {
+ RO [i][j] = 0.0;
+ RF [i][j] = 0.0;
+ ROU[i][j] = 0.0;
+ RFU[i][j] = 0.0;
+ }
+ RO [i][i] = 1.0;
+ RF [i][i] = 1.0;
+ ROU[i][i] = 1.0;
+ RFU[i][i] = 1.0;
+ }
+
+ CalcCoordTransforms();
+
+ if (!(CellCheck & CCHK_NoOrthCode)) {
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ RO[i][j] = RR[NCode][i][j];
+ RO[i][3] = 0.0;
+ RO[3][i] = 0.0;
+ }
+ RO[3][3] = 1.0;
+ Mat4Inverse ( RO,RF );
+ }
+
+ WhatIsSet |= CSET_Transforms;
+
+ } else
+
+ WhatIsSet &= ~(CSET_CellParams | CSET_Transforms);
+
+ }
+
+ void Cryst::SetSyminfoLib ( cpstr syminfoLib ) {
+ CreateCopy ( syminfo_lib,syminfoLib );
+ }
+
+ pstr Cryst::GetSyminfoLib() {
+ return syminfo_lib;
+ }
+
+ int Cryst::SetSpaceGroup ( cpstr spGroup ) {
+ // This function does not attempt to fix the space group
+ int RC,l;
+ RC = SYMOP_UnknownSpaceGroup;
+ WhatIsSet &= ~CSET_SpaceGroup;
+ if (spGroup) {
+ if (spGroup[0]) {
+ l = IMin ( strlen(spGroup),sizeof(spaceGroup)-1 );
+ strcpy_ncss ( spaceGroup,spGroup,l );
+ strcpy ( spaceGroupFix,spaceGroup );
+ if (spaceGroup[0]) {
+ RC = symOps.SetGroup ( spaceGroup,syminfo_lib );
+ // RC = SymOps.SetGroup ( spGroup,syminfo_lib );
+ // strncpy ( spaceGroup,spGroup,l );
+ // spaceGroup[l] = char(0);
+ if (RC==SYMOP_Ok) WhatIsSet |= CSET_SpaceGroup;
+ }
+ }
+ }
+ return RC;
+ }
+
+
+ void Cryst::PutCell ( realtype cell_a,
+ realtype cell_b,
+ realtype cell_c,
+ realtype cell_alpha,
+ realtype cell_beta,
+ realtype cell_gamma,
+ int OrthCode ) {
+ // this function should be used for setting the cell parameters
+ int i,j;
+
+ if ((cell_a!=0.0) || (OrthCode>0)) {
+ a = cell_a;
+ b = cell_b;
+ c = cell_c;
+ alpha = cell_alpha;
+ beta = cell_beta;
+ gamma = cell_gamma;
+ WhatIsSet |= CSET_CellParams;
+ }
+
+ if (OrthCode>0) {
+
+ // calculate matrices
+
+ NCode = OrthCode-1;
+ CalcOrthMatrices();
+
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ RO[i][j] = RR[NCode][i][j];
+ RO[i][3] = 0.0;
+ RO[3][i] = 0.0;
+ }
+ RO[3][3] = 1.0;
+
+ Mat4Inverse ( RO,RF );
+
+ WhatIsSet |= CSET_Transforms;
+
+ } else
+ WhatIsSet &= ~CSET_Transforms;
+
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ s[i][j] = RF[i][j];
+ u[i] = RF[i][3];
+ }
+
+ WhatIsSet |= CSET_ScaleMatrix;
+
+ }
+
+
+ bool Cryst::isScaleMatrix() {
+ return ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix);
+ }
+
+ bool Cryst::isCellParameters() {
+ return ((WhatIsSet & CSET_CellParams)==CSET_CellParams);
+ }
+
+ bool Cryst::isNCSMatrix() {
+ return (ncsMatrix.Length()>0);
+ }
+
+ int Cryst::GetNumberOfNCSMatrices() {
+ return ncsMatrix.Length();
+ }
+
+ int Cryst::GetNumberOfNCSMates() {
+ // Returns the number of NCS mates not given in the file (iGiven==0)
+ int i,l,iG;
+ PNCSMatrix NCSM;
+ iG = 0;
+ l = ncsMatrix.Length();
+ for (i=0;i<l;i++) {
+ NCSM = PNCSMatrix(ncsMatrix.GetContainerClass(i));
+ if (NCSM) {
+ if (!NCSM->iGiven) iG++;
+ }
+ }
+ return iG;
+ }
+
+ bool Cryst::GetNCSMatrix ( int NCSMatrixNo,
+ mat33 & ncs_m, vect3 & ncs_v ) {
+ int i,j;
+ PNCSMatrix NCSM;
+ NCSM = PNCSMatrix(ncsMatrix.GetContainerClass(NCSMatrixNo));
+ if (NCSM) {
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ ncs_m[i][j] = NCSM->m[i][j];
+ ncs_v[i] = NCSM->v[i];
+ }
+ return true;
+ }
+ return false;
+ }
+
+ bool Cryst::GetNCSMatrix ( int NCSMatrixNo,
+ mat44 & ncs_m, int & iGiven ) {
+ int i,j;
+ PNCSMatrix NCSM;
+ NCSM = PNCSMatrix(ncsMatrix.GetContainerClass(NCSMatrixNo));
+ if (NCSM) {
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ ncs_m[i][j] = NCSM->m[i][j];
+ ncs_m[i][3] = NCSM->v[i];
+ }
+ ncs_m[3][0] = 0.0;
+ ncs_m[3][1] = 0.0;
+ ncs_m[3][2] = 0.0;
+ ncs_m[3][3] = 1.0;
+ iGiven = NCSM->iGiven;
+ return true;
+ } else {
+ for (i=0;i<4;i++) {
+ for (j=0;j<4;j++)
+ ncs_m[i][j] = 0.0;
+ ncs_m[i][i] = 1.0;
+ }
+ return false;
+ }
+ }
+
+ int Cryst::AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v,
+ int iGiven ) {
+ PNCSMatrix ncsMtx;
+ ncsMtx = new NCSMatrix();
+ ncsMtx->SetNCSMatrix ( ncsMatrix.Length()+1,ncs_m,ncs_v,iGiven );
+ ncsMatrix.AddData ( ncsMtx );
+ return ncsMtx->serNum;
+ }
+
+ void Cryst::GetRCell ( realtype & cell_as,
+ realtype & cell_bs,
+ realtype & cell_cs,
+ realtype & cell_alphas,
+ realtype & cell_betas,
+ realtype & cell_gammas,
+ realtype & vols ) {
+ cell_as = as;
+ cell_bs = bs;
+ cell_cs = cs;
+ cell_alphas = alphas;
+ cell_betas = betas;
+ cell_gammas = gammas;
+ if (Vol!=0.0) vols = 1.0/Vol;
+ else vols = 0.0;
+ }
+
+ void Cryst::GetCell ( realtype & cell_a,
+ realtype & cell_b,
+ realtype & cell_c,
+ realtype & cell_alpha,
+ realtype & cell_beta,
+ realtype & cell_gamma,
+ realtype & vol ) {
+ if (WhatIsSet & CSET_CellParams) {
+ cell_a = a;
+ cell_b = b;
+ cell_c = c;
+ cell_alpha = alpha;
+ cell_beta = beta;
+ cell_gamma = gamma;
+ vol = Vol;
+ } else {
+ cell_a = 0.0;
+ cell_b = 0.0;
+ cell_c = 0.0;
+ cell_alpha = 0.0;
+ cell_beta = 0.0;
+ cell_gamma = 0.0;
+ vol = 0.0;
+ }
+ }
+
+ pstr Cryst::GetSpaceGroup() {
+ if (WhatIsSet & CSET_SpaceGroup) return spaceGroup;
+ else return NULL;
+ }
+
+ pstr Cryst::GetSpaceGroupFix() {
+ if (WhatIsSet & CSET_SpaceGroup) return spaceGroupFix;
+ else return NULL;
+ }
+
+
+ void Cryst::Copy ( PCryst Cryst ) {
+ int i,j,k;
+
+ if (Cryst) {
+
+ a = Cryst->a;
+ b = Cryst->b;
+ c = Cryst->c;
+ alpha = Cryst->alpha;
+ beta = Cryst->beta;
+ gamma = Cryst->gamma;
+
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++) {
+ RO [i][j] = Cryst->RO [i][j];
+ RF [i][j] = Cryst->RF [i][j];
+ ROU[i][j] = Cryst->ROU[i][j];
+ RFU[i][j] = Cryst->RFU[i][j];
+ }
+
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++) {
+ o[i][j] = Cryst->o[i][j];
+ s[i][j] = Cryst->s[i][j];
+ for (k=0;k<6;k++)
+ RR[k][i][j] = Cryst->RR[k][i][j];
+ }
+ t[i] = Cryst->t[i];
+ u[i] = Cryst->u[i];
+ }
+
+ Vol = Cryst->Vol;
+ NCode = Cryst->NCode;
+ Z = Cryst->Z;
+ CellCheck = Cryst->CellCheck;
+ WhatIsSet = Cryst->WhatIsSet;
+ strcpy ( spaceGroup ,Cryst->spaceGroup );
+ strcpy ( spaceGroupFix,Cryst->spaceGroupFix );
+
+ ncsMatrix.Copy ( &(Cryst->ncsMatrix) );
+ tVect .Copy ( &(Cryst->tVect) );
+ symOps .Copy ( &(Cryst->symOps) );
+
+ as = Cryst->as;
+ bs = Cryst->bs;
+ cs = Cryst->cs;
+ alphas = Cryst->alphas;
+ betas = Cryst->betas;
+ gammas = Cryst->betas;
+ VolChk = Cryst->VolChk;
+ VolErr = Cryst->VolErr;
+
+ for (k=0;k<6;k++)
+ AC[k] = Cryst->AC[k];
+
+ } else {
+
+ ncsMatrix.FreeContainer();
+ tVect .FreeContainer();
+ WhatIsSet = 0;
+
+ }
+
+ }
+
+
+ void Cryst::write ( io::RFile f ) {
+ int i,j,k;
+ byte Version=3;
+
+ f.WriteByte ( &Version );
+ f.WriteWord ( &WhatIsSet );
+ f.WriteReal ( &a );
+ f.WriteReal ( &b );
+ f.WriteReal ( &c );
+ f.WriteReal ( &alpha );
+ f.WriteReal ( &beta );
+ f.WriteReal ( &gamma );
+ f.WriteWord ( &CellCheck );
+ f.WriteBool ( &ignoreScalei );
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++) {
+ f.WriteReal ( &(RO [i][j]) );
+ f.WriteReal ( &(RF [i][j]) );
+ f.WriteReal ( &(ROU[i][j]) );
+ f.WriteReal ( &(RFU[i][j]) );
+ }
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++) {
+ f.WriteReal ( &(o[i][j]) );
+ f.WriteReal ( &(s[i][j]) );
+ for (k=0;k<6;k++)
+ f.WriteReal ( &(RR[k][i][j]) );
+ }
+ f.WriteReal ( &(t[i]) );
+ f.WriteReal ( &(u[i]) );
+ }
+ f.WriteReal ( &Vol );
+ f.WriteReal ( &VolChk );
+ f.WriteReal ( &VolErr );
+ f.WriteInt ( &NCode );
+ f.WriteInt ( &Z );
+ f.WriteTerLine ( spaceGroup ,false );
+ f.WriteTerLine ( spaceGroupFix,false );
+
+ for (i=0;i<6;i++)
+ f.WriteReal ( &(AC[6]) );
+ f.WriteReal ( &as );
+ f.WriteReal ( &bs );
+ f.WriteReal ( &cs );
+ f.WriteReal ( &alphas );
+ f.WriteReal ( &betas );
+ f.WriteReal ( &gammas );
+
+ ncsMatrix.write ( f );
+ tVect .write ( f );
+ symOps .write ( f );
+
+ }
+
+ void Cryst::read ( io::RFile f ) {
+ int i,j,k;
+ byte Version;
+
+ f.ReadByte ( &Version );
+ f.ReadWord ( &WhatIsSet );
+ f.ReadReal ( &a );
+ f.ReadReal ( &b );
+ f.ReadReal ( &c );
+ f.ReadReal ( &alpha );
+ f.ReadReal ( &beta );
+ f.ReadReal ( &gamma );
+ f.ReadWord ( &CellCheck );
+ if (Version>2)
+ f.ReadBool ( &ignoreScalei );
+ else ignoreScalei = false;
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++) {
+ f.ReadReal ( &(RO [i][j]) );
+ f.ReadReal ( &(RF [i][j]) );
+ f.ReadReal ( &(ROU[i][j]) );
+ f.ReadReal ( &(RFU[i][j]) );
+ }
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++) {
+ f.ReadReal ( &(o[i][j]) );
+ f.ReadReal ( &(s[i][j]) );
+ for (k=0;k<6;k++)
+ f.ReadReal ( &(RR[k][i][j]) );
+ }
+ f.ReadReal ( &(t[i]) );
+ f.ReadReal ( &(u[i]) );
+ }
+ f.ReadReal ( &Vol );
+ f.ReadReal ( &VolChk );
+ f.ReadReal ( &VolErr );
+ f.ReadInt ( &NCode );
+ f.ReadInt ( &Z );
+ f.ReadTerLine ( spaceGroup,false );
+ if (Version>1)
+ f.ReadTerLine ( spaceGroupFix,false );
+ else strcpy ( spaceGroupFix,spaceGroup );
+
+ for (i=0;i<6;i++)
+ f.ReadReal ( &(AC[6]) );
+ f.ReadReal ( &as );
+ f.ReadReal ( &bs );
+ f.ReadReal ( &cs );
+ f.ReadReal ( &alphas );
+ f.ReadReal ( &betas );
+ f.ReadReal ( &gammas );
+
+ ncsMatrix.read ( f );
+ tVect .read ( f );
+ symOps .read ( f );
+
+ }
+
+ MakeStreamFunctions(Cryst)
+
+
+ // ===================================================================
+
+
+ void TestCryst() {
+ // reads from 'in.cryst', writes into
+ // 'out.cryst' and 'abin.cryst'
+ io::File f;
+ char S[81];
+ PCryst cryst;
+
+ cryst = new Cryst();
+
+ f.assign ( pstr("in.cryst"),true );
+ if (f.reset()) {
+ while (!f.FileEnd()) {
+ f.ReadLine ( S,sizeof(S) );
+ cryst->ConvertPDBString ( S );
+ }
+ f.shut();
+ } else {
+ printf ( " Can't open input file 'in.chain' \n" );
+ delete cryst;
+ return;
+ }
+
+ f.assign ( pstr("out.cryst"),true );
+ if (f.rewrite()) {
+ cryst->PDBASCIIDump ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open output file 'out.cryst' \n" );
+ delete cryst;
+ return;
+ }
+
+
+ f.assign ( pstr("mmdb.cryst.bin"),false );
+ if (f.rewrite()) {
+ cryst->write ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open binary cryst file for writing.\n" );
+ delete cryst;
+ return;
+ }
+
+ delete cryst;
+ printf ( " Cryst deleted.\n" );
+
+ cryst = new Cryst();
+ if (f.reset()) {
+ cryst->read ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open binary cryst file for reading.\n" );
+ delete cryst;
+ return;
+ }
+
+ f.assign ( pstr("abin.cryst"),true );
+ if (f.rewrite()) {
+ cryst->PDBASCIIDump ( f );
+ f.shut();
+ } else
+ printf ( " Can't open output file 'abin.cryst' \n" );
+
+ delete cryst;
+
+ }
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_cryst.h b/mmdb2/mmdb_cryst.h
new file mode 100644
index 0000000..4ca4150
--- /dev/null
+++ b/mmdb2/mmdb_cryst.h
@@ -0,0 +1,458 @@
+// $Id: mmdb_cryst.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Cryst <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::CrystContainer ( container for cryst. data )
+// ~~~~~~~~~ mmdb::NCSMatrix ( non-cryst. symm. matrix class )
+// mmdb::TVect ( translation vector class )
+// mmdb::Cryst ( MMDB cryst. section class )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Cryst__
+#define __MMDB_Cryst__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_symop.h"
+#include "mmdb_defs.h"
+#include "mmdb_utils.h"
+
+namespace mmdb {
+
+ // ==================== CrystContainer ======================
+
+ DefineClass(CrystContainer);
+ DefineStreamFunctions(CrystContainer);
+
+ class CrystContainer : public ClassContainer {
+
+ public :
+
+ CrystContainer () : ClassContainer() {}
+ CrystContainer ( io::RPStream Object )
+ : ClassContainer ( Object ) {}
+ ~CrystContainer() {}
+
+ PContainerClass MakeContainerClass ( int ClassID );
+
+ ERROR_CODE AddMTRIXLine ( cpstr S );
+
+ };
+
+
+ // ================== NCSMatrix ========================
+
+ enum NCSM_SET {
+ NCSMSET_Matrix1 = 0x00000001,
+ NCSMSET_Matrix2 = 0x00000002,
+ NCSMSET_Matrix3 = 0x00000004,
+ NCSMSET_All = 0x00000007
+ };
+
+ DefineClass(NCSMatrix);
+ DefineStreamFunctions(NCSMatrix);
+
+ class NCSMatrix : public ContainerClass {
+
+ friend class Cryst;
+
+ public :
+
+ int serNum; // serial number
+ mat33 m; // non-crystallographic symmetry matrix
+ vect3 v; // translational part of ncs matrix
+ int iGiven; // iGiven flag (see PDB format)
+
+ NCSMatrix ();
+ NCSMatrix ( cpstr S );
+ NCSMatrix ( io::RPStream Object );
+ ~NCSMatrix();
+
+ bool PDBASCIIDump1 ( io::RFile f );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_NCSMatrix; }
+
+ void SetNCSMatrix ( int serialNum,
+ mat33 & ncs_m, vect3 & ncs_v,
+ int i_Given );
+
+ void Copy ( PContainerClass NCSMatrix );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ word WhatIsSet; // mask field
+ // 0x0001 MTRIX1 was converted
+ // 0x0002 MTRIX2 was converted
+ // 0x0004 MTRIX3 was converted
+
+ void Init();
+
+ };
+
+
+ // ================== TVect ========================
+
+ DefineClass(TVect);
+ DefineStreamFunctions(TVect);
+
+ class TVect : public ContainerClass {
+
+ public :
+
+ int serNum; // serial number
+ vect3 t; // translation vector
+ pstr comment; // comment
+
+ TVect ();
+ TVect ( cpstr S );
+ TVect ( io::RPStream Object );
+ ~TVect();
+
+ void PDBASCIIDump ( pstr S, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_TVect; }
+
+ void Copy ( PContainerClass TVect );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void Init();
+
+ };
+
+
+ // ================= Cryst =======================
+
+ DefineClass(Cryst);
+ DefineStreamFunctions(Cryst);
+
+ // constants for the CellCheck field
+ enum CELL_CHECK {
+ CCHK_Ok = 0x00000000,
+ CCHK_NoCell = 0x00000001,
+ CCHK_Error = 0x00000002,
+ CCHK_Disagreement = 0x00000004,
+ CCHK_NoOrthCode = 0x00000008,
+ CCHK_Translations = 0x00000010,
+ CCHK_Unchecked = 0x00001000
+ };
+
+ // constants for the WhatIsSet field
+ enum CELL_SET {
+ CSET_CellParams1 = 0x00000001,
+ CSET_CellParams2 = 0x00000002,
+ CSET_CellParams = 0x00000003,
+ CSET_SpaceGroup = 0x00000004,
+ CSET_ZValue = 0x00000008,
+ CSET_CrystCard = 0x0000000F,
+ CSET_OrigMatrix1 = 0x00000010,
+ CSET_OrigMatrix2 = 0x00000020,
+ CSET_OrigMatrix3 = 0x00000040,
+ CSET_OrigMatrix = 0x00000070,
+ CSET_ScaleMatrix1 = 0x00000080,
+ CSET_ScaleMatrix2 = 0x00000100,
+ CSET_ScaleMatrix3 = 0x00000200,
+ CSET_ScaleMatrix = 0x00000380,
+ CSET_Transforms = 0x00000400,
+ CSET_DummyCell = 0x00001000
+ };
+
+ extern cpstr OrthCode[6];
+
+ class Cryst : public io::Stream {
+
+ friend class Channel;
+
+ public :
+ realtype a,b,c; // cell parameters
+ realtype alpha,beta,gamma; // cell parameters
+ mat44 RO,RF; // orthogonal-fractional recalculation
+ // matrices
+ mat44 ROU,RFU; // ort-frac recalc matrices for
+ // anisotr. t-fac
+ mat633 RR; // standard orthogonalizations
+ realtype Vol; // cell volume
+ int NCode; // code of orthogonalization matrix
+ SymGroup spaceGroup; // group of space symmetry as read
+ // from file
+ SymGroup spaceGroupFix; // actually used space group
+ int Z; // Z-value
+
+ mat33 o; // orthogonal transformation matrix
+ vect3 t; // translation orthogonal vector
+ mat33 s; // scale matrix
+ vect3 u; // translation part of the scale matrix
+
+ word CellCheck; // 0x0000 - Ok
+ // 0x0001 - no cell stored
+ // 0x0002 - some error in cell volume
+ // 0x0004 - disagreement between
+ // cell and PDB
+ // 0x0008 - no orth code derived
+ // 0x0010 - translations also specified
+ // 0x1000 - the check was not done
+ word WhatIsSet; // indicator of the fields set
+ bool ignoreScalei; // flag to ignore SCALEi cards
+ bool processSG; // flag to process space group at file
+ // read
+ bool fixSpaceGroup; // flag to fix space group at file read
+
+ Cryst ();
+ Cryst ( io::RPStream Object );
+ ~Cryst();
+
+ void FreeMemory();
+ void Reset ();
+
+ // ConvertPDBString(..) interprets an ASCII PDB line and fills
+ // the corresponding data fields. It returns zero if the line was
+ // successfully converted, otherwise returns a non-negative value
+ // of Error_XXXX.
+ // PDBString must be not shorter than 81 characters.
+ ERROR_CODE ConvertPDBString ( pstr PDBString );
+
+ // RWBROOKReadPrintout() may be invoked after reading PDB file
+ // for simulating the old RWBROOK messages and warnings
+ void RWBROOKReadPrintout();
+
+ void SetCell ( realtype cell_a,
+ realtype cell_b,
+ realtype cell_c,
+ realtype cell_alpha,
+ realtype cell_beta,
+ realtype cell_gamma,
+ int OrthCode );
+ void PutCell ( realtype cell_a,
+ realtype cell_b,
+ realtype cell_c,
+ realtype cell_alpha,
+ realtype cell_beta,
+ realtype cell_gamma,
+ int OrthCode );
+
+ void GetCell ( realtype & cell_a,
+ realtype & cell_b,
+ realtype & cell_c,
+ realtype & cell_alpha,
+ realtype & cell_beta,
+ realtype & cell_gamma,
+ realtype & vol );
+
+ void GetRCell ( realtype & cell_as,
+ realtype & cell_bs,
+ realtype & cell_cs,
+ realtype & cell_alphas,
+ realtype & cell_betas,
+ realtype & cell_gammas,
+ realtype & vols );
+
+ void SetSyminfoLib ( cpstr syminfoLib );
+ pstr GetSyminfoLib ();
+
+ int SetSpaceGroup ( cpstr spGroup );
+ pstr GetSpaceGroup ();
+ pstr GetSpaceGroupFix();
+
+ // CalcCoordTransforms() should be called once after all data
+ // relevant to the crystallographic information, are read and
+ // converted. Field CellCheck will then have bits set if there
+ // are errors, e.g. bit CCHK_NoCell means that the coordinate
+ // transformations cannot be performed.
+ void CalcCoordTransforms();
+
+ // A PDB ASCII dump
+ void PDBASCIIDump ( io::RFile f );
+
+ ERROR_CODE GetCIF ( mmcif::PData CIF );
+ void MakeCIF ( mmcif::PData CIF );
+
+ bool areMatrices(); // returns True if the orthogonal-to-
+ // fractional and fractional-to-orthogonal
+ // matrices are defined
+
+ // Frac2Orth(..) and Orth2Frac(..) transform between fractional
+ // and orthogonal coordinates, if areMatrices() returns True.
+ // If the transformation matrices were not set, the functions just
+ // copy the coordinates. Returns True if the transformation was
+ // done; False return means that transformation matrices were not
+ // calculated
+ bool Frac2Orth (
+ realtype x, realtype y, realtype z,
+ realtype & xx, realtype & yy, realtype & zz );
+ bool Orth2Frac (
+ realtype x, realtype y, realtype z,
+ realtype & xx, realtype & yy, realtype & zz );
+
+ // Below, F and T are transformation matrices in fractional and
+ // orthogonal coordinates, respectively.
+ bool Frac2Orth ( mat44 & F, mat44 & T );
+ bool Orth2Frac ( mat44 & T, mat44 & F );
+
+
+ // Cryst2Orth(..) and Orth2Cryst(..) transform between fractional
+ // and orthogonal anisotropic temperature factors, if areMatrices()
+ // returns True. If the transformation matrices were not set, the
+ // functions leave the factors unchanged.
+ // Vector U is composed as follows:
+ // U[0]=u11 U[1]=u22 U[2]=u33
+ // U[3]=u12 U[4]=u13 U[5]=u23
+ // Returns True if the transformation was done; False retuen
+ // means that transformation matrices were not calculated
+ bool Cryst2Orth ( rvector U );
+ bool Orth2Cryst ( rvector U );
+
+ void CalcOrthMatrices(); // calculates RR, AC, cella's and Vol
+
+ bool isNCSMatrix ();
+ bool isScaleMatrix ();
+ bool isCellParameters();
+
+ int GetNumberOfSymOps();
+ pstr GetSymOp ( int Nop );
+
+ int GetNumberOfNCSMatrices();
+ int GetNumberOfNCSMates (); // Returns the number of
+ // NCS mates not given in
+ // the file (iGiven==0)
+
+ bool GetNCSMatrix ( int NCSMatrixNo, mat33 & ncs_m,
+ vect3 & ncs_v );
+ bool GetNCSMatrix ( int NCSMatrixNo, mat44 & ncs_m,
+ int & iGiven ); // no=0..N-1
+ int AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v, int iGiven );
+
+ // GetTMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts orthogonal coordinates
+ // according to the symmetry operation number Nop and places
+ // them into unit cell shifted by cellshift_a a's, cellshift_b
+ // b's and cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ int GetTMatrix ( mat44 & TMatrix, int Nop,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c, PSymOps symOpers=NULL );
+
+ // GetUCTMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts orthogonal coordinates
+ // according to the symmetry operation Nop. Translation part
+ // of the matrix is being chosen such that point (x,y,z) has
+ // least distance to the center of primary (333) unit cell,
+ // and then it is shifted by cellshift_a a's, cellshift_b b's
+ // and cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ //
+ int GetUCTMatrix ( mat44 & TMatrix, int Nop,
+ realtype x, realtype y, realtype z,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c, PSymOps symOpers=NULL );
+
+ // GetFractMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts fractional coordinates
+ // according to the symmetry operation number Nop and places them
+ // into unit cell shifted by cellshift_a a's, cellshift_b b's and
+ // cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ int GetFractMatrix ( mat44 & TMatrix, int Nop,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c, PSymOps symOpers=NULL );
+
+ // GetSymOpMatrix(..) returns the transformation matrix for
+ // Nop-th symmetry operator in the space group
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ //
+ int GetSymOpMatrix ( mat44 & TMatrix, int Nop );
+
+ void Copy ( PCryst Cryst );
+
+ void write ( io::RFile f ); // writes header to PDB binary file
+ void read ( io::RFile f ); // reads header from PDB binary file
+
+ protected :
+
+ CrystContainer ncsMatrix; // non-cryst. symm. matrices
+ CrystContainer tVect; // translation vectors
+
+ realtype as,bs,cs; // calculated 'cell parameters'
+ realtype alphas,betas,gammas; // calculated 'cell parameters'
+ realtype AC[6];
+ realtype VolChk,VolErr;
+
+ pstr syminfo_lib; // path to syminfo.lib
+ SymOps symOps; // symmetry operations
+
+ void Init ( bool fullInit );
+ int FixSpaceGroup();
+
+ };
+
+ extern cpstr getOrthCodeName ( int NCode );
+
+} // namespace mmdb
+
+/*
+extern void TestCryst(); // reads from 'in.cryst', writes into
+ // 'out.cryst' and 'abin.cryst'
+*/
+
+
+#endif
+
diff --git a/mmdb2/mmdb_defs.h b/mmdb2/mmdb_defs.h
new file mode 100644
index 0000000..da06dac
--- /dev/null
+++ b/mmdb2/mmdb_defs.h
@@ -0,0 +1,271 @@
+// $Id: mmdb_defs.h,v 1.27 2012/01/26 17:52:20 ekr Exp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 10.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDBF_Defs <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// Definition of types, constants and important classes.
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Defs__
+#define __MMDB_Defs__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb {
+
+ enum MMDB_VERSION {
+ MAJOR_VERSION = 2, //!< MMDB major version
+ MINOR_VERSION = 0, //!< MMDB minor version
+ MICRO_VERSION = 1 //!< MMDB micro version
+ };
+
+ // ======================= types =================================
+
+ typedef char IDCode [16]; //!< ID code of PDB entry
+ typedef IDCode * PIDCode; //!< pointer to ID code
+ typedef PIDCode & RPIDCode; //!< ref. to pointer to ID code
+ typedef char Date [12]; //!< date DD-MMM-YYYY
+ typedef char RecName [7]; //!< name of PDB record
+
+ typedef char ChainID [10]; //!< chain ID
+ typedef ChainID * PChainID; //!< pointer to chain ID
+ typedef char InsCode [10]; //!< insertion code
+ typedef char DBName [10]; //!< sequence database name
+ typedef char DBAcCode[20]; //!< seq. database accession code
+ typedef DBAcCode * PDBAcCode; //!< pointer to seq. db acc code
+ typedef char DBIdCode[20]; //!< seq. database ident-n code
+ typedef DBIdCode * PDBIdCode; //!< pointer to DBIdCode
+ typedef char ResName [20]; //!< residue name
+ typedef ResName * PResName; //!< pointer to residue name
+ typedef PResName * PPResName; //!< ptr to vector of residue names
+ typedef char HelixID [20]; //!< helix ID
+ typedef char StrandID[20]; //!< strand ID
+ typedef char SheetID [20]; //!< sheet ID
+ typedef char TurnID [20]; //!< turn ID
+ typedef char LinkRID [20]; //!< Refmac link ID
+
+ typedef char SymGroup[100]; //!< group of space symmetry
+ typedef realtype vect3 [3]; //!< vector of 3 real numbers
+ typedef vect3 * pvect3; //!< ptr to vector 3
+ typedef pvect3 & rpvect3; //!< ref to ptr to vector 3
+ typedef realtype vect4 [4]; //!< vector of 4 real numbers
+ typedef vect3 mat33 [3]; //!< matrix 3x3 of real numbers
+
+ typedef vect4 mat44 [4]; //!< matrix 4x4 of real numbers
+ typedef mat44 * pmat44; //!< ptr to matrix 4x4
+ typedef mat44 & rmat44; //!< ref to matrix 4x4
+ typedef pmat44 * ppmat44; //!< ptr to ptr to matrix 4x4
+ typedef pmat44 & rpmat44; //!< ref to ptr to matrix 4x4
+ typedef mat33 mat633 [6]; //!< matrix 6x3x3 of real numbers
+
+ typedef char AtomName[20]; //!< name of the atom
+ typedef AtomName * PAtomName; //!< pointer to atom name
+ typedef char AltLoc [20]; //!< alternate location indicator
+ typedef AltLoc * PAltLoc; //!< pointer to alt loc indicator
+ typedef char SegID [20]; //!< segment identifier
+ typedef char Element [10]; //!< chemical element name
+ typedef Element * PElement; //!< ptr to chemical element name
+ typedef char EnergyType[10]; //!< energy type name
+ typedef EnergyType * PEnergyType; //!< pointer to energy type name
+
+ // do not forget update this when change the above typedefs:
+ typedef char maxMMDBName[40];
+
+
+ // ===================== constants ===============================
+
+ // ANY_RES should be used in selection functions for specifying
+ // "any residue" to select. Defined in mmdb_selmngr.cpp
+ extern const int ANY_RES;
+
+ // PRNK_XXXXX are the print keys. PRNK_Silent supresses all print
+ // inside mmdb_xxxx unless specifically ordered or catastrophic.
+ // PRNK_SimRWBROOK instructs mmdb to issue, whenever possible and
+ // necessary, printouts and warnings of RWBROOK (fortran) package.
+ enum PRINT_KEY {
+ PRNK_Silent = 0,
+ PRNK_SimRWBROOK = 1
+ };
+
+ // Error_XXXX may be returned by XX::ConvertPDBString() and GetCIF(..)
+ // functions.
+ // Error_WrongSection is returned if the string passed into function
+ // does not belong to the corresponding PDB section.
+
+
+ enum ERROR_CODE {
+
+ Error_EmptyCIF =-1, //!< used as signal at reading CIF files
+
+ Error_NoError = 0,
+ Error_Ok = 0,
+ Error_WrongSection = 1,
+ Error_WrongChainID = 2,
+ Error_WrongEntryID = 3,
+
+ // Error_SEQRES_serNum is returned by CSeqRes::ConvertPDBASCII() if
+ // serial numbers of SEQRES records do not increment by 1
+ Error_SEQRES_serNum = 4,
+
+ // Error_SEQRES_numRes is returned by CSeqRes::ConvertPDBASCII() if
+ // SEQRES records show different number of residues
+ Error_SEQRES_numRes = 5,
+
+ // Error_SEQRES_extraRes is returned by CSeqRes::ConvertPDBASCII() if
+ // SEQRES contains more residues than specified
+ Error_SEQRES_extraRes = 6,
+
+ Error_NCSM_Unrecognized = 7,
+ Error_NCSM_AlreadySet = 8,
+ Error_NCSM_WrongSerial = 9,
+ Error_NCSM_UnmatchIG = 10,
+
+ Error_ATOM_Unrecognized = 11,
+ Error_ATOM_AlreadySet = 12,
+ Error_ATOM_NoResidue = 13,
+ Error_ATOM_Unmatch = 14,
+
+ Error_CantOpenFile = 15,
+ Error_UnrecognizedInteger = 16,
+ Error_WrongModelNo = 17,
+ Error_DuplicatedModel = 18,
+ Error_NoModel = 19,
+ Error_ForeignFile = 20,
+ Error_WrongEdition = 21,
+
+ // CIF specific
+ Error_NotACIFFile = 22,
+ Error_NoData = 23,
+ Error_NoLoop = 24,
+ Error_NoStruct = 25,
+ Error_UnrecognCIFItems = 26,
+ Error_MissingCIFField = 27,
+ Error_EmptyCIFLoop = 28,
+ Error_EmptyCIFStruct = 29,
+ Error_UnexpEndOfCIF = 30,
+ Error_MissgCIFLoopField = 31,
+ Error_NotACIFStructure = 32,
+ Error_NotACIFLoop = 33,
+ Error_UnrecognizedReal = 34,
+
+ Error_NoSheetID = 35,
+ Error_WrongSheetID = 36,
+ Error_WrongStrandNo = 37,
+
+ // Error_WrongNumberOfStrands may be issued when reading
+ // sheet data from CIF
+ Error_WrongNumberOfStrands = 38,
+
+ // Error_WrongSheetOrder may be issued when reading
+ // sheet data from CIF
+ Error_WrongSheetOrder = 39,
+
+ // Error_HBondInconsistency may be issued when reading
+ // sheet data from CIF
+ Error_HBondInconsistency = 40,
+
+ // Error_EmptyResidueName is issued when PDB ATOM record
+ // does not have a residue name
+ Error_EmptyResidueName = 41,
+
+ // Error_DuplicateSeqNum is issued when PDB ATOM records
+ // show the sequence number and insertion code assigned
+ // to more than one residue name
+ Error_DuplicateSeqNum = 42,
+
+ // Error_NoLogicalName may be returned by file i/o functions
+ // if the specified environmental variable for file name
+ // is not found.
+ Error_NoLogicalName = 43,
+
+ // Error_EmptyFile may be returned at reading non-existing
+ // coordinate files
+ Error_EmptyFile = 44,
+
+ Error_Unknown = 45,
+
+ // Error_CIF_EmptyRow is the event of encountering
+ // an empty row in _atom_site loop. It is handled
+ // internally and has no effect on API
+ Error_CIF_EmptyRow = 99999,
+
+ Error_GeneralError1 = 10000
+
+ };
+
+ // ClassID_XXXX are used by container classes for proper
+ // creating containered classes when reading from binary file.
+
+ enum CLASS_ID {
+ ClassID_Template ,
+ ClassID_String ,
+ ClassID_ObsLine ,
+ ClassID_TitleLine ,
+ ClassID_CAVEAT ,
+ ClassID_Compound ,
+ ClassID_Source ,
+ ClassID_ExpData ,
+ ClassID_MdlType ,
+ ClassID_Author ,
+ ClassID_RevData ,
+ ClassID_Supersede ,
+ ClassID_Journal ,
+ ClassID_Remark ,
+ ClassID_DBReference,
+ ClassID_SeqAdv ,
+ ClassID_ModRes ,
+ ClassID_Het ,
+ ClassID_NCSMatrix ,
+ ClassID_TVect ,
+ ClassID_Helix ,
+ ClassID_Turn ,
+ ClassID_Link ,
+ ClassID_LinkR ,
+ ClassID_CisPep
+ };
+
+
+ // ===================== classes ===============================
+
+ DefineClass(Atom);
+ DefineClass(Residue);
+ DefineClass(Chain);
+ DefineClass(Model);
+ DefineClass(Manager);
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_ficif.cpp b/mmdb2/mmdb_ficif.cpp
new file mode 100644
index 0000000..e7892d5
--- /dev/null
+++ b/mmdb2/mmdb_ficif.cpp
@@ -0,0 +1,519 @@
+// $Id: mmdb_ficif.cpp,v 1.19 2012/01/26 17:52:20 ekr Exp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 24.04.03 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_FICIF <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes :
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2008
+//
+// =================================================================
+//
+
+#include "mmdb_mmcif_.h"
+#include "mmdb_ficif.h"
+
+
+// ==================================================================
+
+mmcif::PData mmCIFData = NULL;
+
+
+FORTRAN_SUBR ( MMDB_FCIF_INIT, mmdb_fcif_init,(),(),() ) {
+ InitMatType();
+ mmCIFData = NULL;
+}
+
+void MMDB_CCIF_Init() {
+ InitMatType();
+ mmCIFData = NULL;
+}
+
+FORTRAN_SUBR ( MMDB_FCIF_QUIT, mmdb_fcif_quit,(),(),() ) {
+ if (mmCIFData) delete mmCIFData;
+ mmCIFData = NULL;
+}
+
+void MMDB_CCIF_Quit() {
+ if (mmCIFData) delete mmCIFData;
+ mmCIFData = NULL;
+}
+
+pstr makeString ( pstr S, int SLen, pstr FS, int FSLen ) {
+ GetStrTer ( S,FS,FSLen,SLen,FSLen );
+ CutSpaces ( S,SCUTKEY_END );
+ return S;
+}
+
+FORTRAN_SUBR ( MMDB_FCIF_CREATE, mmdb_fcif_create,
+ ( // lengths-at-end list
+ fpstr DataName, // file name
+ int DataName_len // fortran-hidden length of DataName
+ ), ( // lengths-in-structure list
+ fpstr DataName
+ ), ( // lengths-follow list
+ fpstr DataName, int DataName_len
+ ) ) {
+char S[500];
+
+ if (mmCIFData) delete mmCIFData;
+ mmCIFData = new mmcif::Data ( makeString(S,sizeof(S),
+ FTN_STR(DataName),FTN_LEN(DataName)) );
+
+}
+
+void MMDB_CCIF_Create ( pstr DataName ) {
+ if (mmCIFData) delete mmCIFData;
+ mmCIFData = new mmcif::Data ( DataName );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_WRITE, mmdb_fcif_write,
+ ( // lengths-at-end list
+ fpstr FileName, // file name
+ int * iRet, // return code
+ int FileName_len // fortran-hidden length of FileName
+ ), ( // lengths-in-structure list
+ fpstr FileName, int *iRet
+ ), ( // lengths-follow list
+ fpstr FileName, int FileName_len, int * iRet
+ ) ) {
+pstr S;
+
+ if (!mmCIFData)
+ *iRet = -1000;
+ else {
+ S = new char[FTN_LEN(FileName)+10];
+ if (mmCIFData->WriteMMCIFData(makeString(S,FTN_LEN(FileName)+5,
+ FTN_STR(FileName),FTN_LEN(FileName))))
+ *iRet = 0;
+ else *iRet = 1;
+ delete[] S;
+ }
+
+}
+
+
+int MMDB_CCIF_Write ( pstr FileName ) {
+ if (!mmCIFData) return -1000;
+ else if (mmCIFData->WriteMMCIFData(FileName)) return 0;
+ else return 1;
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTDATE, mmdb_fcif_putdate,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) ) {
+char CN[200],TN[200];
+
+ if (!mmCIFData)
+ *iRet = -1000;
+ else *iRet = mmCIFData->PutDate ( makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)) );
+}
+
+int MMDB_CCIF_PutDate ( pstr CatName, pstr Tag ) {
+ if (!mmCIFData) return -1000;
+ else return mmCIFData->PutDate ( CatName,Tag );
+}
+
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTDOT, mmdb_fcif_putdot,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) ) {
+char CN[200],TN[200];
+ if (!mmCIFData)
+ *iRet = -1000;
+ else *iRet = mmCIFData->PutNoData ( mmcif::CIF_NODATA_DOT,
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)) );
+}
+
+
+int MMDB_CCIF_PutDot ( pstr CatName, pstr Tag ) {
+ if (!mmCIFData) return -1000;
+ else return mmCIFData->PutNoData ( mmcif::CIF_NODATA_DOT,
+ CatName,Tag );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTQUESTION, mmdb_fcif_putquestion,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) ) {
+char CN[200],TN[200];
+ if (!mmCIFData)
+ *iRet = -1000;
+ else *iRet = mmCIFData->PutNoData ( mmcif::CIF_NODATA_QUESTION,
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)) );
+}
+
+
+int MMDB_CCIF_PutQuestion ( pstr CatName, pstr Tag ) {
+ if (!mmCIFData)
+ return -1000;
+ else
+ return mmCIFData->PutNoData ( mmcif::CIF_NODATA_QUESTION,
+ CatName,Tag );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTSTRING, mmdb_fcif_putstring,
+ ( // lengths-at-end list
+ fpstr Data, // data string to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int Data_len, // fortran-hidden length of Data
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr Data, fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ fpstr Data, int Data_len,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) ) {
+char CN[200],TN[200];
+pstr S;
+
+ if (!mmCIFData)
+ *iRet = -1000;
+ else {
+ S = new char[FTN_LEN(Data)+10];
+ *iRet = mmCIFData->PutString ( makeString(S,FTN_LEN(Data)+5,
+ FTN_STR(Data),FTN_LEN(Data)),
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)) );
+ delete[] S;
+ }
+
+}
+
+int MMDB_CCIF_PutString ( pstr Data, pstr CatName, pstr Tag ) {
+ if (!mmCIFData) return -1000;
+ else return mmCIFData->PutString ( Data,CatName,Tag );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTREAL, mmdb_fcif_putreal,
+ ( // lengths-at-end list
+ apireal * V, // real value to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ apireal * V, fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ apireal * V,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) ) {
+char CN[200],TN[200];
+
+ if (!mmCIFData) *iRet = -1000;
+ else *iRet = mmCIFData->PutReal ( *V,
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)) );
+
+}
+
+
+int MMDB_CCIF_PutReal ( realtype V, pstr CatName, pstr Tag ) {
+ if (!mmCIFData) return -1000;
+ else return mmCIFData->PutReal ( V,CatName,Tag );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTINTEGER, mmdb_fcif_putinteger,
+ ( // lengths-at-end list
+ int * I, // integer value to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ int * I, fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ int * I,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) ) {
+char CN[200],TN[200];
+
+ if (!mmCIFData) *iRet = -1000;
+ else *iRet = mmCIFData->PutInteger ( *I,
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)) );
+
+}
+
+int MMDB_CCIF_PutInteger ( int I, pstr CatName, pstr Tag ) {
+ if (!mmCIFData) return -1000;
+ else return mmCIFData->PutInteger ( I,CatName,Tag );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPDOT, mmdb_fcif_putloopdot,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * nrow, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) ) {
+char CN[200],TN[200];
+ if (!mmCIFData)
+ *iRet = -1000;
+ else *iRet = mmCIFData->PutLoopNoData ( mmcif::CIF_NODATA_DOT,
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)),*nrow );
+}
+
+
+int MMDB_CCIF_PutLoopDot ( pstr CatName, pstr Tag, int nrow ) {
+ if (!mmCIFData)
+ return -1000;
+ else
+ return mmCIFData->PutLoopNoData ( mmcif::CIF_NODATA_DOT,
+ CatName,Tag,nrow );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPQUESTION, mmdb_fcif_putloopquestion,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * nrow, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) ) {
+char CN[200],TN[200];
+ if (!mmCIFData)
+ *iRet = -1000;
+ else *iRet = mmCIFData->PutLoopNoData ( mmcif::CIF_NODATA_QUESTION,
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)),*nrow );
+}
+
+int MMDB_CCIF_PutLoopQuestion ( pstr CatName, pstr Tag, int nrow ) {
+ if (!mmCIFData)
+ return -1000;
+ else
+ return mmCIFData->PutLoopNoData ( mmcif::CIF_NODATA_QUESTION,
+ CatName,Tag,nrow );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPSTRING, mmdb_fcif_putloopstring,
+ ( // lengths-at-end list
+ fpstr Data, // data string to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int Data_len, // fortran-hidden length of Data
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr Data, fpstr CatName, fpstr Tag,
+ int * nrow, int * iRet
+ ), ( // lengths-follow list
+ fpstr Data, int Data_len,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) ) {
+char CN[200],TN[200];
+pstr S;
+
+ if (!mmCIFData)
+ *iRet = -1000;
+ else {
+ S = new char[FTN_LEN(Data)+10];
+ *iRet = mmCIFData->PutLoopString ( makeString(S,FTN_LEN(Data)+5,
+ FTN_STR(Data),FTN_LEN(Data)),
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)),*nrow );
+ delete[] S;
+ }
+
+}
+
+
+int MMDB_CCIF_PutLoopString ( pstr Data, pstr CatName, pstr Tag, int nrow ) {
+ if (!mmCIFData) return -1000;
+ else return mmCIFData->PutLoopString ( Data,CatName,Tag,nrow );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPREAL, mmdb_fcif_putloopreal,
+ ( // lengths-at-end list
+ apireal * V, // real value to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ apireal * V, fpstr CatName, fpstr Tag,
+ int * nrow, int * iRet
+ ), ( // lengths-follow list
+ apireal * V,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) ) {
+char CN[200],TN[200];
+
+ if (!mmCIFData) *iRet = -1000;
+ else *iRet = mmCIFData->PutLoopReal ( *V,
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)),*nrow );
+
+}
+
+
+int MMDB_CCIF_PutLoopReal ( realtype V, pstr CatName, pstr Tag, int nrow ) {
+ if (!mmCIFData) return -1000;
+ else return mmCIFData->PutLoopReal ( V,CatName,Tag,nrow );
+}
+
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPINTEGER, mmdb_fcif_putloopinteger,
+ ( // lengths-at-end list
+ int * I, // integer value to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ int * I, fpstr CatName, fpstr Tag,
+ int * nrow, int * iRet
+ ), ( // lengths-follow list
+ int * I,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) ) {
+char CN[200],TN[200];
+
+ if (!mmCIFData) *iRet = -1000;
+ else *iRet = mmCIFData->PutLoopInteger ( *I,
+ makeString(CN,sizeof(CN),
+ FTN_STR(CatName),FTN_LEN(CatName)),
+ makeString(TN,sizeof(TN),
+ FTN_STR(Tag),FTN_LEN(Tag)),*nrow );
+
+}
+
+
+int MMDB_CCIF_PutLoopInteger ( int I, pstr CatName, pstr Tag, int nrow ) {
+ if (!mmCIFData) return -1000;
+ else return mmCIFData->PutLoopInteger ( I,CatName,Tag,nrow );
+}
diff --git a/mmdb2/mmdb_ficif.h b/mmdb2/mmdb_ficif.h
new file mode 100644
index 0000000..7347f38
--- /dev/null
+++ b/mmdb2/mmdb_ficif.h
@@ -0,0 +1,287 @@
+// $Id: mmdb_ficif.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_FICIF <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes :
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_FICIF__
+#define __MMDB_FICIF__
+
+#include "mmdb_machine_.h"
+
+using namespace mmdb;
+using namespace mmdb::machine;
+
+// ==================== FORTRAN INTERFACE ========================
+
+FORTRAN_SUBR ( MMDB_FCIF_INIT, mmdb_fcif_init,(),(),() );
+
+FORTRAN_SUBR ( MMDB_FCIF_QUIT, mmdb_fcif_quit,(),(),() );
+
+FORTRAN_SUBR ( MMDB_FCIF_CREATE, mmdb_fcif_create,
+ ( // lengths-at-end list
+ fpstr DataName, // file name
+ int DataName_len // fortran-hidden length of DataName
+ ), ( // lengths-in-structure list
+ fpstr DataName
+ ), ( // lengths-follow list
+ fpstr DataName, int DataName_len
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_WRITE, mmdb_fcif_write,
+ ( // lengths-at-end list
+ fpstr FileName, // file name
+ int * iRet, // return code
+ int FileName_len // fortran-hidden length of FileName
+ ), ( // lengths-in-structure list
+ fpstr FileName, int *iRet
+ ), ( // lengths-follow list
+ fpstr FileName, int FileName_len, int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTDATE, mmdb_fcif_putdate,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTDOT, mmdb_fcif_putdot,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTQUESTION, mmdb_fcif_putquestion,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTSTRING, mmdb_fcif_putstring,
+ ( // lengths-at-end list
+ fpstr Data, // data string to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int Data_len, // fortran-hidden length of Data
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr Data, fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ fpstr Data, int Data_len,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTREAL, mmdb_fcif_putreal,
+ ( // lengths-at-end list
+ apireal * V, // real value to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ apireal * V, fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ apireal * V,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTINTEGER, mmdb_fcif_putinteger,
+ ( // lengths-at-end list
+ int * I, // integer value to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ int * I, fpstr CatName, fpstr Tag, int * iRet
+ ), ( // lengths-follow list
+ int * I,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPDOT, mmdb_fcif_putloopdot,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * nrow, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPQUESTION, mmdb_fcif_putloopquestion,
+ ( // lengths-at-end list
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr CatName, fpstr Tag, int * nrow, int * iRet
+ ), ( // lengths-follow list
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPSTRING, mmdb_fcif_putloopstring,
+ ( // lengths-at-end list
+ fpstr Data, // data string to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int Data_len, // fortran-hidden length of Data
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ fpstr Data, fpstr CatName, fpstr Tag,
+ int * nrow, int * iRet
+ ), ( // lengths-follow list
+ fpstr Data, int Data_len,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPREAL, mmdb_fcif_putloopreal,
+ ( // lengths-at-end list
+ apireal * V, // real value to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ apireal * V, fpstr CatName, fpstr Tag,
+ int * nrow, int * iRet
+ ), ( // lengths-follow list
+ apireal * V,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) );
+
+FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPINTEGER, mmdb_fcif_putloopinteger,
+ ( // lengths-at-end list
+ int * I, // integer value to store
+ fpstr CatName, // category name
+ fpstr Tag, // tag
+ int * nrow, // row number
+ int * iRet, // return code
+ int CatName_len, // fortran-hidden length of CatName
+ int Tag_len // fortran-hidden length of Tag
+ ), ( // lengths-in-structure list
+ int * I, fpstr CatName, fpstr Tag,
+ int * nrow, int * iRet
+ ), ( // lengths-follow list
+ int * I,
+ fpstr CatName, int CatName_len,
+ fpstr Tag, int Tag_len,
+ int * nrow, int * iRet
+ ) );
+
+
+
+
+// ==================== C INTERFACE ========================
+
+extern "C" void MMDB_CCIF_Init();
+extern "C" void MMDB_CCIF_Quit();
+extern "C" void MMDB_CCIF_Create ( pstr DataName );
+extern "C" int MMDB_CCIF_Write ( pstr FileName );
+extern "C" int MMDB_CCIF_PutDate ( pstr CatName, pstr Tag );
+extern "C" int MMDB_CCIF_PutDot ( pstr CatName, pstr Tag );
+extern "C" int MMDB_CCIF_PutQuestion ( pstr CatName, pstr Tag );
+extern "C" int MMDB_CCIF_PutString ( pstr Data, pstr CatName, pstr Tag );
+extern "C" int MMDB_CCIF_PutReal ( realtype V, pstr CatName, pstr Tag );
+extern "C" int MMDB_CCIF_PutInteger ( int I, pstr CatName, pstr Tag );
+extern "C" int MMDB_CCIF_PutLoopDot ( pstr CatName, pstr Tag, int nrow );
+extern "C" int MMDB_CCIF_PutLoopQuestion ( pstr CatName, pstr Tag, int nrow );
+extern "C" int MMDB_CCIF_PutLoopString ( pstr Data, pstr CatName,
+ pstr Tag, int nrow );
+extern "C" int MMDB_CCIF_PutLoopReal ( realtype V, pstr CatName,
+ pstr Tag, int nrow );
+extern "C" int MMDB_CCIF_PutLoopInteger ( int I, pstr CatName,
+ pstr Tag, int nrow );
+
+#endif
diff --git a/mmdb2/mmdb_io_file.cpp b/mmdb2/mmdb_io_file.cpp
new file mode 100644
index 0000000..606bdf2
--- /dev/null
+++ b/mmdb2/mmdb_io_file.cpp
@@ -0,0 +1,1873 @@
+// $Id: file_.cpp,v 1.29 2012/01/26 17:52:19 ekr Exp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 29.01.10 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_io_file <implementation>
+// ~~~~~~~~~
+// **** Classes : mmdb::io::File - file I/O Support.
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+# include <windows.h>
+# define sleep Sleep
+#else
+# ifndef __UNISTD_H
+# include <unistd.h>
+# endif
+#endif
+
+#include "mmdb_io_file.h"
+
+
+// _WIN32_NEWLINE should be raised when compilinig on Windows in
+// order to enforce Windows' line endings when writing text in
+// files opened for *binary* output. Otherwise, writing text lines
+// in binary files will results in UNIX line endings. Line endings
+// in files, opened for output in text mode, will be always
+// platform-specific.
+
+#ifdef _WIN32_NEWLINE
+// for DOS/WINDOWS machines:
+#define NEWLINE "\r\n"
+#else
+// for UNIX machines:
+#define NEWLINE "\n"
+#endif
+
+namespace mmdb {
+
+ namespace io {
+
+#ifdef _WIN32
+ const char _dir_sep_c = '\\';
+ cpstr _dir_sep = "\\";
+#else
+ const char _dir_sep_c = '/';
+ cpstr _dir_sep = "/";
+#endif
+
+ // =================== Auxilary Functions =========================
+
+ cpstr GetFPath ( pstr FilePath, SYSKEY syskey ) {
+ pstr P;
+
+ if (syskey==syskey_unix)
+ P = strrchr(FilePath,'/');
+ else if (syskey==syskey_win)
+ P = strrchr(FilePath,'\\');
+ else if (syskey==syskey_all) {
+ P = strrchr(FilePath,'/');
+ if (!P) P = strrchr(FilePath,'\\');
+ } else
+ P = NULL;
+
+ if (P) {
+ P = P + 1;
+ *P = char(0);
+ } else
+ FilePath[0] = char(0);
+
+ return FilePath;
+
+ }
+
+ cpstr GetFName ( cpstr FilePath, SYSKEY syskey ) {
+ pstr P;
+ if (syskey==syskey_unix)
+ P = strrchr(FilePath,'/');
+ else if (syskey==syskey_win)
+ P = strrchr(FilePath,'\\');
+ else if (syskey==syskey_all) {
+ P = strrchr(FilePath,'/');
+ if (!P) P = strrchr(FilePath,'\\');
+ } else
+ P = NULL;
+ if (!P) return FilePath;
+ else return P + 1;
+ }
+
+ cpstr GetFExt ( cpstr FilePath ) {
+ pstr P;
+ P = strchr ( GetFName(FilePath),'.');
+ if (!P) return &(FilePath[strlen(FilePath)]);
+ else return P;
+ }
+
+ cpstr ChangeExt ( pstr FilePath, cpstr newExt, SYSKEY syskey ) {
+ int i;
+ i = strlen(FilePath)-1;
+ if (syskey==syskey_unix)
+ while ((i>0) && (FilePath[i]!='.') && (FilePath[i]!='/')) i--;
+ else if (syskey==syskey_win)
+ while ((i>0) && (FilePath[i]!='.') && (FilePath[i]!='\\')) i--;
+ else if (syskey==syskey_all)
+ while ((i>0) && (FilePath[i]!='.') &&
+ (FilePath[i]!='/') && (FilePath[i]!='\\')) i--;
+ if (FilePath[i]=='.') {
+ FilePath[i+1] = char(0);
+ strcat ( FilePath,newExt );
+ } else {
+ strcat ( FilePath,"." );
+ strcat ( FilePath,newExt );
+ }
+ return FilePath;
+ }
+
+ bool FileExists ( cpstr FileName, PFile f ) {
+ PFile g;
+ bool B;
+ if (FileName) {
+ if (!f) g = new File();
+ else g = f;
+ g->assign ( FileName );
+ B = g->exists();
+ if (!f) delete g;
+ return B;
+ } else
+ return false;
+ }
+
+
+ // ======================== File Class ========================
+
+ #define ARCH_NONE 0
+ #define ARCH_GZIP 1
+ #define ARCH_COMPRESS 2
+ #define ARCH_ENFORCE 3
+
+ File::File ( word BufSize ) {
+ Buf_Size = BufSize;
+ BufLen = 0;
+ BufInc = 1;
+ EofFile = false;
+ hFile = NULL;
+ FName = NULL;
+ BufCnt = 0;
+ IOBuf = NULL;
+ IOSuccess = true;
+ TextMode = false;
+ UniBin = false;
+ StdIO = false;
+ gzipIO = ARCH_NONE;
+ memIO = false;
+ }
+
+ File::~File() {
+ shut ();
+ FreeBuffer();
+ }
+
+ void File::FreeBuffer () {
+ if (IOBuf) {
+ if (!memIO) delete[] IOBuf;
+ IOBuf = NULL;
+ }
+ if (FName) {
+ delete[] FName;
+ FName = NULL;
+ }
+ }
+
+ void File::assign ( cpstr FileName, bool Text, bool UniB,
+ GZ_MODE gzMode ) {
+ pstr p;
+
+ shut();
+
+ FreeBuffer();
+
+ CreateCopy ( FName,FileName );
+ StdIO = (!strcmp(FName,"stdin" )) ||
+ (!strcmp(FName,"stdout")) ||
+ (!strcmp(FName,"stderr"));
+
+ if (StdIO) TextMode = true;
+ else TextMode = Text;
+
+ UniBin = UniB;
+
+ gzipMode = gzMode;
+ gzipIO = ARCH_NONE;
+ if ((gzipMode==GZM_ENFORCE) || (gzipMode==GZM_ENFORCE_GZIP))
+ gzipIO = ARCH_GZIP;
+ else if (gzipMode==GZM_ENFORCE_COMPRESS)
+ gzipIO = ARCH_COMPRESS;
+ else if (gzipMode==GZM_CHECK) {
+ p = strrchr ( FName,'.' );
+ if (p) {
+ if (!strcmp(p,".gz")) gzipIO = ARCH_GZIP;
+ else if (!strcmp(p,".Z")) gzipIO = ARCH_COMPRESS;
+ }
+ }
+
+ memIO = false;
+
+ }
+
+
+ void File::assign ( word poolSize, word sizeInc, pstr filePool ) {
+
+ shut ();
+ FreeBuffer();
+
+ IOBuf = (pstr)filePool;
+ BufLen = poolSize;
+ FLength = poolSize;
+ BufInc = sizeInc;
+ BufCnt = 0;
+
+ memIO = true;
+ gzipMode = GZM_NONE;
+ gzipIO = ARCH_NONE;
+
+ }
+
+ void File::GetFilePool ( pstr & filePool, word & fileSize ) {
+ if (memIO) {
+ filePool = IOBuf;
+ fileSize = FLength;
+ IOBuf = NULL;
+ BufLen = 0;
+ BufCnt = 0;
+ FLength = 0;
+ } else {
+ filePool = NULL;
+ fileSize = 0;
+ }
+ }
+
+ static pstr gzip_path = pstr("gzip ");
+ static pstr ungzip_path = pstr("gzip -dc ");
+ static pstr compress_path = pstr("compress ");
+ static pstr uncompress_path = pstr("uncompress -c ");
+
+ void SetGZIPPath ( pstr gzipPath, pstr ungzipPath ) {
+ if (!gzipPath) gzip_path = pstr("gzip ");
+ else gzip_path = gzipPath;
+ if (!ungzipPath) ungzip_path = pstr("gzip -d ");
+ else ungzip_path = ungzipPath;
+ }
+
+ void SetCompressPath ( pstr compressPath, pstr uncompressPath ) {
+ if (!compressPath) compress_path = pstr("compress ");
+ else compress_path = compressPath;
+ if (!uncompressPath) uncompress_path = pstr("uncompress -c ");
+ else uncompress_path = uncompressPath;
+ }
+
+
+ bool File::reset ( bool ReadOnly, int retry ) {
+ #ifndef _MSC_VER
+ pstr p;
+ int i;
+ #endif
+
+ if (memIO) {
+
+ shut();
+ if (!IOBuf) return false;
+ BufCnt = 0;
+ IOSuccess = true;
+
+ } else {
+
+ if (!FName) return false;
+ shut();
+ BufLen = 0;
+ BufCnt = 0;
+
+ if (!strcmp(FName,"stdin")) {
+
+ hFile = stdin;
+ StdIO = true;
+ TextMode = true;
+ FLength = 1;
+ EofFile = false;
+ IOSuccess = true;
+
+ } else {
+
+ StdIO = false;
+ if (gzipIO==ARCH_GZIP) {
+ #ifndef _MSC_VER
+ p = NULL;
+ CreateConcat ( p,ungzip_path,FName );
+ for (i=0;(i<=retry) && (!hFile);i++) {
+ if (i>0) sleep ( 1 );
+ hFile = popen ( p,"r" );
+ }
+ if (p) delete[] p;
+ #endif
+
+ } else if (gzipIO==ARCH_COMPRESS) {
+ #ifndef _MSC_VER
+ p = NULL;
+ CreateConcat ( p,uncompress_path,FName );
+ for (i=0;(i<=retry) && (!hFile);i++) {
+ if (i>0) sleep ( 1 );
+ hFile = popen ( p,"r" );
+ }
+ if (p) delete[] p;
+ #endif
+
+ } else {
+
+ #ifndef _MSC_VER
+ for (i=0;(i<=retry) && (!hFile);i++) {
+ if (i>0) sleep ( 1 );
+ if (TextMode) {
+ if (ReadOnly) hFile = fopen ( FName,"rt" );
+ else hFile = fopen ( FName,"r+t" );
+ } else {
+ if (ReadOnly) hFile = fopen ( FName,"rb" );
+ else hFile = fopen ( FName,"r+b" );
+ }
+ }
+ #endif
+
+ }
+
+ if (hFile) {
+ if (gzipIO==ARCH_NONE) {
+ fseek ( hFile,0L,SEEK_END );
+ FLength = ftell ( hFile );
+ fseek ( hFile,0L,SEEK_SET );
+ EofFile = (FLength<=0);
+ } else {
+ FLength = 1;
+ EofFile = false;
+ }
+ IOSuccess = true;
+ } else {
+ EofFile = true;
+ IOSuccess = false;
+ }
+
+ }
+
+ }
+
+ return IOSuccess;
+
+ }
+
+ bool File::rewrite() {
+ #ifndef _MSC_VER
+ pstr p;
+ #endif
+
+ if (memIO) {
+
+ shut();
+ FreeBuffer();
+ IOBuf = new char[BufLen];
+ BufCnt = 0;
+ FLength = 0;
+ IOSuccess = true;;
+
+ } else {
+
+ if (!FName) return false;
+ shut();
+ BufLen = 0;
+ BufCnt = 0;
+
+ if (gzipIO==ARCH_GZIP) {
+ #ifndef _MSC_VER
+ p = NULL;
+ CreateConcat ( p,gzip_path,pstr(" > "),FName );
+ hFile = popen ( p,"w" );
+ if (p) delete[] p;
+ #else
+ hFile = NULL;
+ #endif
+ StdIO = false;
+ } else if (gzipIO==ARCH_COMPRESS) {
+ #ifndef _MSC_VER
+ p = NULL;
+ CreateConcat ( p,compress_path,pstr(" > "),FName );
+ hFile = popen ( p,"w" );
+ if (p) delete[] p;
+ #else
+ hFile = NULL;
+ #endif
+ StdIO = false;
+ } else if (!TextMode) {
+ hFile = fopen ( FName,"w+b" );
+ StdIO = false;
+ } else if (!strcmp(FName,"stdout")) {
+ hFile = stdout;
+ StdIO = true;
+ } else if (!strcmp(FName,"stderr")) {
+ hFile = stderr;
+ StdIO = true;
+ } else {
+ hFile = fopen ( FName,"w+t" );
+ StdIO = false;
+ }
+
+ FLength = 0;
+ IOSuccess = (hFile!=NULL);
+
+ }
+
+ return IOSuccess;
+
+ }
+
+
+ bool File::append() {
+ #ifndef _MSC_VER
+ pstr p;
+ #endif
+
+ if (memIO) {
+
+ if (!IOBuf) {
+ IOBuf = new char[BufLen];
+ BufCnt = 0;
+ }
+ FLength = BufCnt;
+ IOSuccess = true;
+
+ } else {
+
+ if (!FName) return false;
+
+ shut();
+ BufLen = 0;
+ BufCnt = 0;
+ if (gzipIO==ARCH_GZIP) {
+ #ifndef _MSC_VER
+ p = NULL;
+ CreateConcat ( p,gzip_path,pstr(" >> "),FName );
+ hFile = popen ( p,"w" );
+ if (p) delete[] p;
+ #else
+ hFile = NULL;
+ #endif
+ StdIO = false;
+ } else if (gzipIO==ARCH_COMPRESS) {
+ #ifndef _MSC_VER
+ p = NULL;
+ CreateConcat ( p,compress_path,pstr(" >> "),FName );
+ hFile = popen ( p,"w" );
+ if (p) delete[] p;
+ #else
+ hFile = NULL;
+ #endif
+ StdIO = false;
+ } else if (!TextMode) {
+ hFile = fopen ( FName,"ab" );
+ StdIO = false;
+ } else if (!strcmp(FName,"stdout")) {
+ hFile = stdout;
+ StdIO = true;
+ } else if (!strcmp(FName,"stderr")) {
+ hFile = stderr;
+ StdIO = true;
+ } else {
+ hFile = fopen ( FName,"at" );
+ StdIO = false;
+ }
+
+ FLength = 0;
+ IOSuccess = hFile!=NULL;
+
+ }
+
+ return IOSuccess;
+
+ }
+
+ bool File::erase() {
+ if (!FName) return false;
+ shut();
+ if (!StdIO) {
+ BufLen = 0;
+ BufCnt = 0;
+ if (FName)
+ IOSuccess = (remove(FName)==0);
+ FLength = 0;
+ } else
+ IOSuccess = true;
+ return IOSuccess;
+ }
+
+ bool File::exists() {
+
+ if (memIO) {
+
+ IOSuccess = (IOBuf!=NULL);
+
+ } else {
+
+ if (!FName) return false;
+ shut();
+ if (!StdIO) {
+ hFile = fopen ( FName,"r" );
+ IOSuccess = (hFile!=NULL);
+ BufLen = 0;
+ BufCnt = 0;
+ FLength = 0;
+ if (hFile) fclose ( hFile );
+ } else
+ IOSuccess = true;
+ hFile = NULL;
+ }
+
+ return IOSuccess;
+
+ }
+
+ bool File::parse ( cpstr FileName ) {
+ UNUSED_ARGUMENT(FileName);
+ return true;
+ }
+
+ bool File::rename ( cpstr NewFileName ) {
+ if (!FName) return false;
+ shut();
+ if (!StdIO)
+ IOSuccess = (::rename(FName,NewFileName)==0);
+ if (IOSuccess) assign ( NewFileName,TextMode,UniBin,gzipMode );
+ return IOSuccess;
+ }
+
+ long File::Position() {
+ // do not use on text files
+
+ if (memIO) return BufCnt;
+
+ if (hFile==NULL) return 0L;
+ return ftell ( hFile );
+
+ }
+
+ bool File::seek ( long Position ) {
+ // do not use on text files
+ if (memIO) {
+ if (Position<=(long)BufLen) {
+ BufCnt = Position;
+ IOSuccess = true;
+ } else
+ IOSuccess = false;
+ return IOSuccess;
+ } else if (hFile==NULL)
+ return false;
+ else if (!StdIO) {
+ IOSuccess = fseek(hFile,Position,SEEK_SET)==0;
+ return IOSuccess;
+ } else
+ return true;
+ }
+
+ bool File::FileEnd() {
+
+ if (memIO) return ((long)BufCnt>=FLength);
+
+ if (TextMode) {
+ if (EofFile || ((!hFile) && (!StdIO)))
+ return true;
+ if (feof(hFile)==0)
+ return false;
+ return true;
+ }
+
+ return EofFile && (BufLen==0);
+
+ }
+
+ void File::flush () {
+
+ if (hFile!=NULL) {
+ if (!StdIO) {
+ #ifndef _MSC_VER
+ if (gzipIO==ARCH_NONE)
+ fflush ( hFile );
+ #else
+ fflush ( hFile );
+ #endif
+ }
+ }
+ }
+
+ void File::shut () {
+
+ if (hFile!=NULL) {
+ if (!StdIO) {
+ #ifndef _MSC_VER
+ if (gzipIO!=ARCH_NONE) pclose ( hFile );
+ else fclose ( hFile );
+ #else
+ fclose ( hFile );
+ #endif
+ }
+ hFile = NULL;
+ }
+
+ }
+
+ bool File::isOpen() {
+ if (memIO) return (IOBuf!=NULL);
+ return (hFile!=NULL);
+ }
+
+ word File::ReadLine ( pstr Line, word MaxLen ) {
+ word LCnt;
+ int Done;
+ bool HSuccess = IOSuccess;
+
+ if (memIO) {
+
+ LCnt = 0;
+ while (((long)BufCnt<FLength) &&
+ (LCnt<MaxLen-1) &&
+ (IOBuf[BufCnt]!='\r') &&
+ (IOBuf[BufCnt]!='\n') )
+ Line[LCnt++] = IOBuf[BufCnt++];
+ Line[LCnt] = char(0);
+
+ while (((long)BufCnt<FLength) &&
+ (IOBuf[BufCnt]!='\r') &&
+ (IOBuf[BufCnt]!='\n') )
+ BufCnt++;
+
+ if ((long)BufCnt<FLength) {
+ if (IOBuf[BufCnt]=='\r') {
+ BufCnt++;
+ if ((long)BufCnt<FLength) {
+ if (IOBuf[BufCnt]=='\n') BufCnt++;
+ }
+ } else if (IOBuf[BufCnt]=='\n') {
+ BufCnt++;
+ if ((long)BufCnt<FLength) {
+ if (IOBuf[BufCnt]=='\r') BufCnt++;
+ }
+ }
+ }
+
+ return LCnt;
+
+ } else {
+
+ if ((!hFile) && (!StdIO)) {
+ Line[0] = char(0);
+ EofFile = true;
+ BufLen = 0;
+ IOSuccess = false;
+ return 0;
+ }
+ if (TextMode) {
+ Line[0] = char(0);
+ if (fgets(Line,MaxLen,hFile)) {
+ LCnt = strlen(Line);
+ while (LCnt>0) {
+ if ((Line[LCnt-1]!='\n') &&
+ (Line[LCnt-1]!='\r')) break;
+ Line[LCnt-1] = char(0);
+ LCnt--;
+ }
+ } else
+ LCnt = 0;
+ return LCnt;
+ } else {
+ if (IOBuf==NULL) {
+ IOBuf = new char[Buf_Size];
+ BufLen = ReadFile ( IOBuf,Buf_Size );
+ IOSuccess = HSuccess;
+ BufCnt = 0;
+ }
+ LCnt = 0;
+ do {
+ while ((BufCnt<BufLen) &&
+ (LCnt<MaxLen-1) &&
+ (IOBuf[BufCnt]!='\r') &&
+ (IOBuf[BufCnt]!='\n') )
+ Line[LCnt++] = IOBuf[BufCnt++];
+ if (BufCnt>=BufLen) {
+ HSuccess = IOSuccess;
+ BufLen = ReadFile ( IOBuf,Buf_Size );
+ IOSuccess = HSuccess;
+ BufCnt = 0;
+ }
+ if (IOBuf[BufCnt]=='\r') Done = 1;
+ else if (IOBuf[BufCnt]=='\n') Done = 2;
+ else Done = 0;
+ if (Done) BufCnt++;
+ if (BufCnt>=BufLen) {
+ HSuccess = IOSuccess;
+ BufLen = ReadFile ( IOBuf,Buf_Size );
+ IOSuccess = HSuccess;
+ BufCnt = 0;
+ }
+ if (BufLen>0) {
+ if (((Done==2) && (IOBuf[BufCnt]=='\r')) ||
+ ((Done==1) && (IOBuf[BufCnt]=='\n')))
+ BufCnt++;
+ }
+ } while ((!Done) && (LCnt<MaxLen-1) && (BufLen>0));
+ Line[LCnt] = char(0);
+ return LCnt;
+ }
+
+ }
+
+ }
+
+ word File::ReadNonBlankLine ( pstr S, word MaxLen ) {
+ word i,j;
+ do {
+ j = ReadLine ( S,MaxLen );
+ i = 0;
+ while ((i<j) && (S[i]==' ')) i++;
+ } while ((i>=j) && (!FileEnd()));
+ if (i>=j) {
+ S[0] = char(0);
+ j = 0;
+ }
+ return j;
+ }
+
+
+ bool File::WriteLine ( cpstr Line ) {
+ if ((!memIO) && TextMode) {
+ if (hFile==NULL) return false;
+ fputs ( Line,hFile );
+ // return (fputs(NEWLINE,hFile)>=0);
+ return (fputs("\n",hFile)>=0);
+ } else {
+ if (WriteFile(Line,strlen(Line)))
+ return WriteFile ( (void *)NEWLINE,strlen(NEWLINE) );
+ else return false;
+ }
+ }
+
+ bool File::Write ( cpstr Line ) {
+ if ((!memIO) && TextMode) {
+ if (hFile==NULL) return false;
+ return (fputs(Line,hFile)>=0);
+ } else
+ return WriteFile(Line,strlen(Line));
+ }
+
+ bool File::Write ( realtype V, int length ) {
+ char N[50];
+ sprintf ( N,"%-.*g",length,V );
+ if ((!memIO) && TextMode) {
+ if (hFile==NULL) return false;
+ return (fputs(N,hFile)>=0);
+ } else
+ return WriteFile(N,strlen(N));
+ }
+
+ bool File::Write ( int iV, int length ) {
+ char N[50];
+ sprintf ( N,"%*i",length,iV );
+ if ((!memIO) && TextMode) {
+ if (hFile==NULL) return false;
+ return (fputs(N,hFile)>=0);
+ } else
+ return WriteFile(N,strlen(N));
+ }
+
+ bool File::LF() {
+ if ((!memIO) && TextMode) {
+ if (hFile==NULL) return false;
+ // return (fputs(NEWLINE,hFile)>=0);
+ return (fputs("\n",hFile)>=0);
+ } else
+ return WriteFile ( (void *)NEWLINE,strlen(NEWLINE) );
+ }
+
+ bool File::WriteDataLine ( realtype X, realtype Y, int length ) {
+ Write ( pstr(" ") );
+ Write ( X,length );
+ Write ( pstr(" ") );
+ Write ( Y,length );
+ return LF();
+ }
+
+ bool File::WriteParameter ( cpstr S, realtype X,
+ int ParColumn, int length ) {
+ int l=strlen(S);
+ if ((!memIO) && TextMode) {
+ fputs ( S,hFile );
+ while (l<ParColumn) {
+ fputs ( " ",hFile );
+ l++;
+ }
+ } else {
+ WriteFile ( S,l );
+ while (l<ParColumn) {
+ WriteFile ( (void *)" ",1 );
+ l++;
+ }
+ }
+ Write ( X,length );
+ return LF();
+ }
+
+ bool File::WriteParameters ( cpstr S, int n_X, rvector X,
+ int ParColumn, int length ) {
+ int i;
+ int l=strlen(S);
+ if ((!memIO) && TextMode) {
+ fputs ( S,hFile );
+ while (l<ParColumn) {
+ fputs ( " ",hFile );
+ l++;
+ }
+ } else {
+ WriteFile ( S,l );
+ while (l<ParColumn) {
+ WriteFile ( (void *)" ",1 );
+ l++;
+ }
+ }
+ for (i=0;i<n_X;i++) {
+ Write ( X[i],length );
+ if (i!=n_X-1) WriteFile ( (void *)", ",2 );
+ }
+ return LF();
+ }
+
+ bool File::ReadParameter ( pstr S, realtype & X,
+ int ParColumn ) {
+ ReadLine ( S );
+ if ((int)strlen(S)>ParColumn) {
+ // X = atof ( &(S[ParColumn]) );
+ X = GetNumber ( &(S[ParColumn]) );
+ return true;
+ } else {
+ X = 0.0;
+ return false;
+ }
+ }
+
+ bool File::ReadParameters ( pstr S, int & n_X, rvector X,
+ int MaxLen, int ParColumn ) {
+ pstr S1,S2;
+ ReadLine ( S,MaxLen );
+ if ((int)strlen(S)>ParColumn) {
+ n_X = 0;
+ S2 = &(S[ParColumn]);
+ S1 = S2;
+ while (*S1!=char(0)) {
+ if (*S1==',') *S1 = ' ';
+ S1++;
+ }
+ while (*S2!=char(0)) {
+ S1 = S2;
+ X[n_X] = strtod ( S1,&S2 );
+ n_X++;
+ while ((*S2!=char(0)) && (*S2==' ')) S2++;
+ }
+ return true;
+ } else {
+ n_X = 0;
+ X[0] = 0.0;
+ return false;
+ }
+ }
+
+ bool File::ReadParameter ( pstr S, int & X,
+ int ParColumn ) {
+ realtype V;
+ if (ReadParameter(S,V,ParColumn)) {
+ X = mround(V);
+ return true;
+ } else {
+ X = 0;
+ return false;
+ }
+ }
+
+ bool File::CreateWrite ( cpstr Line ) {
+ wordUniBin wUB;
+ word i;
+ if (UniBin) {
+ if (Line) {
+ i = strlen(Line)+1;
+ word2UniBin ( i,wUB );
+ if (WriteFile(wUB,sizeof(wordUniBin)))
+ return WriteFile ( Line,i );
+ else return false;
+ } else {
+ i = 0;
+ word2UniBin ( i,wUB );
+ return WriteFile ( wUB,sizeof(wordUniBin) );
+ }
+ } else {
+ if (Line) {
+ i = strlen(Line)+1;
+ if (WriteFile(&i,sizeof(i)))
+ return WriteFile ( Line,i );
+ else return false;
+ } else {
+ i = 0;
+ return WriteFile ( &i,sizeof(i) );
+ }
+ }
+ }
+
+ #define _max_dyn_string_len 1073741824
+
+ word File::CreateRead ( pstr & Line ) {
+ wordUniBin wUB;
+ word i;
+ //unsigned short int i;
+ if (Line) {
+ delete[] Line;
+ Line = NULL;
+ }
+ if (UniBin) {
+ ReadFile ( wUB,sizeof(wordUniBin) );
+ UniBin2word ( wUB,i );
+ } else
+ ReadFile ( &i,sizeof(i) );
+ if ((i>0) && (i<_max_dyn_string_len)) {
+ Line = new char[i];
+ ReadFile ( Line,i );
+ }
+ return i;
+ }
+
+ bool File::WriteTerLine ( cpstr Line, bool longLine ) {
+ wordUniBin wUB;
+ word ll;
+ byte sl;
+ bool B;
+ if (Line) ll = strlen(Line);
+ else ll = 0;
+ if (!longLine) {
+ sl = byte(ll);
+ B = WriteFile ( &sl,sizeof(sl) );
+ } else if (UniBin) {
+ word2UniBin ( ll,wUB );
+ B = WriteFile ( wUB,sizeof(wordUniBin) );
+ } else
+ B = WriteFile ( &ll,sizeof(ll) );
+ if (B && (ll>0)) B = WriteFile ( Line,ll );
+ return B;
+ }
+
+ word File::ReadTerLine ( pstr Line, bool longLine ) {
+ wordUniBin wUB;
+ word ll;
+ byte sl;
+ if (!longLine) {
+ ReadFile ( &sl,sizeof(sl) );
+ ll = sl;
+ } else if (UniBin) {
+ ReadFile ( wUB,sizeof(wordUniBin) );
+ UniBin2word ( wUB,ll );
+ } else
+ ReadFile ( &ll,sizeof(ll) );
+ if (ll>0) ReadFile ( Line,ll );
+ Line[ll] = char(0);
+ return ll+1;
+ }
+
+ word File::ReadFile ( void * Buffer, word Count ) {
+ word Cnt;
+ if (memIO) {
+ Cnt = WMin(Count,FLength-BufCnt);
+ if (Cnt>0) {
+ memcpy ( Buffer,&(IOBuf[BufCnt]),Cnt );
+ BufCnt += Cnt;
+ }
+ IOSuccess = (Cnt==Count);
+ EofFile = ((Cnt<Count) || ((long)BufCnt>=FLength));
+ return Cnt;
+ } else if (hFile) {
+ Cnt = (word)fread ( Buffer,1,Count,hFile );
+ EofFile = (Cnt<Count) ||
+ ((gzipIO==ARCH_NONE) && (Position()==FLength));
+ IOSuccess = (Cnt==Count);
+ return Cnt;
+ } else
+ return 0;
+ }
+
+ bool File::WriteFile ( const void * Buffer, word Count ) {
+ pstr IOB;
+ word Cnt;
+ long Pos;
+
+ if (memIO) {
+
+ Cnt = BufCnt + Count;
+ if (Cnt>BufLen) {
+ Cnt += BufInc;
+ IOB = new char[Cnt];
+ if (IOBuf) {
+ memcpy ( IOB,IOBuf,BufCnt );
+ delete[] IOBuf;
+ }
+ IOBuf = IOB;
+ BufLen = Cnt;
+ }
+ memcpy ( &(IOBuf[BufCnt]),Buffer,Count );
+ BufCnt += Count;
+ FLength = BufCnt;
+ IOSuccess = true;
+
+ } else {
+
+ if (hFile==NULL) return false;
+ Cnt = (word)fwrite ( Buffer,1,Count,hFile );
+ Pos = Position();
+ if (Pos>FLength) FLength = Pos;
+ IOSuccess = Cnt==Count;
+
+ }
+
+ return IOSuccess;
+
+ }
+
+ bool File::WriteReal ( realtype * V ) {
+ realUniBin rUB;
+ if (UniBin) {
+ real2UniBin ( *V,rUB );
+ return WriteFile ( rUB,sizeof(realUniBin) );
+ } else
+ return WriteFile ( V,sizeof(realtype) );
+ }
+
+ bool File::WriteFloat ( realtype * V ) {
+ floatUniBin fUB;
+ float fV;
+ if (UniBin) {
+ float2UniBin ( *V,fUB );
+ return WriteFile ( fUB,sizeof(floatUniBin) );
+ } else {
+ fV = (float)*V;
+ return WriteFile ( &fV,sizeof(float) );
+ }
+ }
+
+ bool File::WriteInt ( int * I ) {
+ intUniBin iUB;
+ if (UniBin) {
+ int2UniBin ( *I,iUB );
+ return WriteFile ( iUB,sizeof(intUniBin) );
+ } else
+ return WriteFile ( I,sizeof(int) );
+ }
+
+ bool File::WriteShort ( short * S ) {
+ shortUniBin sUB;
+ if (UniBin) {
+ short2UniBin ( *S,sUB );
+ return WriteFile ( sUB,sizeof(shortUniBin) );
+ } else
+ return WriteFile ( S,sizeof(short) );
+ }
+
+ bool File::WriteLong ( long * L ) {
+ longUniBin lUB;
+ if (UniBin) {
+ long2UniBin ( *L,lUB );
+ return WriteFile ( lUB,sizeof(longUniBin) );
+ } else
+ return WriteFile ( L,sizeof(long) );
+ }
+
+ bool File::WriteBool ( bool * B ) {
+ intUniBin iUB;
+ int k;
+ if (UniBin) {
+ if (*B) k = 1;
+ else k = 0;
+ int2UniBin ( k,iUB );
+ return WriteFile ( iUB,sizeof(intUniBin) );
+ } else
+ return WriteFile ( B,sizeof(bool) );
+ }
+
+ bool File::WriteByte ( byte * B ) {
+ return WriteFile ( B,sizeof(byte) );
+ }
+
+ bool File::WriteWord ( word * W ) {
+ wordUniBin wUB;
+ if (UniBin) {
+ word2UniBin ( *W,wUB );
+ return WriteFile ( wUB,sizeof(wordUniBin) );
+ } else
+ return WriteFile ( W,sizeof(word) );
+ }
+
+ bool File::ReadReal ( realtype * V ) {
+ realUniBin rUB;
+ if (UniBin) {
+ if (ReadFile(rUB,sizeof(realUniBin))==sizeof(realUniBin)) {
+ UniBin2real ( rUB,*V );
+ return true;
+ } else
+ return false;
+ } else
+ return ( ReadFile(V,sizeof(realtype))==sizeof(realtype) );
+ }
+
+ bool File::ReadFloat ( realtype * V ) {
+ floatUniBin fUB;
+ float fV;
+ if (UniBin) {
+ if (ReadFile(fUB,sizeof(floatUniBin))==sizeof(floatUniBin)) {
+ UniBin2float ( fUB,*V );
+ return true;
+ }
+ } else if (ReadFile(&fV,sizeof(float))==sizeof(float)) {
+ *V = fV;
+ return true;
+ }
+ return false;
+ }
+
+ bool File::ReadInt ( int * I ) {
+ intUniBin iUB;
+ if (UniBin) {
+ if (ReadFile(iUB,sizeof(intUniBin))==sizeof(intUniBin)) {
+ UniBin2int ( iUB,*I );
+ return true;
+ } else
+ return false;
+ } else
+ return ( ReadFile(I,sizeof(int))==sizeof(int) );
+ }
+
+ bool File::ReadShort ( short * S ) {
+ shortUniBin sUB;
+ if (UniBin) {
+ if (ReadFile(sUB,sizeof(shortUniBin))==sizeof(shortUniBin)) {
+ UniBin2short ( sUB,*S );
+ return true;
+ } else
+ return false;
+ } else
+ return ( ReadFile(S,sizeof(short))==sizeof(short) );
+ }
+
+ bool File::ReadLong ( long * L ) {
+ longUniBin lUB;
+ if (UniBin) {
+ if (ReadFile(lUB,sizeof(longUniBin))==sizeof(longUniBin)) {
+ UniBin2long ( lUB,*L );
+ return true;
+ } else
+ return false;
+ } else
+ return ( ReadFile(L,sizeof(long))==sizeof(long) );
+ }
+
+ bool File::ReadBool ( bool * B ) {
+ intUniBin iUB;
+ int k;
+ if (UniBin) {
+ if (ReadFile(iUB,sizeof(intUniBin))==sizeof(intUniBin)) {
+ UniBin2int ( iUB,k );
+ *B = (k!=0);
+ return true;
+ } else
+ return false;
+ } else
+ return ( ReadFile(B,sizeof(bool))==sizeof(bool) );
+ }
+
+ bool File::ReadByte ( byte * B ) {
+ return ( ReadFile(B,sizeof(byte))==sizeof(byte) );
+ }
+
+ bool File::ReadWord ( word * W ) {
+ wordUniBin wUB;
+ if (UniBin) {
+ if (ReadFile(wUB,sizeof(wordUniBin))==sizeof(wordUniBin)) {
+ UniBin2word ( wUB,*W );
+ return true;
+ } else
+ return false;
+ } else
+ return ( ReadFile(W,sizeof(word))==sizeof(word) );
+ }
+
+ bool File::AddReal ( realtype * V ) {
+ realtype x;
+ if (ReadReal(&x)) {
+ *V += x;
+ return true;
+ }
+ return false;
+ }
+
+ bool File::AddFloat ( realtype * V ) {
+ realtype x;
+ if (ReadFloat(&x)) {
+ *V += x;
+ return true;
+ }
+ return false;
+ }
+
+
+ bool File::AddInt ( int * I ) {
+ int k;
+ if (ReadInt(&k)) {
+ *I += k;
+ return true;
+ }
+ return false;
+ }
+
+ bool File::AddShort ( short * S ) {
+ short k;
+ if (ReadShort(&k)) {
+ *S += k;
+ return true;
+ }
+ return false;
+ }
+
+ bool File::AddLong ( long * L ) {
+ long k;
+ if (ReadLong(&k)) {
+ *L += k;
+ return true;
+ }
+ return false;
+ }
+
+ bool File::AddByte ( byte * B ) {
+ byte k;
+ if (ReadByte(&k)) {
+ *B += k;
+ return true;
+ }
+ return false;
+ }
+
+ bool File::AddWord ( word * W ) {
+ word k;
+ if (ReadWord(&k)) {
+ *W += k;
+ return true;
+ }
+ return false;
+ }
+
+ bool File::WriteVector ( rvector V, int len, int Shift ) {
+ intUniBin iUB;
+ realUniBin rUB;
+ int i;
+ int l = len;
+ if (V==NULL) l = 0;
+ if (UniBin) {
+ int2UniBin ( l,iUB );
+ WriteFile ( iUB,sizeof(intUniBin) );
+ for (i=0;i<len;i++) {
+ real2UniBin ( V[Shift+i],rUB );
+ WriteFile ( rUB,sizeof(realUniBin) );
+ }
+ } else {
+ WriteFile ( &l,sizeof(l) );
+ if (l>0) WriteFile ( &(V[Shift]),sizeof(realtype)*l );
+ }
+ return IOSuccess;
+ }
+
+ bool File::WriteVector ( ivector iV, int len, int Shift ) {
+ intUniBin iUB;
+ int i;
+ int l = len;
+ if (iV==NULL) l = 0;
+ if (UniBin) {
+ int2UniBin ( l,iUB );
+ WriteFile ( iUB,sizeof(intUniBin) );
+ for (i=0;i<len;i++) {
+ int2UniBin ( iV[Shift+i],iUB );
+ WriteFile ( iUB,sizeof(intUniBin) );
+ }
+ } else {
+ WriteFile ( &l,sizeof(l) );
+ if (l>0) WriteFile ( &(iV[Shift]),sizeof(int)*l );
+ }
+ return IOSuccess;
+ }
+
+ bool File::WriteVector ( lvector lV, int len, int Shift ) {
+ intUniBin iUB;
+ longUniBin lUB;
+ int i;
+ int l = len;
+ if (lV==NULL) l = 0;
+ if (UniBin) {
+ int2UniBin ( l,iUB );
+ WriteFile ( iUB,sizeof(intUniBin) );
+ for (i=0;i<len;i++) {
+ long2UniBin ( lV[Shift+i],lUB );
+ WriteFile ( lUB,sizeof(longUniBin) );
+ }
+ } else {
+ WriteFile ( &l,sizeof(l) );
+ if (l>0) WriteFile ( &(lV[Shift]),sizeof(long)*l );
+ }
+ return IOSuccess;
+ }
+
+ bool File::WriteVector ( bvector B, int len, int Shift ) {
+ intUniBin iUB;
+ int l = len;
+ if (B==NULL) l = 0;
+ if (UniBin) {
+ int2UniBin ( l,iUB );
+ WriteFile ( iUB,sizeof(intUniBin) );
+ } else
+ WriteFile ( &l,sizeof(l) );
+ if (l>0) WriteFile ( &(B[Shift]),sizeof(byte)*l );
+ return IOSuccess;
+ }
+
+ bool File::ReadVector ( rvector V, int maxlen, int Shift ) {
+ intUniBin iUB;
+ realUniBin rUB;
+ int i,l,ll;
+ realtype B;
+ if (UniBin) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,l );
+ if (IOSuccess && (l>0)) {
+ ll = IMin(l,maxlen);
+ if (V)
+ for (i=0;i<=ll;i++) {
+ ReadFile ( rUB,sizeof(realUniBin) );
+ UniBin2real ( rUB,V[Shift+i] );
+ }
+ for (i=ll+1;i<=l;i++)
+ ReadFile ( rUB,sizeof(realUniBin) );
+ }
+ } else {
+ ReadFile ( &l,sizeof(l) );
+ if (IOSuccess && (l>0)) {
+ ll = IMin(l,maxlen);
+ if (V) ReadFile ( &(V[Shift]),sizeof(realtype)*ll );
+ for (i=ll+1;i<=l;i++) ReadFile ( &B,sizeof(B) );
+ }
+ }
+ return IOSuccess;
+ }
+
+ bool File::ReadVector ( ivector iV, int maxlen, int Shift ) {
+ intUniBin iUB;
+ int i,l,ll,iB;
+ if (UniBin) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,l );
+ if (IOSuccess && (l>0)) {
+ ll = IMin(l,maxlen);
+ if (iV)
+ for (i=0;i<=ll;i++) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,iV[Shift+i] );
+ }
+ for (i=ll+1;i<=l;i++)
+ ReadFile ( iUB,sizeof(intUniBin) );
+ }
+ } else {
+ ReadFile ( &l,sizeof(l) );
+ if (IOSuccess && (l>0)) {
+ ll = IMin(l,maxlen);
+ if (iV) ReadFile ( &(iV[Shift]),sizeof(int)*ll );
+ for (i=ll+1;i<=l;i++) ReadFile ( &iB,sizeof(iB) );
+ }
+ }
+ return IOSuccess;
+ }
+
+ bool File::ReadVector ( lvector lV, int maxlen, int Shift ) {
+ intUniBin iUB;
+ longUniBin lUB;
+ int i,l,ll;
+ long lB;
+ if (UniBin) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,l );
+ if (IOSuccess && (l>0)) {
+ ll = IMin(l,maxlen);
+ if (lV)
+ for (i=0;i<=ll;i++) {
+ ReadFile ( lUB,sizeof(longUniBin) );
+ UniBin2long ( lUB,lV[Shift+i] );
+ }
+ for (i=ll+1;i<=l;i++)
+ ReadFile ( lUB,sizeof(longUniBin) );
+ }
+ } else {
+ ReadFile ( &l,sizeof(l) );
+ if (IOSuccess && (l>0)) {
+ ll = IMin(l,maxlen);
+ if (lV) ReadFile ( &(lV[Shift]),sizeof(long)*ll );
+ for (i=ll+1;i<=l;i++) ReadFile ( &lB,sizeof(lB) );
+ }
+ }
+ return IOSuccess;
+ }
+
+ bool File::ReadVector ( bvector B, int maxlen, int Shift ) {
+ intUniBin iUB;
+ int i,l,ll;
+ byte t;
+ if (UniBin) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,l );
+ } else
+ ReadFile ( &l,sizeof(l) );
+ if (IOSuccess && (l>0)) {
+ ll = IMin(l,maxlen);
+ if (B) ReadFile ( &(B[Shift]),sizeof(byte)*ll );
+ for (i=ll+1;i<=l;i++) ReadFile ( &t,sizeof(t) );
+ }
+ return IOSuccess;
+ }
+
+ bool File::CreateReadVector ( rvector & V, int & len,
+ int Shift ) {
+ intUniBin iUB;
+ realUniBin rUB;
+ int i;
+ realtype B;
+ FreeVectorMemory ( V,Shift );
+ if (UniBin) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,len );
+ if (IOSuccess && (len>0)) {
+ GetVectorMemory ( V,len,Shift );
+ if (V)
+ for (i=0;i<len;i++) {
+ ReadFile ( rUB,sizeof(realUniBin) );
+ UniBin2real ( rUB,V[Shift+i] );
+ }
+ else for (i=0;i<len;i++)
+ ReadFile ( rUB,sizeof(realUniBin) );
+ }
+ } else {
+ ReadFile ( &len,sizeof(len) );
+ if (IOSuccess && (len>0)) {
+ GetVectorMemory ( V,len,Shift );
+ if (V) ReadFile ( &(V[Shift]),sizeof(realtype)*len );
+ else for (i=0;i<len;i++)
+ ReadFile ( &B,sizeof(B) );
+ }
+ }
+ return IOSuccess;
+ }
+
+ bool File::CreateReadVector ( rvector & V, int Shift ) {
+ int len;
+ return CreateReadVector ( V,len,Shift );
+ }
+
+ bool File::CreateReadVector ( ivector & iV, int & len,
+ int Shift ) {
+ intUniBin iUB;
+ int i,iB;
+ FreeVectorMemory ( iV,Shift );
+ if (UniBin) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,len );
+ if (IOSuccess && (len>0)) {
+ GetVectorMemory ( iV,len,Shift );
+ if (iV)
+ for (i=0;i<len;i++) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,iV[Shift+i] );
+ }
+ else for (i=0;i<len;i++)
+ ReadFile ( iUB,sizeof(intUniBin) );
+ }
+ } else {
+ ReadFile ( &len,sizeof(len) );
+ if (IOSuccess && (len>0)) {
+ GetVectorMemory ( iV,len,Shift );
+ if (iV) ReadFile ( &(iV[Shift]),sizeof(int)*len );
+ else for (i=0;i<len;i++)
+ ReadFile ( &iB,sizeof(iB) );
+ }
+ }
+ return IOSuccess;
+ }
+
+ bool File::CreateReadVector ( ivector & iV, int Shift ) {
+ int len;
+ return CreateReadVector ( iV,len,Shift );
+ }
+
+ bool File::CreateReadVector ( lvector & lV, int & len,
+ int Shift ) {
+ intUniBin iUB;
+ longUniBin lUB;
+ int i;
+ long lB;
+ FreeVectorMemory ( lV,Shift );
+ if (UniBin) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,len );
+ if (IOSuccess && (len>0)) {
+ GetVectorMemory ( lV,len,Shift );
+ if (lV)
+ for (i=0;i<len;i++) {
+ ReadFile ( lUB,sizeof(intUniBin) );
+ UniBin2long ( lUB,lV[Shift+i] );
+ }
+ else for (i=0;i<len;i++)
+ ReadFile ( lUB,sizeof(longUniBin) );
+ }
+ } else {
+ ReadFile ( &len,sizeof(len) );
+ if (IOSuccess && (len>0)) {
+ GetVectorMemory ( lV,len,Shift );
+ if (lV) ReadFile ( &(lV[Shift]),sizeof(long)*len );
+ else for (i=0;i<len;i++)
+ ReadFile ( &lB,sizeof(lB) );
+ }
+ }
+ return IOSuccess;
+ }
+
+ bool File::CreateReadVector ( lvector & lV, int Shift ) {
+ int len;
+ return CreateReadVector ( lV,len,Shift );
+ }
+
+
+ bool File::CreateReadVector ( bvector & B, int & len,
+ int Shift ) {
+ intUniBin iUB;
+ int i;
+ byte t;
+ FreeVectorMemory ( B,Shift );
+ if (UniBin) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,len );
+ } else
+ ReadFile ( &len,sizeof(len) );
+ if (IOSuccess && (len>0)) {
+ GetVectorMemory ( B,len,Shift );
+ if (B) ReadFile ( &(B[Shift]),sizeof(byte)*len );
+ else for (i=0;i<len;i++)
+ ReadFile ( &t,sizeof(t) );
+ }
+ return IOSuccess;
+ }
+
+ bool File::CreateReadVector ( bvector & B, int Shift ) {
+ int len;
+ return CreateReadVector ( B,len,Shift );
+ }
+
+
+ bool File::WriteMatrix ( rmatrix & A, int N, int M,
+ int ShiftN, int ShiftM ) {
+ intUniBin iUB;
+ realUniBin rUB;
+ int i,j;
+ if (UniBin) {
+ if (!A) {
+ i = 0;
+ int2UniBin ( i,iUB );
+ WriteFile ( iUB,sizeof(intUniBin) );
+ } else {
+ int2UniBin ( N,iUB );
+ WriteFile ( iUB,sizeof(intUniBin) );
+ int2UniBin ( M,iUB );
+ WriteFile ( iUB,sizeof(intUniBin) );
+ for (i=0;i<N;i++)
+ for (j=0;j<M;j++) {
+ real2UniBin ( A[ShiftN+i][ShiftM+j],rUB );
+ WriteFile ( rUB,sizeof(realUniBin) );
+ }
+ }
+ } else if (!A) {
+ i = 0;
+ WriteFile ( &i,sizeof(i) );
+ } else {
+ WriteFile ( &N,sizeof(N) );
+ WriteFile ( &M,sizeof(M) );
+ for (i=0;i<N;i++)
+ WriteFile ( &(A[ShiftN][ShiftM]),sizeof(realtype)*M );
+ }
+ return IOSuccess;
+ }
+
+ bool File::CreateReadMatrix ( rmatrix & A, int ShiftN,
+ int ShiftM ) {
+ int N,M;
+ return CreateReadMatrix ( A,N,M,ShiftN,ShiftM );
+ }
+
+ bool File::CreateReadMatrix ( rmatrix & A, int & N, int & M,
+ int ShiftN, int ShiftM ) {
+ intUniBin iUB;
+ realUniBin rUB;
+ int i,j;
+ FreeMatrixMemory ( A,N,ShiftN,ShiftM );
+ if (UniBin) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,N );
+ if (IOSuccess && (N>0)) {
+ ReadFile ( iUB,sizeof(intUniBin) );
+ UniBin2int ( iUB,M );
+ if (IOSuccess && (M>0)) {
+ GetMatrixMemory ( A,N,M,ShiftN,ShiftM );
+ for (i=0;i<N;i++)
+ for (j=0;j<M;j++) {
+ ReadFile ( rUB,sizeof(realUniBin) );
+ UniBin2real ( rUB,A[ShiftN+i][ShiftM+j] );
+ }
+ }
+ }
+ } else {
+ ReadFile ( &N,sizeof(N) );
+ if (N>0) {
+ ReadFile ( &M,sizeof(M) );
+ if (M>0) {
+ GetMatrixMemory ( A,N,M,ShiftN,ShiftM );
+ for (i=0;i<N;i++)
+ ReadFile ( &(A[ShiftN][ShiftM]),sizeof(realtype)*M );
+ }
+ }
+ }
+ return IOSuccess;
+ }
+
+
+ bool File::WriteColumns ( rvector X, rvector Y, rvector Z,
+ int len, int Shift, int MLength ) {
+ // WriteColumns writes data stored in X, Y and Z in the form
+ // of columns, adding a blank line in the end. If Z (or Z and Y)
+ // are set to NULL, then only X and Y (or only X) are written.
+ // Shift corresponds to the begining of arrays' enumeration
+ // X[Shift..Shift+len-1].
+ int i,l;
+ l = Shift+len;
+ for (i=Shift;i<l;i++) {
+ Write ( pstr(" ") );
+ Write ( X[i],MLength );
+ if (Y) {
+ Write ( pstr(", ") );
+ Write ( Y[i],MLength );
+ }
+ if (Z) {
+ Write ( pstr(", ") );
+ Write ( Z[i],MLength );
+ }
+ LF();
+ }
+ return LF();
+ }
+
+ bool File::WriteColumns ( rvector X, rvector Y,
+ int len, int Shift, int MLength ) {
+ return WriteColumns ( X,Y,NULL,len,Shift,MLength );
+ }
+
+ int File::ReadColumns ( int maxlen, rvector X, rvector Y, rvector Z,
+ int xCol, int yCol, int zCol, int Shift ) {
+ // ReadColumns reads data stored by WriteColumns. X, Y, and Z must
+ // be allocated prior to call.
+ // xCol, yCol and zCol specify the order number of columns
+ // (starting from 0) to be read into X, Y and Z, correspondingly.
+ // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
+ // Shift corresponds to the begining of arrays' enumeration
+ // X[Shift..Shift+len-1].
+ // Returns number of lines read.
+ int DataLen;
+ char S[1025];
+ DataLen = maxlen;
+ _ReadColumns ( DataLen,S,sizeof(S),X,Y,Z,xCol,yCol,zCol,Shift );
+ return DataLen;
+ }
+
+ int File::ReadColumns ( int maxlen, rvector X, rvector Y,
+ int xCol, int yCol, int Shift ) {
+ return ReadColumns ( maxlen,X,Y,NULL,xCol,yCol,-1,Shift );
+ }
+
+
+ int File::CreateReadColumns ( rvector & X, rvector & Y, rvector & Z,
+ int xCol, int yCol, int zCol,
+ int Shift ) {
+ // ReadColumns reads data stored by WriteColumns. X, Y, and Z
+ // must be set to NULL prior to call. They will be allocated
+ // within the procedure.
+ // xCol, yCol and zCol specify the order number of columns
+ // (starting from 0) to be read into X, Y and Z, correspondingly.
+ // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
+ // Shift corresponds to the begining of arrays' enumeration
+ // X[Shift..Shift+len-1].
+ // Returns number of lines read, errors are reported by ErrorCode().
+ int i,j,DataLen;
+ char S[1025];
+ bool Ok;
+ DataLen = 0;
+ ErrCode = 0;
+ if (!FileEnd()) {
+ i = 0;
+ j = 1;
+ // the loop terminates at first blank line
+ while ((i<j) && (!FileEnd())) {
+ j = ReadLine ( S,sizeof(S) );
+ i = 0;
+ // check for blank line
+ while ((i<j) && (S[i]==' ')) i++;
+ DataLen++;
+ }
+ if (i>=j) DataLen--;
+ if (DataLen>0) {
+ Ok = GetVectorMemory(X,DataLen,Shift);
+ if (Ok && (yCol>=0))
+ Ok = Ok && GetVectorMemory(Y,DataLen,Shift);
+ if (Ok && (zCol>=0))
+ Ok = Ok && GetVectorMemory(Z,DataLen,Shift);
+ if (Ok) {
+ reset();
+ _ReadColumns ( DataLen,S,sizeof(S),X,Y,Z,xCol,yCol,
+ zCol,Shift );
+ } else ErrCode = FileError_NoMemory;
+ } else ErrCode = FileError_NoDataFound;
+ } else ErrCode = FileError_NoDataFound;
+ return DataLen;
+ }
+
+ int File::CreateReadColumns ( rvector & X, rvector & Y,
+ int xCol, int yCol, int Shift ) {
+ return CreateReadColumns ( X,Y,X,xCol,yCol,-1,Shift );
+ }
+
+ void File::_ReadColumns ( int & DLen, pstr S, int SLen,
+ rvector X, rvector Y, rvector Z,
+ int xCol, int yCol, int zCol,
+ int Shift ) {
+ int i,is,j,k,m,n,cmax;
+ char SV[256];
+ realtype Res;
+ ErrCode = 0;
+ i = 0;
+ cmax = IMax(zCol,IMax(xCol,yCol));
+ while ((i<DLen) && (ErrCode==0)) {
+ k = ReadLine ( S,SLen );
+ RemoveDelimiters(S,k);
+ j = 0;
+ m = -1;
+ n = 0;
+ while ((m<cmax) && (ErrCode==0)) {
+ do {
+ PickOutNumber ( S,SV,k,j );
+ if ((m<0) && (SV[0]==char(0)) && (j>=k)) {
+ DLen = i;
+ return;
+ }
+ m++;
+ } while ((m!=xCol) && (m!=yCol) && (m!=zCol));
+ if (SV[0]==char(0)) {
+ if (n>0) ErrCode = FileError_NoColumn;
+ else ErrCode = FileError_ShortData;
+ } else {
+ Res = GetNumber ( SV );
+ if (ErrCode==0) {
+ is = i+Shift;
+ if (m==xCol) X[is] = Res;
+ else if (m==yCol) Y[is] = Res;
+ else Z[is] = Res;
+ n++;
+ }
+ }
+ }
+ if ((ErrCode==0) && (n<2)) ErrCode = FileError_NoColumn;
+ i++;
+ }
+ if ((ErrCode==FileError_ShortData) && (i>1)) {
+ ErrCode = 0;
+ DLen = i-1;
+ }
+ if (ErrCode!=0) ErrCode = FileError_BadData;
+ }
+
+ void RemoveDelimiters ( pstr S, int SLen ) {
+ int j;
+ for (j=0;j<SLen;j++)
+ if ((S[j]==',') || (S[j]==';') ||
+ (S[j]==':') || (S[j]==char(9)))
+ S[j] = ' ';
+ }
+
+ void PickOutNumber ( cpstr S, pstr SV, int SLen, int & j ) {
+ int l;
+ l = 0;
+ while ((j<SLen) && (S[j]==' ')) j++;
+ if ((S[j]=='+') || (S[j]=='-')) SV[l++] = S[j++];
+ if (S[j]=='.') SV[l++] = '0';
+ while ((j<SLen) && (S[j]!=' ')) SV[l++] = S[j++];
+ SV[l] = char(0);
+ }
+
+ realtype File::GetNumber ( cpstr S ) {
+ char * endptr;
+ realtype V;
+ V = strtod ( S,&endptr );
+ if ((*endptr!=' ') && (*endptr))
+ ErrCode = FileError_BadData;
+ return V;
+ }
+
+ cpstr FileError ( int ErrCode ) {
+ switch (ErrCode) {
+ case 0 : return "Ok";
+ case FileError_NoMemory : return "Insufficient memory";
+ case FileError_NoDataFound : return "No data found";
+ case FileError_NoColumn : return "No column structure";
+ case FileError_BadData : return "Incorrect data format";
+ case FileError_WrongMemoryAllocation
+ : return "Wrong Memory Allocation";
+ default : return "Unknown I/O error";
+ }
+ }
+
+ }
+
+}
diff --git a/mmdb2/mmdb_io_file.h b/mmdb2/mmdb_io_file.h
new file mode 100644
index 0000000..726666e
--- /dev/null
+++ b/mmdb2/mmdb_io_file.h
@@ -0,0 +1,301 @@
+// $Id: mmdb_io_file.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 11.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : file_ <interface>
+// ~~~~~~~~~
+// **** Classes : mmdb::io::File - file I/O Support.
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_IO_File__
+#define __MMDB_IO_File__
+
+#include <stdio.h>
+
+#include "mmdb_mattype.h"
+
+namespace mmdb {
+
+ namespace io {
+
+ // ======================== File Class ========================
+
+ enum GZ_MODE {
+ GZM_NONE = 0,
+ GZM_CHECK = 1,
+ GZM_ENFORCE = 2,
+ GZM_ENFORCE_GZIP = 2,
+ GZM_ENFORCE_COMPRESS = 3
+ };
+
+ enum FILE_ERROR {
+ FileError_NoMemory = 110,
+ FileError_ShortData = 111,
+ FileError_NoDataFound = 112,
+ FileError_NoColumn = 113,
+ FileError_BadData = 114,
+ FileError_WrongMemoryAllocation = 115
+ };
+
+ enum SYSKEY {
+ syskey_unix = 1,
+ syskey_win = 2,
+ syskey_all = 3
+ };
+
+ extern const char _dir_sep_c;
+ extern cpstr _dir_sep;
+
+ // =================== Auxilary Functions ========================
+
+
+ extern cpstr GetFPath ( pstr FilePath, SYSKEY syskey=syskey_unix );
+ extern cpstr GetFName ( cpstr FilePath, SYSKEY syskey=syskey_unix );
+ extern cpstr GetFExt ( cpstr FilePath );
+ extern cpstr ChangeExt ( pstr FilePath, cpstr newExt,
+ SYSKEY syskey=syskey_unix );
+ extern cpstr FileError ( int ErrCode );
+ extern void RemoveDelimiters ( pstr S, int SLen );
+ extern void PickOutNumber ( cpstr S, pstr SV, int SLen, int & j );
+
+
+ // ========================== File ===============================
+
+ DefineClass(File);
+
+ class File {
+
+ public :
+
+ File ( word BufSize=4096 );
+ virtual ~File();
+
+ // ---- control functions
+ // FileName allows for "stdin", "stdout" and "stderr" as
+ // for standard UNIX streams.
+ void assign ( cpstr FileName,
+ bool Text=false,
+ bool UniB=false,
+ GZ_MODE gzMode=GZM_NONE );
+ // assign for memory IO
+ void assign ( word poolSize, word sizeInc, pstr filePool );
+ void GetFilePool ( pstr & filePool, word & fileSize );
+
+ inline cpstr FileName() { return FName; }
+ bool reset ( bool ReadOnly=false, int retry=0 );
+ // = true if opened, each retry 1 sec sleep
+ bool erase (); // = true if erased
+ bool exists (); // = true if exists
+ bool parse ( cpstr FileName ); // true if filled
+ bool rename ( cpstr NewFileName ); // true if renamed
+ bool rewrite (); // = true if opened
+ bool append (); // = true if opened
+ bool isOpen ();
+ long Position ();
+ inline long FileLength () { return FLength; }
+ bool seek ( long Position );
+ bool FileEnd ();
+ inline bool Success () { return IOSuccess; }
+ inline void SetSuccess() { IOSuccess = true; }
+ void flush ();
+ void shut ();
+
+ // ---- binary I/O
+ word ReadFile ( void * Buffer, word Count );
+ word CreateRead ( pstr & Line );
+ word ReadTerLine ( pstr Line, bool longLine=false );
+ bool WriteFile ( const void * Buffer, word Count );
+ bool CreateWrite ( cpstr Line );
+ bool WriteTerLine ( cpstr Line, bool longLine=false );
+
+ // machine-independent binary I/O
+ bool WriteReal ( realtype * V );
+ bool WriteFloat ( realtype * V );
+ bool WriteInt ( int * I );
+ bool WriteShort ( short * S );
+ bool WriteLong ( long * L );
+ bool WriteBool ( bool * B );
+ bool WriteByte ( byte * B );
+ bool WriteWord ( word * W );
+ bool ReadReal ( realtype * V );
+ bool ReadFloat ( realtype * V );
+ bool ReadInt ( int * I );
+ bool ReadShort ( short * S );
+ bool ReadLong ( long * L );
+ bool ReadBool ( bool * B );
+ bool ReadByte ( byte * B );
+ bool ReadWord ( word * B );
+ bool AddReal ( realtype * V );
+ bool AddFloat ( realtype * V );
+ bool AddInt ( int * I );
+ bool AddShort ( short * S );
+ bool AddLong ( long * L );
+ bool AddByte ( byte * B );
+ bool AddWord ( word * B );
+
+ // complex data binary I/O
+ bool WriteVector ( rvector V, int len, int Shift );
+ bool WriteVector ( ivector iV, int len, int Shift );
+ bool WriteVector ( lvector lV, int len, int Shift );
+ bool WriteVector ( bvector B, int len, int Shift );
+ bool ReadVector ( rvector V, int maxlen, int Shift );
+ bool ReadVector ( ivector iV, int maxlen, int Shift );
+ bool ReadVector ( lvector lV, int maxlen, int Shift );
+ bool ReadVector ( bvector B, int maxlen, int Shift );
+ bool CreateReadVector ( rvector & V, int & len, int Shift );
+ bool CreateReadVector ( ivector & iV, int & len, int Shift );
+ bool CreateReadVector ( lvector & lV, int & len, int Shift );
+ bool CreateReadVector ( bvector & B, int & len, int Shift );
+ bool CreateReadVector ( rvector & V, int Shift );
+ bool CreateReadVector ( ivector & iV, int Shift );
+ bool CreateReadVector ( lvector & lV, int Shift );
+ bool CreateReadVector ( bvector & B, int Shift );
+ bool WriteMatrix ( rmatrix & A, int N, int M,
+ int ShiftN, int ShiftM );
+ bool CreateReadMatrix ( rmatrix & A, int ShiftN, int ShiftM );
+ bool CreateReadMatrix ( rmatrix & A, int & N, int & M,
+ int ShiftN, int ShiftM );
+
+ /// ---- text I/O
+ bool Write ( cpstr Line ); //!< writes without LF
+ bool Write ( realtype V, int length=10 ); //!< w/o LF
+ bool Write ( int iV, int length=5 ); //!< w/o LF
+ bool WriteLine ( cpstr Line ); //!< writes and adds LF
+ bool LF (); //!< just adds LF
+ word ReadLine ( pstr Line, word MaxLen=255 );
+ word ReadNonBlankLine ( pstr S, word MaxLen=255 );
+
+ /// complex data text I/O
+
+ // writes with spaces and adds LF
+ bool WriteDataLine ( realtype X, realtype Y, int length=10 );
+
+ bool WriteParameter ( cpstr S, realtype X, // writes parameter
+ int ParColumn=40, // name S and value X
+ int length=10 ); // at column ParColumn
+ // and adds LF.
+
+ bool WriteParameters ( cpstr S, int n_X, // writes parameter
+ rvector X, // name S and n_X values
+ int ParColumn=40, // X[0..n_X-1] at col
+ int length=10 ); // ParColumn, ads LF.
+
+ bool ReadParameter ( pstr S, realtype & X, // reads parameter
+ int ParColumn=40 ); // name S and val X
+ bool ReadParameter ( pstr S, int & X,
+ int ParColumn=40 );
+
+ bool ReadParameters ( pstr S, int & n_X, // reads parameter
+ rvector X, // name S, counts the
+ int MaxLen=255, // of values n_X and
+ int ParColumn=40 ); // reads X[0..n_X-1].
+ // MaxLen gives sizeof(S)
+
+ // WriteColumns writes data stored in X, Y and Z in the form
+ // of columns, adding a blank line in the end. If Z (or Z and Y)
+ // are set to NULL, then only X and Y (or only X) are written.
+ // Shift corresponds to the begining of arrays' enumeration
+ // X[Shift..Shift+len-1].
+ bool WriteColumns ( rvector X, rvector Y, rvector Z,
+ int len, int Shift, int MLength );
+ bool WriteColumns ( rvector X, rvector Y,
+ int len, int Shift, int MLength );
+
+ // ReadColumns reads data stored by WriteColumns. X, Y, and Z
+ // must be allocated prior to call.
+ // xCol, yCol and zCol specify the order number of columns
+ // (starting from 0) to be read into X, Y and Z, correspondingly.
+ // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
+ // Shift corresponds to the begining of arrays' enumeration
+ // X[Shift..Shift+len-1].
+ // Returns number of lines read.
+ int ReadColumns ( int maxlen, rvector X, rvector Y, rvector Z,
+ int xCol, int yCol, int zCol, int Shift );
+ int ReadColumns ( int maxlen, rvector X, rvector Y,
+ int xCol, int yCol, int Shift );
+
+ // CreateReadColumns reads data stored by WriteColumns. X, Y,
+ // and Z must be set to NULL prior to call. They will be allocated
+ // within the procedure.
+ // xCol, yCol and zCol specify the order number of columns
+ // (starting from 0) to be read into X, Y and Z, correspondingly.
+ // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
+ // Shift corresponds to the begining of arrays' enumeration
+ // X[Shift..Shift+len-1].
+ // Returns number of lines read, errors are reported by
+ // ErrorCode().
+ int CreateReadColumns ( rvector & X, rvector & Y, rvector & Z,
+ int xCol, int yCol, int zCol, int Shift );
+ int CreateReadColumns ( rvector & X, rvector & Y,
+ int xCol, int yCol, int Shift );
+
+ // ---- miscellaneous
+ realtype GetNumber ( cpstr S );
+ FILE * GetHandle () { return hFile; }
+
+ protected :
+ word Buf_Size;
+ bool TextMode,UniBin;
+ GZ_MODE gzipMode;
+ pstr IOBuf;
+ word BufCnt,BufLen,BufInc;
+ FILE * hFile;
+ bool EofFile;
+ pstr FName;
+ long FLength;
+ bool IOSuccess;
+ int ErrCode;
+
+ void FreeBuffer ();
+ void _ReadColumns ( int & DLen, pstr S, int SLen,
+ rvector X, rvector Y, rvector Z,
+ int xCol, int yCol, int zCol, int Shift );
+
+ private :
+ int gzipIO;
+ bool StdIO,memIO;
+
+ };
+
+
+ extern void SetGZIPPath ( pstr gzipPath, pstr ungzipPath );
+ extern void SetCompressPath ( pstr compressPath, pstr uncompressPath );
+
+ extern bool FileExists ( cpstr FileName, PFile f=NULL );
+
+ }
+
+}
+
+
+#endif
+
diff --git a/mmdb2/mmdb_io_stream.cpp b/mmdb2/mmdb_io_stream.cpp
new file mode 100644
index 0000000..4dbdd46
--- /dev/null
+++ b/mmdb2/mmdb_io_stream.cpp
@@ -0,0 +1,112 @@
+// $Id: mmdb_io_stream.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 11.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Stream_ <interface>
+// ~~~~~~~~~
+// **** Classes : mmdb::io::Stream ( Basic Stream Class )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 1995-2013
+//
+// =================================================================
+//
+
+#include "mmdb_io_stream.h"
+
+namespace mmdb {
+
+ namespace io {
+
+ // ========================== CStream ===========================
+
+ // Each streamable class should be derived from Stream
+ // and have constructor Class(PStream & Object), which should
+ // initialize all memory of the class, and virtual functions
+ // read(..) and write(..) (see below). Constructor Class(PStream&)
+ // must not touch the Object variable. This constructor is used
+ // only once just before read(..) function. It is assumed that
+ // read/write functions of Class provide storage/reading of
+ // all vital data. Function read(..) must read data in exactly
+ // the same way as function write(..) stores it.
+ // For using Class in streams, three following functions should
+ // be supplied:
+ //
+ // 1.
+ // void StreamWrite ( RFile f, RPClass Object ) {
+ // StreamWrite ( f,(PStream)PClass );
+ // }
+ //
+ // 2.
+ // PCStream ClassInit ( RPStream Object ) {
+ // return (PStream)(new Class(Object));
+ // }
+ //
+ // 3.
+ // void StreamRead ( RFile f, RPClass Object ) {
+ // StreamRead_ ( f,(PStream)Object,ClassInit );
+ // }
+ //
+ // All these functions are automatically generated by macros
+ // DefineStreamFunctions(CClass) -- in the header -- and
+ // MakeStreamFunctions(CClass) -- in the implementation body.
+ // Then CClass may be streamed in/out using functions #1 and #3.
+ // StreamRead will return NULL for Object if it was not
+ // in the stream. If Object existed before StreamRead(..) but
+ // was not found in the stream, it will be disposed.
+
+ void StreamRead_ ( RFile f, RPStream Object,
+ InitStreamObject Init ) {
+ int i;
+ f.ReadInt ( &i );
+ if (i) {
+ if (!Object)
+ Object = Init(Object); //Object = new CStream ( Object );
+ Object->read ( f );
+ } else {
+ if (Object) delete Object;
+ Object = NULL;
+ }
+ }
+
+ void StreamWrite_ ( RFile f, RPStream Object ) {
+ int i;
+ if (Object) {
+ i = 1;
+ f.WriteInt ( &i );
+ Object->write ( f );
+ } else {
+ i = 0;
+ f.WriteInt ( &i );
+ }
+ }
+
+ MakeStreamFunctions(Stream)
+
+ }
+
+}
diff --git a/mmdb2/mmdb_io_stream.h b/mmdb2/mmdb_io_stream.h
new file mode 100644
index 0000000..689b37f
--- /dev/null
+++ b/mmdb2/mmdb_io_stream.h
@@ -0,0 +1,193 @@
+// $Id: mmdb_io_stream.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 11.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Stream <interface>
+// ~~~~~~~~~
+// **** Classes : mmdb::io::Stream ( Basic Stream Class )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 1995-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_IO_Stream__
+#define __MMDB_IO_Stream__
+
+#include "mmdb_io_file.h"
+
+// *******************************************************************
+
+#ifndef __ClassMacros
+
+# define __ClassMacros
+
+ // A Class definition macros
+# define DefineClass(ClassName) \
+ class ClassName; \
+ typedef ClassName * P##ClassName; \
+ typedef ClassName & R##ClassName; \
+ typedef P##ClassName * PP##ClassName; \
+ typedef P##ClassName & RP##ClassName;
+
+ // A Structure definition macros
+# define DefineStructure(StructureName) \
+ struct StructureName; \
+ typedef StructureName * P##StructureName; \
+ typedef StructureName & R##StructureName; \
+ typedef P##StructureName * PP##StructureName; \
+ typedef P##StructureName & RP##StructureName;
+
+#endif
+
+
+#define DefineStreamFunctions(ClassName) \
+ extern void StreamWrite ( mmdb::io::RFile f, RP##ClassName Object ); \
+ extern void StreamRead ( mmdb::io::RFile f, RP##ClassName Object );
+
+
+#define MakeStreamFunctions(ClassName) \
+ void StreamWrite ( mmdb::io::RFile f, RP##ClassName Object ) { \
+ StreamWrite_ ( f,(mmdb::io::RPStream)Object ); \
+ } \
+ mmdb::io::PStream StreamInit##ClassName ( mmdb::io::RPStream Object ) { \
+ return (mmdb::io::PStream)(new ClassName(Object)); \
+ } \
+ void StreamRead ( mmdb::io::RFile f, RP##ClassName Object ) { \
+ StreamRead_ ( f,(mmdb::io::RPStream)Object,StreamInit##ClassName );\
+ }
+
+#define DefineFactoryFunctions(ClassName) \
+ typedef P##ClassName Make##ClassName(); \
+ typedef Make##ClassName * PMake##ClassName; \
+ typedef P##ClassName StreamMake##ClassName ( mmdb::io::RPStream Object ); \
+ P##ClassName new##ClassName (); \
+ P##ClassName streamNew##ClassName ( mmdb::io::RPStream Object ); \
+ typedef StreamMake##ClassName * PStreamMake##ClassName; \
+ extern void SetMakers##ClassName ( void * defMk, void * streamMk ); \
+ extern void StreamWrite ( mmdb::io::RFile f, RP##ClassName Object ); \
+ extern void StreamRead ( mmdb::io::RFile f, RP##ClassName Object );
+
+
+#define MakeFactoryFunctions(ClassName) \
+ static PMake##ClassName make##ClassName = NULL; \
+ static PStreamMake##ClassName streamMake##ClassName = NULL; \
+ P##ClassName new##ClassName() { \
+ if (make##ClassName) return (*make##ClassName)(); \
+ else return new ClassName(); \
+ } \
+ P##ClassName streamNew##ClassName ( mmdb::io::RPStream Object ) { \
+ if (streamMake##ClassName) \
+ return (*streamMake##ClassName)(Object); \
+ else return new ClassName(Object); \
+ } \
+ void SetMakers##ClassName ( void * defMk, void * streamMk ) { \
+ make##ClassName = PMake##ClassName(defMk); \
+ streamMake##ClassName = PStreamMake##ClassName(streamMk); \
+ } \
+ void StreamWrite ( mmdb::io::RFile f, RP##ClassName Object ) { \
+ StreamWrite_ ( f,(mmdb::io::RPStream)Object ); \
+ } \
+ mmdb::io::PStream StreamInit##ClassName ( mmdb::io::RPStream Object ) { \
+ return (mmdb::io::PStream)(streamNew##ClassName(Object)); \
+ } \
+ void StreamRead ( mmdb::io::RFile f, RP##ClassName Object ) { \
+ StreamRead_ ( f,(mmdb::io::RPStream)Object,StreamInit##ClassName ); \
+ }
+
+namespace mmdb {
+
+ namespace io {
+
+ // ========================== Stream ===========================
+
+ // Each streamable class should be derived from Stream
+ // and have constructor Class(PStream & Object), which should
+ // initialize all memory of the class, and virtual functions
+ // read(..) and write(..) (see below). Constructor Class(PStream&)
+ // must not touch the Object variable. This constructor is used
+ // only once just before the read(..) function. It is assumed that
+ // read(..)/write(..) functions of the Class provide storage/reading
+ // of all vital data. Function read(..) must read data in exactly
+ // the same way as function write(..) stores it.
+ // For using Class in streams, three following functions should
+ // be supplied:
+ //
+ // 1.
+ // void StreamWrite ( File & f, PClass & Object ) {
+ // StreamWrite ( f,(PStream)Object );
+ // }
+ //
+ // 2.
+ // PStream ClassInit ( PStream & Object ) {
+ // return (PStream)(new Class(Object));
+ // }
+ //
+ // 3.
+ // void StreamRead ( File & f, PClass & Object ) {
+ // StreamRead_ ( f,(PStream)Object,ClassInit );
+ // }
+ //
+ // All these functions are automatically generated by macros
+ // DefineStreamFunctions(Class) -- in the header -- and
+ // MakeStreamFunctions(Class) -- in the implementation body. Note
+ // that macro DefineClass(Class) should always be issued for
+ // streamable classes prior to the stream-making macros. Then
+ // Class may be streamed using functions #1 and #3.
+ // StreamRead will return NULL for Object if it was not in
+ // the stream. If Object existed before calling StreamRead(..)
+ // but was not found in the stream, it will be disposed (NULL
+ // assigned).
+
+
+ DefineClass(Stream);
+ DefineStreamFunctions(Stream);
+
+ class Stream {
+ public :
+ Stream () {}
+ Stream ( RPStream ) {}
+ virtual ~Stream () {}
+ virtual void read ( RFile ) {}
+ virtual void write ( RFile ) {}
+ };
+
+
+ typedef PStream InitStreamObject(RPStream Object);
+
+ extern void StreamRead_ ( RFile f, RPStream Object,
+ InitStreamObject Init );
+
+ extern void StreamWrite_ ( RFile f, RPStream Object );
+
+
+ }
+
+}
+
+#endif
diff --git a/mmdb2/mmdb_machine_.cpp b/mmdb2/mmdb_machine_.cpp
new file mode 100644
index 0000000..fb50378
--- /dev/null
+++ b/mmdb2/mmdb_machine_.cpp
@@ -0,0 +1,155 @@
+// $Id: mmdb_machine.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Machine <interface>
+// ~~~~~~~~~
+// **** Functions : mmdb::machine::GetMachineID - returns ID code
+// ~~~~~~~~~~~ for the machine
+// mmdb::machine::GetMachineName - returns name of
+// the machine
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include "mmdb_machine_.h"
+
+namespace mmdb {
+
+ namespace machine {
+
+#ifdef CALL_LIKE_SUN
+
+ int GetMachineID() {
+ int k = CALL_LIKE_SUN;
+ switch (k) {
+ case 1 : return MACHINE_ALLIANT;
+ case 2 : return MACHINE_CONVEX;
+ case 3 : return MACHINE_ESV;
+ case 4 : return MACHINE_SGI;
+ case 5 : return MACHINE_SOLBOURNE;
+ case 6 : return MACHINE_SOLARIS;
+ case 7 : return MACHINE_ALPHA;
+ case 8 : return MACHINE_F2C_G77;
+ case 9 : return MACHINE_LINUX;
+ default : return MACHINE_UNKNOWN;
+ }
+ }
+
+#elif defined(CALL_LIKE_HPUX)
+
+ int GetMachineID() {
+ int k = CALL_LIKE_HPUX;
+ switch (k) {
+ case 1 : return MACHINE_RS6000;
+ case 2 : return MACHINE_HP9000;
+ default : return MACHINE_UNKNOWN;
+ }
+ }
+
+#elif defined(CALL_LIKE_STARDENT)
+
+ int GetMachineID() {
+ int k = CALL_LIKE_STARDENT;
+ switch (k) {
+ case 1 : return MACHINE_ARDENT;
+ case 2 : return MACHINE_TITAN;
+ case 3 : return MACHINE_STARDENT;
+ default : return MACHINE_UNKNOWN;
+ }
+ }
+
+#elif defined(CALL_LIKE_VMS)
+
+ int GetMachineID() {
+ return MACHINE_VMS;
+ }
+
+#elif defined(CALL_LIKE_MVS)
+
+ int GetMachineID() {
+ return MACHINE_MVS;
+ }
+
+#else
+
+ int GetMachineID() {
+ return MACHINE_UNKNOWN;
+ }
+
+#endif
+
+ static cpstr MCH_SGI = cpstr("Silicon Graphics");
+ static cpstr MCH_RS6000 = cpstr("IBM RS/6000");
+ static cpstr MCH_ALLIANT = cpstr("Alliant");
+ static cpstr MCH_ARDENT = cpstr("Ardent");
+ static cpstr MCH_TITAN = cpstr("Titan");
+ static cpstr MCH_STARDENT = cpstr("Stardent");
+ static cpstr MCH_CONVEX = cpstr("Convex");
+ static cpstr MCH_ESV = cpstr("Evans or Sutherland");
+ static cpstr MCH_HP9000 = cpstr("Hewlett Packard 9000");
+ static cpstr MCH_SOLBOURNE = cpstr("Solbourne");
+ static cpstr MCH_SOLARIS = cpstr("Solaris");
+ static cpstr MCH_ALPHA = cpstr("DEC Alpha");
+ static cpstr MCH_VMS = cpstr("A VMS machine");
+ static cpstr MCH_MVS = cpstr("MS Windows");
+ static cpstr MCH_F2C_G77 = cpstr("SUN compatible");
+ static cpstr MCH_LINUX = cpstr("Linux");
+
+ cpstr GetMachineName ( int MachineID ) {
+ switch (MachineID) {
+ case MACHINE_SGI : return MCH_SGI;
+ case MACHINE_RS6000 : return MCH_RS6000;
+ case MACHINE_ALLIANT : return MCH_ALLIANT;
+ case MACHINE_ARDENT : return MCH_ARDENT;
+ case MACHINE_TITAN : return MCH_TITAN;
+ case MACHINE_STARDENT : return MCH_STARDENT;
+ case MACHINE_CONVEX : return MCH_CONVEX;
+ case MACHINE_ESV : return MCH_ESV;
+ case MACHINE_HP9000 : return MCH_HP9000;
+ case MACHINE_SOLBOURNE : return MCH_SOLBOURNE;
+ case MACHINE_SOLARIS : return MCH_SOLARIS;
+ case MACHINE_ALPHA : return MCH_ALPHA;
+ case MACHINE_VMS : return MCH_VMS;
+ case MACHINE_MVS : return MCH_MVS;
+ case MACHINE_F2C_G77 : return MCH_F2C_G77;
+ case MACHINE_LINUX : return MCH_LINUX;
+ default :
+ case MACHINE_UNKNOWN : return pstr("Unidentified machine");
+ }
+ }
+
+ cpstr GetMachineName() {
+ return GetMachineName ( GetMachineID() );
+ }
+
+
+ }
+
+}
diff --git a/mmdb2/mmdb_machine_.h b/mmdb2/mmdb_machine_.h
new file mode 100644
index 0000000..6897d06
--- /dev/null
+++ b/mmdb2/mmdb_machine_.h
@@ -0,0 +1,477 @@
+// $Id: mmdb_machine.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Machine <interface>
+// ~~~~~~~~~
+// **** Functions : mmdb::machine::GetMachineID - returns ID code
+// ~~~~~~~~~~~ for the machine
+// mmdb::machine::GetMachineName - returns name of
+// the machine
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Machine__
+#define __MMDB_Machine__
+
+#include "mmdb_mattype.h"
+
+/*
+// Programs written in plain C, should define __PlainC each time
+// this header is invoked.
+
+#ifdef __PlainC
+# undef __CPlusPlus
+#else
+# define __CPlusPlus
+#endif
+*/
+
+namespace mmdb {
+
+ namespace machine {
+
+
+ // ================== List of known machines =================
+
+ enum MACHINE {
+ MACHINE_SGI = 1,
+ MACHINE_RS6000 = 2,
+ MACHINE_ALLIANT = 3,
+ MACHINE_ARDENT = 4,
+ MACHINE_TITAN = 5,
+ MACHINE_STARDENT = 6,
+ MACHINE_CONVEX = 7,
+ MACHINE_ESV = 8,
+ MACHINE_HP9000 = 9,
+ MACHINE_SOLBOURNE = 10,
+ MACHINE_SOLARIS = 11,
+ MACHINE_ALPHA = 12,
+ MACHINE_VMS = 13,
+ MACHINE_MVS = 14,
+ MACHINE_F2C_G77 = 15,
+ MACHINE_LINUX = 16,
+ MACHINE_UNKNOWN = 100
+ };
+
+ // ============= Identification of the machine ===============
+
+// IBM Unix RS/6000
+#if defined(_AIX) || defined(___AIX)
+# define CALL_LIKE_HPUX 1
+
+// Alliant
+#elif defined(alliant)
+# define CALL_LIKE_SUN 1
+
+// Ardent, Stardent/Titan
+#elif defined(ardent)
+# define CALL_LIKE_STARDENT 1
+#elif defined(titan)
+# define CALL_LIKE_STARDENT 2
+#elif defined(stardent)
+# define CALL_LIKE_STARDENT 3
+
+// Convex
+#elif defined(__convex__) || defined(__convexc__)
+# define CALL_LIKE_SUN 2
+
+// Evans and Sutherland
+#elif defined(ESV)
+# define CALL_LIKE_SUN 3
+
+// Hewlett Packard 9000/750 (RISC) models
+#elif defined(__hpux)
+# define CALL_LIKE_HPUX 2
+
+// Silicon Graphics IRIX systems, Iris'es, Indigo's, Crimson's etc.
+#elif defined(__sgi) || defined(sgi)
+# define CALL_LIKE_SUN 4
+
+// Solbourne's are Sun clones.
+#elif defined(solbourne)
+# define CALL_LIKE_SUN 5
+
+// Solaris 1 and 2
+#elif defined(sun) || defined(__sun)
+# define CALL_LIKE_SUN 6
+
+// DEC, OSF/1, Alpha and Ultrix
+#elif defined(ultrix) || defined(__OSF1__) || defined(__osf__)
+# define CALL_LIKE_SUN 7
+
+// VMS
+#elif defined(vms) || defined(__vms) || defined(__VMS)
+# define CALL_LIKE_VMS 1
+
+// MVS stands for Microsoft Visual Studio
+#elif defined(_MVS)
+# define CALL_LIKE_MVS 1
+
+#elif defined(F2C) || defined(G77)
+# define CALL_LIKE_SUN 8
+
+#elif defined(linux)
+# define CALL_LIKE_SUN 9
+
+#else
+//# error System type is not known -- see the Installation Guide
+# define CALL_LIKE_SUN 100
+
+#endif
+
+
+
+// ================= Machine-dependent definitions ==================
+
+#ifdef CALL_LIKE_STARDENT
+ // StrPar is used in Ardent-like machines' fortran calls
+ // for passing a string parameter
+ DefineStructure(StrPar)
+ struct StrPar {
+ pstr S;
+ int len;
+ int id;
+ };
+#endif
+
+
+//
+// Macro FORTRAN_SUBR(NAME,name,p_send,p_struct,p_sflw)
+// makes function header statements that allow for linking with
+// programs written in FORTRAN.
+//
+// Parameters:
+//
+// NAME name of the FORTRAN subroutine in capital letters
+// name name of the FORTRAN subroutine in small letters
+// p_send parameter list (in brackets) with string lengths
+// attached to the end of it (see below)
+// p_struct parameter list (in brackets) with strings passed
+// as complex parameters, or structures
+// p_sflw parameter list (in brackets) with string lengths
+// following immediately the string parameters
+// (see below)
+//
+// All non-string parameters must be passed as pointers, in
+// the same order as they enter the FORTRAN call. Rules for
+// the string parameters are as follows.
+//
+// 1. All strings should be specified as of 'fpstr' type.
+// The 'fpstr' type is defined below and depends on the
+// platform:
+//
+// a) whenever length of string is passed as a separate
+// parameter ( CALL_LIKE_SUN, CALL_LIKE_HPUX,
+// CALL_LIKE_MVS ) 'fpstr' is identical to 'pstr'.
+// You may choose arbitrary name for the string,
+// but you MUST use the same name, appended with
+// suffix '_len', for its length (see example below).
+//
+// b) whenever string and its length are passed as
+// complex parameter, 'fpstr' is identical to the
+// pointer on the corresponding structure:
+// CALL_LIKE_STARDENT :
+// 'fpstr' is identical to 'PStrPar'
+// CALL_LIKE_VMS :
+// 'fpstr' is identical to 'dsc$descriptor_s *'
+//
+// With 'fpstr' type, two important macro definition come:
+//
+// i) FTN_STR(s) - returns pointer to fortran-passed
+// string s. This pointer is always
+// of 'pstr' type
+// ii) FTN_LEN(s) - returns integer length of fortran-
+// passed string s. For this macro to
+// work properly with SUN- and MVS-like
+// machines, always use suffix '_len'
+// for the string length parameters as
+// described in a) above.
+//
+// 2. Three parameter lists, each enclosed in brackets, should
+// be given. These lists retain the general order of
+// parameters in the corresponding fortran call. Non-string
+// parameters are passed as pointers. String parameters
+// and their lengths are passed differently in different
+// lists:
+//
+// p_send strings enter their place in the list as in
+// the corresponding FORTRAN call, having 'fpstr'
+// parameter type. Their lengths are appended as
+// 'int' to the end of the list. They should
+// retain the order in which the strings appear
+// in the list.
+//
+// p_struct strings enter their place in the list as in
+// the corresponding FORTRAN call, having 'fpstr'
+// parameter type.
+//
+// p_sflw strings enter their place in the list as in
+// the corresponding FORTRAN call, having 'fpstr'
+// type and being immediately followed by their
+// lengths as 'int' parameters.
+//
+//
+//
+// Example:
+//
+// FORTRAN statement
+//
+// subroutine SomeSub ( k,s1,a,s2,m )
+// integer k,m
+// real a
+// character*(*) s1,s2
+//
+// is translated to
+//
+// FORTRAN_SUBR ( SOMESUB, somesub,
+// ( int * k, fpstr s1, float * a, fpstr s2, int * m,
+// int s1_len, int s2_len ),
+// ( int * k, fpstr s1, float * a, fpstr s2, int * m ),
+// ( int * k, fpstr s1, int s1_len, float * a,
+// fpstr s2, int s2_len, int * m ) )
+//
+//
+// The macro should replace ordinary function header
+// statements to assure compatibility with FORTRAN links.
+// In header files, do not forget to add semicolumn:
+//
+// FORTRAN_SUBR ( .... );
+//
+// while in source files use simply
+//
+// FORTRAN_SUBR ( .... ) {
+// <source body, operators>
+// }
+//
+//
+//
+// Macro FORTRAN_CALL(NAME,name,p_send,p_struct,p_sflw)
+// calls function defined with macro FORTRAN_SUBR(...), from
+// a C/C++ application. Its parameters and their meaning are
+// exactly identical to those of FORTRAN_SUBR(...).
+// FORTRAN_CALL(...) should be followed by semicolon.
+//
+
+
+// **** type of real numbers in the API functions
+// comment or uncomment the proper string
+
+ typedef float apireal; // FORTRAN real*4
+/*
+ typedef double apireal; // FORTRAN real*8
+*/
+
+
+#if defined(CALL_LIKE_SUN)
+
+ typedef pstr fpstr;
+
+# define FTN_STR(s) s
+# define FTN_LEN(s) s##_len
+
+# define char_struct(s) \
+ mmdb::pstr s; \
+ int s##_len;
+# define fill_char_struct(s,str) \
+ s = str; \
+ s##_len = strlen(str);
+
+# ifdef __cplusplus
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void name##_ p_sun
+# else
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ void name##_ p_sun
+# endif
+
+# define FORTRAN_EXTERN(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void name##_ p_sun
+
+# define FORTRAN_CALL(NAME,name,p_sun,p_stardent,p_mvs) \
+ name##_ p_sun
+
+# elif defined(CALL_LIKE_HPUX)
+
+ typedef pstr fpstr;
+
+# define FTN_STR(s) s
+# define FTN_LEN(s) s##_len
+
+# define char_struct(s) \
+ pstr s; \
+ int s##_len;
+# define fill_char_struct(s,str) \
+ s = str; \
+ s##_len = strlen(str);
+
+# ifdef __cplusplus
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void name p_sun
+# else
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ void name p_sun
+# endif
+
+# define FORTRAN_EXTERN(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void name p_sun
+
+# define FORTRAN_CALL(NAME,name,p_sun,p_stardent,p_mvs) \
+ name p_sun
+
+#elif defined(CALL_LIKE_STARDENT)
+
+ typedef PStrPar fpstr;
+
+# define FTN_STR(s) s->S
+# define FTN_LEN(s) s->len
+
+# define char_struct(s) \
+ StrPar s;
+# define fill_char_struct(s,str) \
+ s.S = str; \
+ s.len = strlen(FName); \
+ s.id = 0;
+
+# ifdef __cplusplus
+# define FORTRAN_SUBR(NAME,name,p_send,p_struct,p_sflw) \
+ extern "C" void NAME p_stardent
+# else
+# define FORTRAN_SUBR(NAME,name,p_send,p_struct,p_sflw) \
+ void NAME p_stardent
+# endif
+
+# define FORTRAN_EXTERN(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void NAME p_stardent
+
+# define FORTRAN_CALL(NAME,name,p_send,p_struct,p_sflw) \
+ NAME p_stardent
+
+#elif defined(CALL_LIKE_VMS)
+
+ typedef dsc$descriptor_s * fpstr;
+
+# define FTN_STR(s) s->dsc$a_pointer;
+# define FTN_LEN(s) s->dsc$w_length;
+
+# define character(s) \
+ dsc$descriptor_s s;
+# define fill_char_struct(s,str) \
+ s.dsc$a_pointer = str; \
+ s.dsc$w_length = strlen(str); \
+ s.dsc$b_dtype = DSC$K_DTYPE_T; \
+ s.dsc$b_class = DSC$K_CLASS_S;
+
+# ifdef __cplusplus
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void NAME p_stardent
+# else
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ void NAME p_stardent
+# endif
+
+# define FORTRAN_EXTERN(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void NAME p_stardent
+
+# define FORTRAN_CALL(NAME,name,p_sun,p_stardent,p_mvs) \
+ NAME p_stardent
+
+#elif defined(CALL_LIKE_MVS)
+
+ typedef pstr fpstr;
+
+# define FTN_STR(s) s
+# define FTN_LEN(s) s##_len
+
+# define char_struct(s) \
+ pstr s; \
+ int s##_len;
+# define fill_char_struct(s,str) \
+ s = str; \
+ s##_len = strlen(str);
+
+# ifdef __cplusplus
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void __stdcall NAME p_mvs
+# else
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ void __stdcall NAME p_mvs
+# endif
+
+# define FORTRAN_EXTERN(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void NAME p_mvs
+
+# define FORTRAN_CALL(NAME,name,p_sun,p_stardent,p_mvs) \
+ NAME p_mvs
+
+#else
+
+# error Unknown machine!!!
+
+ typedef pstr fpstr;
+
+# define FTN_STR(s) s
+# define FTN_LEN(s) s##_len
+
+# define char_struct(s) \
+ pstr s; \
+ int s##_len;
+# define fill_char_struct(s,str) \
+ s = str; \
+ s##_len = strlen(str);
+
+# ifdef __cplusplus
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void name##_ p_sun
+# else
+# define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
+ void name##_ p_sun
+# endif
+
+# define FORTRAN_EXTERN(NAME,name,p_sun,p_stardent,p_mvs) \
+ extern "C" void name##_ p_sun
+
+# define FORTRAN_CALL(NAME,name,p_sun,p_stardent,p_mvs) \
+ name##_ p_sun
+
+#endif
+
+
+ // ============== Machine-dependent functions ===============
+
+ extern int GetMachineID ();
+ extern mmdb::cpstr GetMachineName ();
+ extern mmdb::cpstr GetMachineName ( int MachineID );
+
+ }
+
+}
+
+#endif
diff --git a/mmdb2/mmdb_manager.cpp b/mmdb2/mmdb_manager.cpp
new file mode 100644
index 0000000..4681adb
--- /dev/null
+++ b/mmdb2/mmdb_manager.cpp
@@ -0,0 +1,389 @@
+// $Id: mmdb_manager.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 15.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_manager <implementation>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Manager ( MMDB file manager )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+
+#include <string.h>
+
+#include "mmdb_manager.h"
+
+namespace mmdb {
+
+// ===================== Manager =======================
+
+ Manager::Manager() : BondManager() {
+ }
+
+ Manager::Manager ( io::RPStream Object ) : BondManager(Object) {
+ }
+
+ Manager::~Manager() {}
+
+ void Manager::Copy ( PManager MMDB, COPY_MASK CopyMask ) {
+ PModel mdl;
+ PPChain chain;
+ PChain ch;
+ ChainID chID;
+ int i,j, nchains;
+
+ if (CopyMask & MMDBFCM_Flags) Flags = MMDB->Flags;
+
+ if (CopyMask & MMDBFCM_Title) title.Copy ( &(MMDB->title) );
+ if (CopyMask & MMDBFCM_Cryst) cryst.Copy ( &(MMDB->cryst) );
+
+ if (CopyMask & MMDBFCM_Coord) {
+
+ FreeCoordMemory ();
+ DeleteAllSelections();
+
+ nAtoms = MMDB->nAtoms;
+ atmLen = nAtoms;
+ if (nAtoms>0) {
+ atom = new PAtom[atmLen];
+ for (i=0;i<nAtoms;i++) {
+ if (MMDB->atom[i]) {
+ atom[i] = newAtom();
+ atom[i]->Copy ( MMDB->atom[i] );
+ // the internal atom references are installed
+ // by residue classes when they are read in
+ // model->chain below
+ atom[i]->SetAtomIndex ( i+1 );
+ } else
+ atom[i] = NULL;
+ }
+ }
+
+ nModels = MMDB->nModels;
+ if (nModels>0) {
+ model = new PModel[nModels];
+ for (i=0;i<nModels;i++) {
+ if (MMDB->model[i]) {
+ model[i] = newModel();
+ model[i]->SetMMDBManager ( this,0 );
+ model[i]->_copy ( MMDB->model[i] );
+ } else
+ model[i] = NULL;
+ }
+ }
+
+ crModel = NULL;
+ crChain = NULL;
+ crRes = NULL;
+
+ if (MMDB->crModel) {
+
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ if (model[i]->serNum==MMDB->crModel->serNum) {
+ crModel = model[i];
+ break;
+ }
+ }
+
+ if (crModel && crModel->chain && MMDB->crChain)
+ for (i=0;i<crModel->nChains;i++)
+ if (crModel->chain[i]) {
+ if (!strcmp(crModel->chain[i]->chainID,
+ MMDB->crModel->chain[i]->chainID)) {
+ crChain = crModel->chain[i];
+ break;
+ }
+ }
+
+ if (crChain && crChain->residue && MMDB->crRes)
+ for (i=0;i<crChain->nResidues;i++)
+ if (crChain->residue[i]) {
+ if ((!strcmp(crChain->residue[i]->name,
+ MMDB->crRes->name)) &&
+ (crChain->residue[i]->seqNum==MMDB->crRes->seqNum) &&
+ (!strcmp(crChain->residue[i]->insCode,
+ MMDB->crRes->insCode))) {
+ crRes = crChain->residue[i];
+ break;
+ }
+ }
+ }
+
+ /*
+ if ((MMDB->nSelections>0) && MMDB->Mask) {
+ nSelections = MMDB->nSelections;
+ if (nSelections>0) {
+ Mask = new PCMask [nSelections];
+ SelAtom = new PPAtom[nSelections];
+ nSelAtoms = new int [nSelections];
+ for (i=0;i<nSelections;i++) {
+ Mask[i] = new CMask();
+ Mask[i]->CopyMask ( MMDB->Mask[i] );
+ nSelAtoms[i] = MMDB->nSelAtoms[i];
+ if (nSelAtoms[i]>0) {
+ SelAtom[i] = new PAtom[nSelAtoms[i]];
+ for (j=0;j<nSelAtoms[i];j++)
+ SelAtom[i][j] = Atom[MMDB->SelAtom[i][j]->index];
+ } else
+ SelAtom[i] = NULL;
+ }
+ }
+ }
+ */
+
+ } else if (CopyMask & (MMDBFCM_HetInfo | MMDBFCM_SecStruct |
+ MMDBFCM_Links | MMDBFCM_CisPeps |
+ MMDBFCM_ChainAnnot)) {
+
+ for (i=0;i<MMDB->nModels;i++)
+ if (MMDB->model[i]) {
+
+ mdl = GetModel ( i+1 );
+ if (!mdl) {
+ mdl = new Model( NULL,i+1 );
+ AddModel ( mdl );
+ }
+
+ if (CopyMask & MMDBFCM_HetInfo)
+ mdl->CopyHets ( MMDB->model[i] );
+ if (CopyMask & MMDBFCM_SecStruct)
+ mdl->CopySecStructure ( MMDB->model[i] );
+ if (CopyMask & MMDBFCM_Links) {
+ mdl->CopyLinks ( MMDB->model[i] );
+ mdl->CopyLinkRs ( MMDB->model[i] );
+ }
+ if (CopyMask & MMDBFCM_CisPeps)
+ mdl->CopyCisPeps ( MMDB->model[i] );
+ if (CopyMask & MMDBFCM_ChainAnnot) {
+ MMDB->GetChainTable ( i+1,chain,nchains );
+ for (j=0;j<nchains;j++)
+ if (chain[j]) {
+ chain[j]->GetChainID ( chID );
+ ch = mdl->GetChain ( chID );
+ if (!ch) {
+ ch = new Chain();
+ ch->SetChainID ( chID );
+ mdl->AddChain ( ch );
+ }
+ ch->CopyAnnotations ( chain[j] );
+ }
+
+ }
+
+ }
+
+ }
+
+ if (CopyMask & MMDBFCM_SA) SA.Copy ( &(MMDB->SA) );
+ if (CopyMask & MMDBFCM_SB) SB.Copy ( &(MMDB->SB) );
+ if (CopyMask & MMDBFCM_SC) SC.Copy ( &(MMDB->SC) );
+ if (CopyMask & MMDBFCM_Footnotes)
+ Footnote.Copy ( &(MMDB->Footnote) );
+
+ if (CopyMask & MMDBFCM_Buffer) {
+ lcount = MMDB->lcount;
+ strncpy ( S,MMDB->S,sizeof(S) );
+ }
+
+ }
+
+ void Manager::Delete ( word DelMask ) {
+ PPModel model;
+ PPChain chain;
+ int i,j,nm, nchains;
+
+ if (DelMask & MMDBFCM_Flags) Flags = 0;
+
+ if (DelMask & MMDBFCM_Title) title.Copy ( NULL );
+ if (DelMask & MMDBFCM_TitleKeepBM) title.FreeMemory ( true );
+ if (DelMask & MMDBFCM_Cryst) cryst.Copy ( NULL );
+
+ if (DelMask & MMDBFCM_Coord) {
+ FreeCoordMemory ();
+ DeleteAllSelections();
+ }
+
+ if (DelMask & MMDBFCM_SecStruct) {
+ GetModelTable ( model,nm );
+ if (model)
+ for (i=0;i<nm;i++)
+ if (model[i])
+ model[i]->RemoveSecStructure();
+ }
+
+ if (DelMask & MMDBFCM_HetInfo) {
+ GetModelTable ( model,nm );
+ if (model)
+ for (i=0;i<nm;i++)
+ if (model[i])
+ model[i]->RemoveHetInfo();
+ }
+
+ if (DelMask & MMDBFCM_Links) {
+ GetModelTable ( model,nm );
+ if (model)
+ for (i=0;i<nm;i++)
+ if (model[i]) {
+ model[i]->RemoveLinks ();
+ model[i]->RemoveLinkRs();
+ }
+ }
+
+ if (DelMask & MMDBFCM_CisPeps) {
+ GetModelTable ( model,nm );
+ if (model)
+ for (i=0;i<nm;i++)
+ if (model[i])
+ model[i]->RemoveCisPeps();
+ }
+
+ if (DelMask & MMDBFCM_ChainAnnot) {
+ nm = GetNumberOfModels();
+ for (i=1;i<=nm;i++) {
+ GetChainTable ( i,chain,nchains );
+ if (chain)
+ for (j=0;j<nchains;j++)
+ if (chain[j])
+ chain[j]->FreeAnnotations();
+ }
+ }
+
+ if (DelMask & MMDBFCM_SA) SA.FreeContainer();
+ if (DelMask & MMDBFCM_SB) SB.FreeContainer();
+ if (DelMask & MMDBFCM_SC) SC.FreeContainer();
+ if (DelMask & MMDBFCM_Footnotes) Footnote.FreeContainer();
+
+ if (DelMask & MMDBFCM_Buffer) {
+ lcount = 0;
+ S[0] = char(0);
+ }
+
+ }
+
+ PTitleContainer Manager::GetRemarks() {
+ return title.GetRemarks();
+ }
+
+
+ PTitleContainer Manager::GetJournal() {
+ return title.GetJournal();
+ }
+
+ realtype Manager::GetResolution() {
+ return title.GetResolution();
+ }
+
+ int Manager::ParseBiomolecules() {
+ return title.ParseBiomolecules();
+ }
+
+ int Manager::GetNofBiomolecules() {
+ return title.GetNofBiomolecules();
+ }
+
+ void Manager::GetBiomolecules ( PPBiomolecule & BM, int & nBMs ) {
+ title.GetBiomolecules ( BM,nBMs );
+ }
+
+ PBiomolecule Manager::GetBiomolecule ( int bmNo ) {
+ return title.GetBiomolecule ( bmNo );
+ }
+
+ PManager Manager::MakeBiomolecule ( int bmNo, int modelNo ) {
+ PManager M;
+ PPChain ch;
+ PChain chain;
+ PModel model;
+ PBiomolecule BM;
+ int i,j,k,n,n0,nChains;
+
+ BM = title.GetBiomolecule ( bmNo );
+ if (!BM) return NULL;
+
+ GetChainTable ( modelNo,ch,nChains );
+ if ((!ch) || (nChains<=0)) return NULL;
+
+ n0 = 0;
+ model = new Model();
+
+ for (i=0;(i<BM->nBMAs) && (n0>=0);i++)
+ if (BM->bmApply[i]) {
+ for (j=0;(j<BM->bmApply[i]->nMatrices) && (n0>=0);j++)
+ for (k=0;(k<BM->bmApply[i]->nChains) && (n0>=0);k++) {
+ n0 = -1;
+ for (n=0;(n<nChains) && (n0<0);n++)
+ if (!strcmp(ch[n]->GetChainID(),BM->bmApply[i]->chain[k]))
+ n0 = n;
+ if (n0>=0) {
+ chain = new Chain();
+ chain->Copy ( ch[n0] );
+ chain->ApplyTransform ( BM->bmApply[i]->tm[j] );
+ model->AddChain ( chain );
+ }
+ }
+ }
+
+ if (n0>=0) {
+ M = new Manager();
+ M->AddModel ( model );
+ M->PDBCleanup ( PDBCLEAN_SERIAL | PDBCLEAN_INDEX );
+ } else {
+ delete model;
+ M = NULL;
+ }
+
+ return M;
+
+ }
+
+
+ // ------------------- Stream functions ----------------------
+
+
+ void Manager::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ BondManager::write ( f );
+ }
+
+ void Manager::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ BondManager::read ( f );
+ }
+
+
+ MakeStreamFunctions(Manager)
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_manager.h b/mmdb2/mmdb_manager.h
new file mode 100644
index 0000000..c70d804
--- /dev/null
+++ b/mmdb2/mmdb_manager.h
@@ -0,0 +1,124 @@
+// $Id: mmdb_manager.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 15.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_manager <interface>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Manager ( MMDB file manager )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Manager__
+#define __MMDB_Manager__
+
+#include "mmdb_bondmngr.h"
+
+namespace mmdb {
+
+ // ======================= Manager ===========================
+
+ // copy masks
+ enum COPY_MASK {
+ MMDBFCM_None = 0x00000000,
+ MMDBFCM_All = 0xFFFFFFFF,
+ MMDBFCM_Title = 0x00000001,
+ MMDBFCM_TitleKeepBM = 0x00000002,
+ MMDBFCM_Cryst = 0x00000004,
+ MMDBFCM_Coord = 0x00000008,
+ MMDBFCM_SecStruct = 0x00000010,
+ MMDBFCM_HetInfo = 0x00000020,
+ MMDBFCM_Links = 0x00000040,
+ MMDBFCM_CisPeps = 0x00000080,
+ MMDBFCM_SA = 0x00000100,
+ MMDBFCM_SB = 0x00000200,
+ MMDBFCM_SC = 0x00000400,
+ MMDBFCM_Footnotes = 0x00000800,
+ MMDBFCM_ChainAnnot = 0x00001000,
+ MMDBFCM_Flags = 0x00002000,
+ MMDBFCM_Buffer = 0x80000000,
+ MMDBFCM_Top = 0xFFFFFFF7
+ };
+
+ DefineStreamFunctions(Manager);
+
+ class Manager : public BondManager {
+
+ public :
+
+ Manager ();
+ Manager ( io::RPStream Object );
+ ~Manager();
+
+
+ // --------------- Copying/Deleting -----------------------
+
+ // Copy(..) will transfer different sort of information
+ // between two MMDB's according to the copy mask given
+ // (cf. MMDBFCM_XXXXX values). Note that the copying content
+ // replaces the corresponding information (e.g. copying
+ // coordinates will replace existing coordinates rather than
+ // add to them).
+ void Copy ( PManager MMDB, COPY_MASK CopyMask );
+
+ // Delete(..) deletes different sort of information from
+ // the MMDB according to the delete mask given.
+ void Delete ( word DelMask ); // DelMask is the same as CopyMask
+
+ PTitleContainer GetRemarks();
+ PTitleContainer GetJournal();
+
+ realtype GetResolution(); // -1.0 means no resolution record in file
+
+ int ParseBiomolecules(); // returns the number of biomolecules,
+ // -2 for general format error
+ // -3 for errors in BIOMT records
+ int GetNofBiomolecules();
+ void GetBiomolecules ( PPBiomolecule & BM, int & nBMs );
+
+ PBiomolecule GetBiomolecule ( int bmNo ); // bmno=0,1,..
+ // returns NULL if bmNo is incorrect
+ PManager MakeBiomolecule ( int bmNo, int modelNo=1 );
+
+
+ protected :
+
+ // --------------- Stream I/O -----------------------------
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ };
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_mask.cpp b/mmdb2/mmdb_mask.cpp
new file mode 100644
index 0000000..dbf9891
--- /dev/null
+++ b/mmdb2/mmdb_mask.cpp
@@ -0,0 +1,240 @@
+// $Id: mmdb_mask.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDBF_Mask <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Classes : mmdb::Mask ( atom selection mask )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mmdb_mask.h"
+
+namespace mmdb {
+
+ // ==================== Mask ========================
+
+ Mask::Mask() : io::Stream() {
+ InitMask();
+ }
+
+ Mask::Mask ( io::RPStream Object ) : io::Stream(Object) {
+ InitMask();
+ }
+
+ Mask::~Mask() {
+ ClearMask();
+ }
+
+ void Mask::InitMask() {
+ mlen = 0;
+ m = NULL;
+ }
+
+ void Mask::SetMaskBit ( int BitNo ) {
+ int n,i;
+ n = BitNo/(8*sizeof(word));
+ Expand ( n+1 );
+ i = BitNo - n*(8*sizeof(word));
+ m[n] |= ((word)1 << i);
+ }
+
+ void Mask::Expand ( int n ) {
+ wvector m1;
+ int i;
+ if (mlen<n) {
+ m1 = new word[n];
+ for (i=0;i<mlen;i++)
+ m1[i] = m[i];
+ for (i=mlen;i<n;i++)
+ m1[i] = 0;
+ if (m) delete[] m;
+ m = m1;
+ mlen = n;
+ }
+ }
+
+ void Mask::NewMask ( PPMask Mask, int nMasks ) {
+ int i,nlen;
+ word w;
+ ClearMask();
+ if (Mask && (nMasks>0)) {
+ nlen = 0;
+ w = 0;
+ while (w==0) {
+ for (i=0;i<nMasks;i++)
+ if (Mask[i]) {
+ if (nlen<Mask[i]->mlen)
+ w |= Mask[i]->m[nlen];
+ }
+ nlen++;
+ w = ~w;
+ }
+ Expand ( nlen );
+ i = nlen-1;
+ m[i] = 1;
+ while (!(m[i] & w))
+ m[i] <<= 1;
+ } else {
+ Expand ( 1 );
+ m[0] = 1;
+ }
+ }
+
+ void Mask::CopyMask ( PMask Mask ) {
+ int i;
+ if (mlen!=Mask->mlen) ClearMask();
+ if (Mask) {
+ mlen = Mask->mlen;
+ if (mlen>0) {
+ m = new word[mlen];
+ for (i=0;i<mlen;i++)
+ m[i] = Mask->m[i];
+ }
+ }
+ }
+
+ void Mask::SetMask ( PMask Mask ) {
+ int i;
+ if (Mask) {
+ Expand ( Mask->mlen );
+ for (i=0;i<Mask->mlen;i++)
+ m[i] |= Mask->m[i];
+ }
+ }
+
+ void Mask::RemoveMask ( PMask Mask ) {
+ int i,l;
+ if (Mask) {
+ l = IMin(mlen,Mask->mlen);
+ for (i=0;i<l;i++)
+ m[i] &= ~Mask->m[i];
+ }
+ }
+
+ void Mask::SelMask ( PMask Mask ) {
+ int i,l;
+ if (Mask) {
+ l = IMin(mlen,Mask->mlen);
+ for (i=0;i<l;i++)
+ m[i] &= Mask->m[i];
+ for (i=l;i<mlen;i++)
+ m[i] = 0;
+ } else
+ ClearMask();
+ }
+
+ void Mask::XadMask ( PMask Mask ) {
+ int i;
+ if (Mask) {
+ Expand ( Mask->mlen );
+ for (i=0;i<Mask->mlen;i++)
+ m[i] ^= Mask->m[i];
+ }
+ }
+
+ void Mask::ClearMask() {
+ if (m) delete[] m;
+ m = NULL;
+ mlen = 0;
+ }
+
+ void Mask::NegMask() {
+ int i;
+ for (i=0;i<mlen;i++)
+ m[i] = ~m[i];
+ }
+
+ bool Mask::CheckMask ( PMask Mask ) {
+ int i,l;
+ if (Mask) {
+ i = 0;
+ l = IMin(mlen,Mask->mlen);
+ while ((i<l) && (!(m[i] & Mask->m[i]))) i++;
+ return (i<l);
+ } else
+ return false;
+ }
+
+ bool Mask::isMask() {
+ int i=0;
+ while ((i<mlen) && (!m[i])) i++;
+ return (i<mlen);
+ }
+
+ pstr Mask::Print ( pstr S ) {
+ int i,j,k;
+ word w;
+ j = 0;
+ for (i=0;i<mlen;i++) {
+ w = 1;
+ for (k=0;k<8*(int)sizeof(word);k++) {
+ if (w & m[i]) S[j] = '1';
+ else S[j] = '0';
+ w <<= 1;
+ j++;
+ }
+ }
+ S[j] = char(0);
+ return S;
+ }
+
+ void Mask::write ( io::RFile f ) {
+ int i;
+ f.WriteInt ( &mlen );
+ for (i=0;i<mlen;i++)
+ f.WriteWord ( &(m[i]) );
+ }
+
+ void Mask::read ( io::RFile f ) {
+ int i;
+ if (m) {
+ delete[] m;
+ m = NULL;
+ }
+ f.ReadInt ( &mlen );
+ if (mlen>0) {
+ m = new word[mlen];
+ for (i=0;i<mlen;i++)
+ f.ReadWord ( &(m[i]) );
+ }
+ }
+
+ MakeStreamFunctions(Mask)
+
+} // namespace mmdb
+
diff --git a/mmdb2/mmdb_mask.h b/mmdb2/mmdb_mask.h
new file mode 100644
index 0000000..697b328
--- /dev/null
+++ b/mmdb2/mmdb_mask.h
@@ -0,0 +1,95 @@
+// $Id: mmdb_mask.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDBF_Mask <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Classes : mmdb::Mask ( atom selection mask )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Mask__
+#define __MMDB_Mask__
+
+#include "mmdb_io_stream.h"
+
+namespace mmdb {
+
+ // ========================== Mask =============================
+
+ DefineClass(Mask);
+ DefineStreamFunctions(Mask);
+
+ class Mask : public io::Stream {
+
+ public :
+
+ Mask ();
+ Mask ( io::RPStream Object );
+ ~Mask();
+
+ void SetMaskBit ( int BitNo );
+ void NewMask ( PPMask Mask, int nMasks );
+
+ void CopyMask ( PMask Mask ); // this = Mask
+ void SetMask ( PMask Mask ); // this = this | Mask
+ void RemoveMask ( PMask Mask ); // this = this & (~Mask)
+ void SelMask ( PMask Mask ); // this = this & Mask
+ void XadMask ( PMask Mask ); // this = this ^ Mask
+ void ClearMask (); // this = NULL
+ void NegMask (); // this = ~this
+
+ bool CheckMask ( PMask Mask ); // true if the bit is on
+ bool isMask (); // true if any mask bit is on
+
+ inline int getLength() { return mlen; }
+
+ pstr Print ( pstr S ); // returns binary string
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ int mlen;
+ wvector m;
+
+ void InitMask();
+ void Expand ( int n );
+
+ };
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_math_.cpp b/mmdb2/mmdb_math_.cpp
new file mode 100644
index 0000000..23cfdc8
--- /dev/null
+++ b/mmdb2/mmdb_math_.cpp
@@ -0,0 +1,203 @@
+// $Id: mmdb_math.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 11.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Math <implementation>
+// ~~~~~~~~~
+// **** Functions : mmdb::math::GetTorsion
+// ~~~~~~~~~~~ mmdb::math::GetAngle
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <math.h>
+
+#include "mmdb_math_.h"
+
+namespace mmdb {
+
+ namespace math {
+
+ // --------------------------------------------------------------
+
+ realtype GetTorsion ( rvector U, rvector W, rvector V ) {
+ // U W V
+ // o<----o----->o----->o
+ //
+ realtype A[3],B[3],C[3],Wmag,S,T;
+
+ A[0] = U[1]*W[2] - W[1]*U[2];
+ A[1] = U[2]*W[0] - W[2]*U[0];
+ A[2] = U[0]*W[1] - W[0]*U[1];
+
+ B[0] = V[1]*W[2] - W[1]*V[2];
+ B[1] = V[2]*W[0] - W[2]*V[0];
+ B[2] = V[0]*W[1] - W[0]*V[1];
+
+ C[0] = A[1]*B[2] - B[1]*A[2];
+ C[1] = A[2]*B[0] - B[2]*A[0];
+ C[2] = A[0]*B[1] - B[0]*A[1];
+
+ Wmag = sqrt(W[0]*W[0]+W[1]*W[1]+W[2]*W[2]);
+
+ S = C[0]*W[0] + C[1]*W[1] + C[2]*W[2];
+ T = A[0]*B[0] + A[1]*B[1] + A[2]*B[2];
+ T *= Wmag;
+
+ if ((S==0.0) && (T==0.0)) return NO_TORSION;
+ else return atan2(S,T);
+
+ }
+
+
+ realtype GetAngle ( rvector v1, rvector v2 ) {
+ realtype l1,l2;
+
+ l1 = v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2];
+ if (l1==0.0) l1 = 1.0;
+ l2 = v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2];
+ if (l2==0.0) l2 = 1.0;
+
+ return acos((v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])/sqrt(l1*l2));
+
+ }
+
+
+ #define nCombMax 500
+
+ realtype Combinations ( int n, int m ) {
+ // 0<=n<=nCombMax, 0<=m<=n
+ realtype P[nCombMax+1];
+ int i,j;
+ if ((m<0) || (m>n)) return 0.0;
+ if ((m==0) || (m==n)) return 1.0;
+ if ((m==1) || (m==n-1)) return realtype(n);
+ P[0] = 1.0;
+ P[1] = 3.0;
+ P[2] = 3.0;
+ P[3] = 1.0;
+ for (i=4;i<=n;i++) {
+ P[i] = 1.0;
+ for (j=i-1;j>0;j--)
+ P[j] += P[j-1];
+ }
+ return P[m];
+ }
+
+ realtype log1mx ( realtype x ) {
+ // Calculates precisely log(1-x) for x<1, including
+ // very small x
+ realtype z,z1,z2,n;
+
+ if (x>=1.0-10.0*MachEps) z = -MaxReal;
+ else if (fabs(x)>1.0e-8) z = log(1.0-x);
+ else {
+ z1 = x;
+ z = 0.0;
+ n = 1.0;
+ do {
+ z2 = z;
+ z -= z1/n;
+ z1 *= x;
+ n += 1.0;
+ } while (z!=z2);
+ }
+
+ return z;
+
+ }
+
+ realtype expc ( realtype x ) {
+ // Calculates precisely 1 - exp(x) for any x including
+ // very small values
+ realtype z,z1,z2,n;
+
+ if (x>LnMaxReal) z = -MaxReal;
+ else if (x<-LnMaxReal) z = 1.0;
+ else if (fabs(x)>1.0e-8) z = 1.0 - Exp(x);
+ else {
+ z1 = x;
+ z = x;
+ n = 1.0;
+ do {
+ z2 = z;
+ n += 1.0;
+ z1 *= x/n;
+ z += z1;
+ } while (z!=z2);
+ z = -z;
+ }
+
+ return z;
+
+ }
+
+
+ realtype expc1mx ( realtype x, realtype y ) {
+ // Calculates precisely 1-(1-x)**y including very small x and
+ // very large y
+ realtype z,z1,z2,n,s;
+
+ // Calculate (1-x)**y as exp(y*log(1-x)). Get log(1-x) first:
+ if (x>1.0e-8) z = log(1.0-x);
+ else {
+ z1 = x;
+ z = 0.0;
+ n = 1.0;
+ do {
+ z2 = z;
+ z -= z1/n;
+ z1 *= x;
+ n += 1.0;
+ } while (z!=z2);
+ }
+
+ // Now calculate 1 - exp(y*log(1-x)) :
+ z *= y;
+ if (fabs(z)>1.0e-8) s = 1.0 - exp(z);
+ else {
+ z1 = z;
+ s = z;
+ n = 1.0;
+ do {
+ z2 = s;
+ n += 1.0;
+ z1 *= z/n;
+ s += z1;
+ } while (s!=z2);
+ s = -s;
+ }
+
+ return s;
+
+ }
+
+ }
+
+}
diff --git a/mmdb2/mmdb_math_.h b/mmdb2/mmdb_math_.h
new file mode 100644
index 0000000..70172ee
--- /dev/null
+++ b/mmdb2/mmdb_math_.h
@@ -0,0 +1,77 @@
+// $Id: mmdb_math.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 11.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Math <interface>
+// ~~~~~~~~~
+// **** Functions : mmdb::math::GetTorsion
+// ~~~~~~~~~~~ mmdb::math::GetAngle
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Math__
+#define __MMDB_Math__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb {
+
+ namespace math {
+
+ // ------------------------------------------------------------------
+
+ const realtype NO_TORSION = -MaxReal;
+
+ // U[0,1,2] = x,y,z
+ extern realtype GetTorsion ( rvector U, rvector W, rvector V );
+ extern realtype GetAngle ( rvector U, rvector V );
+
+ // Calculates the binomial coefficient n choose m, 0<=n<=500, 0<=m<=n
+ extern realtype Combinations ( int n, int m );
+
+ // Calculates precisely log(1-x) for x<1, including very small x
+ extern realtype log1mx ( realtype x );
+
+ // Calculates precisely 1 - exp(x) for any x including very small values
+ extern realtype expc ( realtype x );
+
+ inline double exp10 ( double x ) { return exp(x*ln10); }
+
+ // Calculates precisely 1-(1-x)**y including very small x and very large y
+ extern realtype expc1mx ( realtype x, realtype y );
+
+ }
+
+}
+
+
+#endif
+
+
diff --git a/mmdb2/mmdb_math_align.cpp b/mmdb2/mmdb_math_align.cpp
new file mode 100644
index 0000000..a974839
--- /dev/null
+++ b/mmdb2/mmdb_math_align.cpp
@@ -0,0 +1,1226 @@
+// $Id: mmdb_math_align.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Align <implementation>
+// ~~~~~~~~~
+// **** Classes : mmdb::math::Alignment (char strings alignment)
+// ~~~~~~~~~~~~ mmdb::math::Alignment1 (int vectors alignment)
+//
+// (C) E.Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <math.h>
+
+#include "mmdb_math_align.h"
+
+
+namespace mmdb {
+
+ namespace math {
+
+ // ===================== CAligParams ======================
+
+ AlignParams::AlignParams() : Stream() {
+ InitAlignParams();
+ }
+
+ AlignParams::AlignParams ( io::RPStream Object ) :
+ io::Stream ( Object ) {
+ InitAlignParams();
+ }
+
+ void AlignParams::InitAlignParams() {
+ gapWeight = -1.0;
+ spaceWeight = -1.0;
+ equalScore = 2.0;
+ nequalScore = -1.0;
+ method = ALIGN_GLOBAL;
+ }
+
+ void AlignParams::write ( io::RFile f ) {
+ f.WriteReal ( &gapWeight );
+ f.WriteReal ( &spaceWeight );
+ f.WriteReal ( &equalScore );
+ f.WriteReal ( &nequalScore );
+ f.WriteInt ( &method );
+ }
+
+ void AlignParams::read ( io::RFile f ) {
+ f.ReadReal ( &gapWeight );
+ f.ReadReal ( &spaceWeight );
+ f.ReadReal ( &equalScore );
+ f.ReadReal ( &nequalScore );
+ f.ReadInt ( &method );
+ }
+
+ MakeStreamFunctions(AlignParams)
+
+
+ // ===================== Alignment ======================
+
+ Alignment::Alignment() : io::Stream() {
+ InitAlignment();
+ }
+
+ Alignment::Alignment ( io::RPStream Object ) :
+ io::Stream ( Object ) {
+ InitAlignment();
+ }
+
+ Alignment::~Alignment() {
+ FreeMemory();
+ }
+
+ void Alignment::InitAlignment() {
+ Space = '-';
+ SLen = 0;
+ TLen = 0;
+ VT = NULL;
+ ET = NULL;
+ FT = NULL;
+ AlgnS = NULL;
+ AlgnT = NULL;
+ AlignKey = ALIGN_GLOBAL;
+ VAchieved = 0.0;
+ SEq = 2.0;
+ SNEq = -1.0;
+ Wg = 0.0;
+ Ws = -1.0;
+ }
+
+ void Alignment::FreeMemory() {
+ FreeMatrixMemory ( VT,TLen+1,0,0 );
+ FreeMatrixMemory ( ET,TLen+1,0,0 );
+ FreeMatrixMemory ( FT,TLen+1,0,0 );
+ if (AlgnS) {
+ delete[] AlgnS;
+ AlgnS = NULL;
+ }
+ if (AlgnT) {
+ delete[] AlgnT;
+ AlgnT = NULL;
+ }
+ TLen = 0;
+ SLen = 0;
+ }
+
+ void Alignment::SetAffineModel ( realtype WGap, realtype WSpace ) {
+ Wg = WGap;
+ Ws = WSpace;
+ }
+
+ void Alignment::SetScores ( realtype SEqual, realtype SNEqual ) {
+ SEq = SEqual;
+ SNEq = SNEqual;
+ }
+
+ void Alignment::Align ( cpstr S, cpstr T, ALIGN_METHOD Method ) {
+ int i,j,i0,j0;
+
+ FreeMemory();
+
+ AlignKey = Method;
+
+ switch (Method) {
+
+ default :
+ case ALIGN_GLOBAL : // global pairwise alignment of S and T
+ BuildGATable ( S,T, false,false );
+ VAchieved = VT[TLen][SLen];
+ Backtrace ( S,T,SLen,TLen,false );
+ if ((AlgnS[0]!=Space) && (AlgnT[0]!=Space))
+ VAchieved -= Wg;
+ break;
+
+ case ALIGN_LOCAL : // local pairwise alignment of S and T
+ BuildLATable ( S,T );
+ VAchieved = 0.0;
+ i0 = -1;
+ j0 = -1;
+ for (i=0;i<=TLen;i++)
+ for (j=0;j<=SLen;j++)
+ if (VT[i][j]>VAchieved) {
+ VAchieved = VT[i][j];
+ i0 = i;
+ j0 = j;
+ }
+ Backtrace ( S,T,j0,i0,true );
+ break;
+
+ case ALIGN_GLOBLOC : // global alignment with non-penalized
+ // end gaps in T
+ BuildGATable ( S,T,false,true );
+ VAchieved = -MaxReal;
+ i0 = -1;
+ j0 = -1;
+ for (i=0;i<=TLen;i++)
+ if (VT[i][SLen]>VAchieved) {
+ VAchieved = VT[i][SLen];
+ i0 = i;
+ j0 = SLen;
+ }
+ Backtrace ( S,T,j0,i0,false );
+ AdjustEnds ( S,T,j0,i0 );
+ break;
+
+ case ALIGN_FREEENDS : // global alignment with non-penalized
+ // end gaps in both S and T
+ BuildGATable ( S,T,true,true );
+ VAchieved = -MaxReal;
+ i0 = -1;
+ j0 = -1;
+ for (i=0;i<=TLen;i++)
+ if (VT[i][SLen]>VAchieved) {
+ VAchieved = VT[i][SLen];
+ i0 = i;
+ j0 = SLen;
+ }
+ for (j=0;j<=SLen;j++)
+ if (VT[TLen][j]>VAchieved) {
+ VAchieved = VT[TLen][j];
+ i0 = TLen;
+ j0 = j;
+ }
+ Backtrace ( S,T,j0,i0,false );
+ AdjustEnds ( S,T,j0,i0 );
+
+ }
+
+ }
+
+
+ void Alignment::BuildGATable ( cpstr S, cpstr T,
+ bool FreeSEnd, bool FreeTEnd ) {
+ int i,j;
+ realtype V1;
+
+ SLen = strlen ( S );
+ TLen = strlen ( T );
+ GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
+ GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
+ GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
+
+ // Base conditions
+ if (FreeSEnd || FreeTEnd) VT[0][0] = RMax(0.0,Wg);
+ else VT[0][0] = Wg;
+ ET[0][0] = VT[0][0];
+ FT[0][0] = VT[0][0];
+
+ if (FreeTEnd)
+ for (i=1;i<=TLen;i++) {
+ V1 = RMax ( 0.0,VT[i-1][0]+Ws );
+ VT[i][0] = V1;
+ ET[i][0] = V1;
+ }
+ else
+ for (i=1;i<=TLen;i++) {
+ V1 = VT[i-1][0] + Ws;
+ VT[i][0] = V1;
+ ET[i][0] = V1;
+ }
+
+ if (FreeSEnd)
+ for (j=1;j<=SLen;j++) {
+ V1 = RMax ( 0.0,VT[0][j-1]+Ws );
+ VT[0][j] = V1;
+ FT[0][j] = V1;
+ }
+ else
+ for (j=1;j<=SLen;j++) {
+ V1 = VT[0][j-1] + Ws;
+ VT[0][j] = V1;
+ FT[0][j] = V1;
+ }
+
+ // Recurrence
+ for (i=1;i<=TLen;i++)
+ for (j=1;j<=SLen;j++) {
+ V1 = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
+ ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
+ FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
+ VT[i][j] = RMax ( RMax(V1,ET[i][j]),FT[i][j] );
+ }
+
+ FreeMatrixMemory ( ET,TLen+1,0,0 );
+ FreeMatrixMemory ( FT,TLen+1,0,0 );
+
+ // PrintVT ( S,T );
+
+ }
+
+
+ void Alignment::BuildLATable ( cpstr S, cpstr T ) {
+ int i,j;
+ realtype V1;
+
+ SLen = strlen ( S );
+ TLen = strlen ( T );
+ GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
+ GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
+ GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
+
+ // Base conditions
+ VT[0][0] = RMax ( 0.0,Wg );
+ ET[0][0] = VT[0][0];
+ FT[0][0] = VT[0][0];
+ for (i=1;i<=TLen;i++) {
+ V1 = RMax ( 0.0,VT[i-1][0]+Ws );
+ VT[i][0] = V1;
+ ET[i][0] = V1;
+ }
+ for (j=1;j<=SLen;j++) {
+ V1 = RMax ( 0.0,VT[0][j-1]+Ws );
+ VT[0][j] = V1;
+ FT[0][j] = V1;
+ }
+
+ // Recurrence
+ for (i=1;i<=TLen;i++)
+ for (j=1;j<=SLen;j++) {
+ V1 = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
+ ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
+ FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
+ VT[i][j] = RMax ( RMax(V1,ET[i][j]),RMax(0.0,FT[i][j]) );
+ }
+
+ FreeMatrixMemory ( ET,TLen+1,0,0 );
+ FreeMatrixMemory ( FT,TLen+1,0,0 );
+
+ // PrintVT ( S,T );
+
+ }
+
+ void Alignment::PrintVT ( cpstr S, cpstr T ) {
+ int i,j;
+ printf ( "\n " );
+ for (j=0;j<=SLen;j++)
+ printf ( " %2i",j );
+ printf ( " \n " );
+ for (j=1;j<=SLen;j++)
+ printf ( " %c ",S[j-1] );
+ printf ( " \n\n " );
+ for (i=0;i<=TLen;i++) {
+ if (i>0) printf ( " %2i %c ",i,T[i-1] );
+ else printf ( " %2i ",i );
+ for (j=0;j<=SLen;j++)
+ printf ( " %2i",mround(VT[i][j]) );
+ printf ( " \n " );
+ }
+ printf ( " \n" );
+ }
+
+
+ void Alignment::Backtrace ( cpstr S, cpstr T, int J, int I,
+ bool StopAtZero ) {
+ int i,j,k, i1,j1, sk,tk;
+ char C;
+ realtype V,SV,TV;
+ bool Stop;
+
+ // 1. Allocate memory
+
+ if (AlgnS) delete[] AlgnS;
+ if (AlgnT) delete[] AlgnT;
+
+ i = SLen+TLen+1;
+ AlgnS = new char[i];
+ AlgnT = new char[i];
+ memset ( AlgnS,Space,i );
+ memset ( AlgnT,Space,i );
+
+ // 2. Initialize backtracing
+ i = I; // backtracing
+ j = J; // indices
+ k = 0; // alignment index
+ SV = 0.0; sk = -1; // alignment indices and leading elements
+ TV = 0.0; tk = -1; // for vertical and horizontal sections
+
+
+ // 3. Backtracing
+ Stop = false;
+ while ((!Stop) && (i>0) && (j>0)) {
+
+ V = VT[i][j];
+
+ // find next leading element
+ if (VT[i][j-1]>VT[i-1][j]) {
+ i1 = i; j1 = j-1;
+ } else {
+ i1 = i-1; j1 = j;
+ }
+ if (VT[i-1][j-1]>=VT[i1][j1]) {
+ i1 = i-1; j1 = j-1;
+ }
+
+ //printf ( " i=%i j=%i \n",i,j );
+
+ Stop = StopAtZero && (VT[i1][j1]<=0.0); // used at local alignment
+
+ // treat horizontal section
+ if ((sk<0) || (V>SV)) {
+ sk = k;
+ SV = V;
+ }
+ if ((j1!=j) || Stop) { // end of horizontal section
+ AlgnS[sk] = S[j-1];
+ sk = -1;
+ }
+
+ // treat vertical section
+ if ((tk<0) || (V>TV)) {
+ tk = k;
+ TV = V;
+ }
+ if ((i1!=i) || Stop) { // end of vertical section
+ AlgnT[tk] = T[i-1];
+ tk = -1;
+ }
+
+ i = i1;
+ j = j1;
+ k++;
+
+ }
+
+ if (!StopAtZero) {
+ // 4. Finish the last horizontal section
+ sk = k;
+ while (j>0) AlgnS[k++] = S[--j];
+ // 5. Finish the last vertical section
+ while (i>0) AlgnT[sk++] = T[--i];
+ k = IMax ( k,sk );
+ }
+
+ // 6. Put the termination character
+ AlgnS[k] = char(0);
+ AlgnT[k] = char(0);
+
+ // 7. Reverse the strings
+ i = 0;
+ j = k-1;
+ if (StopAtZero) {
+ // should work only for local alignment
+ while ((j>0) && ((AlgnS[j]==Space) || (AlgnT[j]==Space))) j--;
+ k = j+1;
+ AlgnS[k] = char(0);
+ AlgnT[k] = char(0);
+ }
+ while (j>i) {
+ C = AlgnS[i]; AlgnS[i] = AlgnS[j]; AlgnS[j] = C;
+ C = AlgnT[i]; AlgnT[i] = AlgnT[j]; AlgnT[j] = C;
+ i++;
+ j--;
+ }
+
+ // 8. Collapse the alternating spaces
+ do {
+ k = 0;
+ i = 0;
+ while (AlgnS[k]) {
+ if ((AlgnS[k]==Space) && (AlgnT[k]==Space)) k++;
+ else if ((AlgnS[k]==Space) && (AlgnS[k+1]!=Space) &&
+ (AlgnT[k]!=Space) && (AlgnT[k+1]==Space)) {
+ AlgnS[i] = AlgnS[k+1];
+ AlgnT[i] = AlgnT[k];
+ k++;
+ } else if ((AlgnS[k]!=Space) && (AlgnS[k+1]==Space) &&
+ (AlgnT[k]==Space) && (AlgnT[k+1]!=Space)) {
+ AlgnS[i] = AlgnS[k];
+ AlgnT[i] = AlgnT[k+1];
+ k++;
+ } else if (i!=k) {
+ AlgnS[i] = AlgnS[k];
+ AlgnT[i] = AlgnT[k];
+ }
+ if (AlgnS[k]) {
+ k++;
+ i++;
+ }
+ }
+ if (i!=k) { // terminating character
+ AlgnS[i] = AlgnS[k];
+ AlgnT[i] = AlgnT[k];
+ }
+ } while (k>i);
+
+ }
+
+
+ void Alignment::AdjustEnds ( cpstr S, cpstr T, int J, int I ) {
+ int si,ti,m;
+
+ if (J<SLen) strcat ( AlgnS,&(S[J]) );
+ if (I<TLen) strcat ( AlgnT,&(T[I]) );
+ si = strlen ( AlgnS );
+ ti = strlen ( AlgnT );
+ m = IMax ( si,ti );
+ while (si<m) AlgnS[si++] = Space;
+ while (ti<m) AlgnT[ti++] = Space;
+ AlgnS[si] = char(0);
+ AlgnT[ti] = char(0);
+
+ /*
+ int k,m;
+
+ if (J>I) {
+ k = J-I;
+ strcat ( AlgnT,&(T[IMax(0,TLen-k)]) );
+ k = strlen ( AlgnS );
+ m = strlen ( AlgnT );
+ while (k<m)
+ AlgnS[k++] = Space;
+ AlgnS[k] = char(0);
+ } else if (I>J) {
+ k = I-J;
+ strcat ( AlgnS,&(S[IMax(0,SLen-k)]) );
+ k = strlen ( AlgnT );
+ m = strlen ( AlgnS );
+ while (k<m)
+ AlgnT[k++] = Space;
+ AlgnT[k] = char(0);
+ }
+ */
+
+ }
+
+
+ realtype Alignment::Score ( char A, char B ) {
+ if (A==B) return SEq;
+ if ((A==Space) || (B==Space)) return Ws;
+ return SNEq;
+ }
+
+ realtype Alignment::GetSimilarity() {
+ realtype s,a;
+ int i,n;
+
+ s = 0.0;
+ a = 0.0;
+ n = IMin ( strlen(AlgnS),strlen(AlgnT) );
+
+ for (i=0;i<n;i++)
+ if ((AlgnS[i]!=Space) || (AlgnT[i]!=Space)) {
+ a += RMax ( Score(AlgnS[i],AlgnS[i]),Score(AlgnT[i],AlgnT[i]) );
+ s += Score ( AlgnS[i],AlgnT[i] );
+ }
+
+ if ((s>0.0) && (a>0.0)) return s/a;
+ return 0.0;
+
+ }
+
+
+ realtype Alignment::GetSeqId() {
+ realtype s;
+ int i,n,ne,ns,nt;
+
+ ne = 0;
+ ns = 0;
+ nt = 0;
+ n = IMin ( strlen(AlgnS),strlen(AlgnT) );
+
+ for (i=0;i<n;i++) {
+ if (AlgnS[i]!=Space) ns++;
+ if (AlgnT[i]!=Space) {
+ nt++;
+ if (AlgnS[i]==AlgnT[i])
+ ne++;
+ }
+ }
+
+ s = IMin ( ns,nt );
+ if (s>0.0) return ne/s;
+ return 0.0;
+
+ }
+
+
+ #define WrapPeriod 61
+
+ void Alignment::OutputResults ( io::RFile f, cpstr S, cpstr T ) {
+ int k,l,n;
+ char P[3];
+
+ P[1] = char(0);
+ if ((!AlgnS) || (!AlgnT)) {
+ f.LF();
+ f.WriteLine ( pstr(" NO ALIGNMENT HAS BEEN DONE.") );
+ f.shut();
+ return;
+ }
+ f.LF();
+ f.WriteLine ( pstr(" ======== INPUT DATA") );
+ f.LF();
+ f.WriteLine ( pstr(" String S:") );
+ f.Write ( pstr(" ") );
+ l = 1;
+ k = 0;
+ while (S[k]) {
+ P[0] = S[k++];
+ f.Write ( P );
+ l++;
+ if (l>=WrapPeriod) {
+ f.LF(); f.Write ( pstr(" ") ); l = 1;
+ }
+ }
+ f.LF();
+ f.LF();
+ f.WriteLine ( pstr(" String T:") );
+ f.Write ( pstr(" ") );
+ l = 1;
+ k = 0;
+ while (T[k]) {
+ P[0] = T[k++];
+ f.Write ( P );
+ l++;
+ if (l>=WrapPeriod) {
+ f.LF(); f.Write ( pstr(" ") ); l = 1;
+ }
+ }
+ f.LF();
+ f.LF();
+ f.WriteParameter ( pstr(" Score equal") ,SEq ,20,10 );
+ f.WriteParameter ( pstr(" Score unequal"),SNEq,20,10 );
+ f.LF();
+ f.WriteParameter ( pstr(" Gap weight") ,Wg ,20,10 );
+ f.WriteParameter ( pstr(" Space weight") ,Ws ,20,10 );
+ f.LF();
+ f.LF();
+ f.Write ( pstr(" ======== RESULT OF ") );
+ switch (AlignKey) {
+ default :
+ case ALIGN_GLOBAL : f.Write ( pstr("GLOBAL") ); break;
+ case ALIGN_LOCAL : f.Write ( pstr("LOCAL") ); break;
+ case ALIGN_GLOBLOC : f.Write ( pstr("GLOBAL/LOCAL") ); break;
+ case ALIGN_FREEENDS : f.Write ( pstr("FREE-ENDS") );
+ }
+ f.WriteLine ( pstr(" ALIGNMENT") );
+ f.LF();
+ if (AlignKey==ALIGN_GLOBLOC) {
+ f.WriteLine ( pstr(" End gaps in T-string were not penalized") );
+ f.LF();
+ }
+ f.WriteParameter ( pstr(" Highest score achieved:"),VAchieved,26,10 );
+ f.LF();
+ f.WriteLine ( pstr(" Aligned S (upper string) and T (lower string):") );
+ f.LF();
+ k = 0;
+ n = 0;
+ l = 1; f.Write ( pstr(" ") );
+ while (AlgnS[k]) {
+ P[0] = AlgnS[k++];
+ f.Write ( P );
+ l++;
+ if ((l>=WrapPeriod) || (!AlgnS[k])) {
+ f.LF(); f.Write ( pstr(" ") ); l = 1;
+ while (AlgnT[n] && (l<WrapPeriod)) {
+ P[0] = AlgnT[n++];
+ f.Write ( P );
+ l++;
+ }
+ f.LF(); f.LF(); f.Write ( pstr(" ") ); l = 1;
+ }
+ }
+
+ }
+
+
+ // ----------------- Streaming -----------------------------
+
+ void Alignment::write ( io::RFile f ) {
+ int Version=1;
+ f.WriteFile ( &Version,sizeof(Version) );
+ Stream::write ( f );
+ }
+
+ void Alignment::read ( io::RFile f ) {
+ int Version;
+ f.ReadFile ( &Version,sizeof(Version) );
+ Stream::write ( f );
+ }
+
+
+
+ // ===================== Alignment1 ======================
+
+ Alignment1::Alignment1() : io::Stream() {
+ InitAlignment1();
+ }
+
+ Alignment1::Alignment1 ( io::RPStream Object ) :
+ io::Stream ( Object ) {
+ InitAlignment1();
+ }
+
+ Alignment1::~Alignment1() {
+ FreeMemory();
+ }
+
+ void Alignment1::InitAlignment1() {
+ Space = 0;
+ SLen = 0;
+ TLen = 0;
+ AlgnLen = 0;
+ VT = NULL;
+ ET = NULL;
+ FT = NULL;
+ AlgnS = NULL;
+ AlgnT = NULL;
+ AlignKey = ALIGN_GLOBAL;
+ VAchieved = 0.0;
+ SEq = 2.0;
+ SNEq = -1.0;
+ Wg = 0.0;
+ Ws = -1.0;
+ }
+
+ void Alignment1::FreeMemory() {
+ FreeMatrixMemory ( VT,TLen+1,0,0 );
+ FreeMatrixMemory ( ET,TLen+1,0,0 );
+ FreeMatrixMemory ( FT,TLen+1,0,0 );
+ FreeVectorMemory ( AlgnS,0 );
+ FreeVectorMemory ( AlgnT,0 );
+ TLen = 0;
+ SLen = 0;
+ AlgnLen = 0;
+ }
+
+ void Alignment1::SetAffineModel ( realtype WGap, realtype WSpace ) {
+ Wg = WGap;
+ Ws = WSpace;
+ }
+
+ void Alignment1::SetScores ( realtype SEqual, realtype SNEqual ) {
+ SEq = SEqual;
+ SNEq = SNEqual;
+ }
+
+ void Alignment1::Align ( ivector S, int SLength,
+ ivector T, int TLength,
+ ALIGN_METHOD Method ) {
+ int i,j,i0,j0;
+
+ FreeMemory();
+
+ SLen = SLength;
+ TLen = TLength;
+
+ AlignKey = Method;
+
+ switch (Method) {
+
+ default :
+ case ALIGN_GLOBAL : // global pairwise alignment of S and T
+ BuildGATable ( S,T, false,false );
+ VAchieved = VT[TLen][SLen];
+ Backtrace ( S,T,SLen,TLen,false );
+ if ((AlgnS[0]!=Space) && (AlgnT[0]!=Space))
+ VAchieved -= Wg;
+ break;
+
+ case ALIGN_LOCAL : // local pairwise alignment of S and T
+ BuildLATable ( S,T );
+ VAchieved = 0.0;
+ i0 = -1;
+ j0 = -1;
+ for (i=0;i<=TLen;i++)
+ for (j=0;j<=SLen;j++)
+ if (VT[i][j]>VAchieved) {
+ VAchieved = VT[i][j];
+ i0 = i;
+ j0 = j;
+ }
+ Backtrace ( S,T,j0,i0,true );
+ break;
+
+ case ALIGN_GLOBLOC : // global alignment with non-penalized
+ // end gaps in T
+ BuildGATable ( S,T,false,true );
+ VAchieved = -MaxReal;
+ i0 = -1;
+ j0 = -1;
+ for (i=0;i<=TLen;i++)
+ if (VT[i][SLen]>VAchieved) {
+ VAchieved = VT[i][SLen];
+ i0 = i;
+ j0 = SLen;
+ }
+ Backtrace ( S,T,j0,i0,false );
+ AdjustEnds ( S,T,j0,i0 );
+ break;
+
+ case ALIGN_FREEENDS : // global alignment with non-penalized
+ // end gaps in both S and T
+ BuildGATable ( S,T,true,true );
+ VAchieved = -MaxReal;
+ i0 = -1;
+ j0 = -1;
+ for (i=0;i<=TLen;i++)
+ if (VT[i][SLen]>VAchieved) {
+ VAchieved = VT[i][SLen];
+ i0 = i;
+ j0 = SLen;
+ }
+ for (j=0;j<=SLen;j++)
+ if (VT[TLen][j]>VAchieved) {
+ VAchieved = VT[TLen][j];
+ i0 = TLen;
+ j0 = j;
+ }
+ Backtrace ( S,T,j0,i0,false );
+ AdjustEnds ( S,T,j0,i0 );
+ }
+
+ }
+
+
+ void Alignment1::BuildGATable ( ivector S, ivector T,
+ bool FreeSEnd, bool FreeTEnd ) {
+ int i,j;
+ realtype V1;
+
+ GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
+ GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
+ GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
+
+ // Base conditions
+ if (FreeSEnd || FreeTEnd) VT[0][0] = RMax(0.0,Wg);
+ else VT[0][0] = Wg;
+ ET[0][0] = VT[0][0];
+ FT[0][0] = VT[0][0];
+
+ if (FreeTEnd)
+ for (i=1;i<=TLen;i++) {
+ V1 = RMax ( 0.0,VT[i-1][0]+Ws );
+ VT[i][0] = V1;
+ ET[i][0] = V1;
+ }
+ else
+ for (i=1;i<=TLen;i++) {
+ V1 = VT[i-1][0] + Ws;
+ VT[i][0] = V1;
+ ET[i][0] = V1;
+ }
+
+ if (FreeSEnd)
+ for (j=1;j<=SLen;j++) {
+ V1 = RMax ( 0.0,VT[0][j-1]+Ws );
+ VT[0][j] = V1;
+ FT[0][j] = V1;
+ }
+ else
+ for (j=1;j<=SLen;j++) {
+ V1 = VT[0][j-1] + Ws;
+ VT[0][j] = V1;
+ FT[0][j] = V1;
+ }
+
+ // Recurrence
+ for (i=1;i<=TLen;i++)
+ for (j=1;j<=SLen;j++) {
+ V1 = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
+ ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
+ FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
+ VT[i][j] = RMax ( RMax(V1,ET[i][j]),FT[i][j] );
+ }
+
+ FreeMatrixMemory ( ET,TLen+1,0,0 );
+ FreeMatrixMemory ( FT,TLen+1,0,0 );
+
+ // PrintVT ( S,T );
+
+ }
+
+
+ void Alignment1::BuildLATable ( ivector S, ivector T ) {
+ int i,j;
+ realtype V1;
+
+ GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
+ GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
+ GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
+
+ // Base conditions
+ VT[0][0] = RMax ( 0.0,Wg );
+ ET[0][0] = VT[0][0];
+ FT[0][0] = VT[0][0];
+ for (i=1;i<=TLen;i++) {
+ V1 = RMax ( 0.0,VT[i-1][0]+Ws );
+ VT[i][0] = V1;
+ ET[i][0] = V1;
+ }
+ for (j=1;j<=SLen;j++) {
+ V1 = RMax ( 0.0,VT[0][j-1]+Ws );
+ VT[0][j] = V1;
+ FT[0][j] = V1;
+ }
+
+ // Recurrence
+ for (i=1;i<=TLen;i++)
+ for (j=1;j<=SLen;j++) {
+ V1 = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
+ ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
+ FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
+ VT[i][j] = RMax ( RMax(V1,ET[i][j]),RMax(0.0,FT[i][j]) );
+ }
+
+ FreeMatrixMemory ( ET,TLen+1,0,0 );
+ FreeMatrixMemory ( FT,TLen+1,0,0 );
+
+ // PrintVT ( S,T );
+
+ }
+
+ void Alignment1::PrintVT ( ivector S, ivector T ) {
+ int i,j;
+ printf ( "\n " );
+ for (j=0;j<=SLen;j++)
+ printf ( " %2i",j );
+ printf ( " \n " );
+ for (j=1;j<=SLen;j++)
+ printf ( " %3i ",S[j-1] );
+ printf ( " \n\n " );
+ for (i=0;i<=TLen;i++) {
+ if (i>0) printf ( " %2i %3i ",i,T[i-1] );
+ else printf ( " %2i ",i );
+ for (j=0;j<=SLen;j++)
+ printf ( " %2i",mround(VT[i][j]) );
+ printf ( " \n " );
+ }
+ printf ( " \n" );
+ }
+
+
+ void Alignment1::Backtrace ( ivector S, ivector T, int J, int I,
+ bool StopAtZero ) {
+ int i,j,k, i1,j1, sk,tk;
+ int C;
+ realtype V,SV,TV;
+ bool Stop;
+
+ // 1. Allocate memory
+
+ FreeVectorMemory ( AlgnS,0 );
+ FreeVectorMemory ( AlgnT,0 );
+ AlgnLen = 0;
+
+ k = SLen+TLen+1;
+ GetVectorMemory ( AlgnS,k,0 );
+ GetVectorMemory ( AlgnT,k,0 );
+ for (i=0;i<k;i++) {
+ AlgnS[i] = Space;
+ AlgnT[i] = Space;
+ }
+
+ // 2. Initialize backtracing
+ i = I; // backtracing
+ j = J; // indices
+
+ k = 0; // alignment index
+ SV = 0.0; sk = -1; // alignment indices and leading elements
+ TV = 0.0; tk = -1; // for vertical and horizontal sections
+
+
+ // 3. Backtracing
+ Stop = false;
+ while ((!Stop) && (i>0) && (j>0)) {
+
+ V = VT[i][j];
+
+ // find next leading element
+ if (VT[i][j-1]>VT[i-1][j]) {
+ i1 = i; j1 = j-1;
+ } else {
+ i1 = i-1; j1 = j;
+ }
+ if (VT[i-1][j-1]>=VT[i1][j1]) {
+ i1 = i-1; j1 = j-1;
+ }
+
+ Stop = StopAtZero && (VT[i1][j1]<=0.0); // used at local alignment
+
+ // treat horizontal section
+ if ((sk<0) || (V>SV)) {
+ sk = k;
+ SV = V;
+ }
+ if ((j1!=j) || Stop) { // end of horizontal section
+ AlgnS[sk] = S[j-1];
+ sk = -1;
+ }
+
+ // treat vertical section
+ if ((tk<0) || (V>TV)) {
+ tk = k;
+ TV = V;
+ }
+ if ((i1!=i) || Stop) { // end of vertical section
+ AlgnT[tk] = T[i-1];
+ tk = -1;
+ }
+
+ i = i1;
+ j = j1;
+ k++;
+
+ }
+
+ if (!StopAtZero) {
+ // 4. Finish the last horizontal section
+ sk = k;
+ while (j>0) AlgnS[k++] = S[--j];
+ // 5. Finish the last vertical section
+ while (i>0) AlgnT[sk++] = T[--i];
+ k = IMax ( k,sk );
+ }
+
+ // 6. Put the termination character
+ AlgnLen = k;
+
+ // 7. Reverse the strings
+ i = 0;
+ j = k-1;
+ if (StopAtZero) {
+ // should work only for local alignment
+ while ((j>0) && ((AlgnS[j]==Space) || (AlgnT[j]==Space))) j--;
+ AlgnLen = j+1;
+ }
+ while (j>i) {
+ C = AlgnS[i]; AlgnS[i] = AlgnS[j]; AlgnS[j] = C;
+ C = AlgnT[i]; AlgnT[i] = AlgnT[j]; AlgnT[j] = C;
+ i++;
+ j--;
+ }
+
+ // 8. Filter out parasite spaces
+ k = 0;
+ i = 0;
+ while (k<AlgnLen) {
+ while ((k<AlgnLen) && (AlgnS[k]==Space) && (AlgnT[k]==Space)) k++;
+ if (k<AlgnLen) {
+ AlgnS[i] = AlgnS[k];
+ AlgnT[i] = AlgnT[k];
+ k++;
+ i++;
+ }
+ }
+
+ AlgnLen = i;
+
+ // 9. Collapse the alternating spaces
+ do {
+
+ k = 0;
+ i = 0;
+ while (k<AlgnLen) {
+ if ((AlgnS[k]==Space) && (AlgnT[k]==Space)) k++;
+ else if ((k+1<AlgnLen) &&
+ (AlgnS[k]==Space) && (AlgnS[k+1]!=Space) &&
+ (AlgnT[k]!=Space) && (AlgnT[k+1]==Space)) {
+ AlgnS[i] = AlgnS[k+1];
+ AlgnT[i] = AlgnT[k];
+ k++;
+ } else if ((k+1<AlgnLen) &&
+ (AlgnS[k]!=Space) && (AlgnS[k+1]==Space) &&
+ (AlgnT[k]==Space) && (AlgnT[k+1]!=Space)) {
+ AlgnS[i] = AlgnS[k];
+ AlgnT[i] = AlgnT[k+1];
+ k++;
+ } else if (i!=k) {
+ AlgnS[i] = AlgnS[k];
+ AlgnT[i] = AlgnT[k];
+ }
+ if (k<AlgnLen) {
+ k++;
+ i++;
+ }
+ }
+
+ AlgnLen = i;
+
+ } while (k>i);
+
+
+ }
+
+
+ void Alignment1::AdjustEnds ( ivector S, ivector T, int J, int I ) {
+ int is,it;
+ is = J;
+ it = I;
+ while ((is<SLen) || (it<TLen)) {
+ if (is<SLen) AlgnS[AlgnLen] = S[is];
+ else AlgnS[AlgnLen] = Space;
+ if (it<TLen) AlgnT[AlgnLen] = T[it];
+ else AlgnT[AlgnLen] = Space;
+ is++;
+ it++;
+ AlgnLen++;
+ }
+ }
+
+ realtype Alignment1::Score ( int A, int B ) {
+ if (A==B) {
+ if (A==Space) return 0.0;
+ else return SEq;
+ }
+ if ((A==Space) || (B==Space)) return Ws;
+ return SNEq;
+ }
+
+
+ realtype Alignment1::GetSimilarity() {
+ realtype s,a;
+ int i;
+
+ s = 0.0;
+ a = 0.0;
+
+ for (i=0;i<AlgnLen;i++)
+ if ((AlgnS[i]!=Space) || (AlgnT[i]!=Space)) {
+ a += RMax ( Score(AlgnS[i],AlgnS[i]),Score(AlgnT[i],AlgnT[i]) );
+ s += Score ( AlgnS[i],AlgnT[i] );
+ }
+
+ if ((s>0.0) && (a>0.0)) return s/a;
+ return 0.0;
+
+ }
+
+
+ void Alignment1::OutputResults ( io::RFile f, ivector S, int lenS,
+ ivector T, int lenT ) {
+ int k,l,n;
+ char P[10];
+
+ if ((!AlgnS) || (!AlgnT)) {
+ f.LF();
+ f.WriteLine ( pstr(" NO ALIGNMENT HAS BEEN DONE.") );
+ f.shut();
+ return;
+ }
+ f.LF();
+ f.WriteLine ( pstr(" ======== INPUT DATA") );
+ f.LF();
+ f.WriteLine ( pstr(" String S:") );
+ f.Write ( pstr(" ") );
+ l = 1;
+ k = 0;
+ while (k<lenS) {
+ sprintf ( P,"%4i ",S[k++] );
+ f.Write ( P );
+ l += 5;
+ if (l>=WrapPeriod) {
+ f.LF(); f.Write ( pstr(" ") ); l = 1;
+ }
+ }
+ f.LF();
+ f.LF();
+ f.WriteLine ( pstr(" String T:") );
+ f.Write ( pstr(" ") );
+ l = 1;
+ k = 0;
+ while (k<lenT) {
+ sprintf ( P,"%4i ",T[k++] );
+ f.Write ( P );
+ l += 5;
+ if (l>=WrapPeriod) {
+ f.LF(); f.Write ( pstr(" ") ); l = 1;
+ }
+ }
+ f.LF();
+ f.LF();
+ f.WriteParameter ( pstr(" Score equal") ,SEq ,20,10 );
+ f.WriteParameter ( pstr(" Score unequal"),SNEq,20,10 );
+ f.LF();
+ f.WriteParameter ( pstr(" Gap weight") ,Wg ,20,10 );
+ f.WriteParameter ( pstr(" Space weight") ,Ws ,20,10 );
+ f.LF();
+ f.LF();
+ f.Write ( pstr(" ======== RESULT OF ") );
+ switch (AlignKey) {
+ default :
+ case ALIGN_GLOBAL : f.Write ( pstr("GLOBAL") ); break;
+ case ALIGN_LOCAL : f.Write ( pstr("LOCAL") ); break;
+ case ALIGN_GLOBLOC : f.Write ( pstr("GLOBAL/LOCAL") ); break;
+ case ALIGN_FREEENDS : f.Write ( pstr("FREE-ENDS") );
+ }
+ f.WriteLine ( pstr(" ALIGNMENT") );
+ f.LF();
+ if (AlignKey==ALIGN_GLOBLOC) {
+ f.WriteLine ( pstr(" End gaps in T-string were not penalized") );
+ f.LF();
+ }
+ f.WriteParameter ( pstr(" Highest score achieved:"),
+ VAchieved,26,10 );
+ f.LF();
+ f.WriteLine ( pstr(" Aligned S (upper string) and T "
+ "(lower string):") );
+ f.LF();
+ k = 0;
+ n = 0;
+ l = 1; f.Write ( pstr(" ") );
+ while (k<AlgnLen) {
+ sprintf ( P,"%4i ",AlgnS[k++] );
+ f.Write ( P );
+ l += 5;
+ if ((l>=WrapPeriod) || (!AlgnS[k])) {
+ f.LF(); f.Write ( pstr(" ") ); l = 1;
+ while ((n<AlgnLen) && (l<WrapPeriod)) {
+ sprintf ( P,"%4i ",AlgnT[n++] );
+ f.Write ( P );
+ l += 5;
+ }
+ f.LF(); f.LF(); f.Write ( pstr(" ") ); l = 1;
+ }
+ }
+
+ }
+
+
+ // ----------------- Streaming -----------------------------
+
+ void Alignment1::write ( io::RFile f ) {
+ int Version=1;
+ f.WriteFile ( &Version,sizeof(Version) );
+ Stream::write ( f );
+ }
+
+ void Alignment1::read ( io::RFile f ) {
+ int Version;
+ f.ReadFile ( &Version,sizeof(Version) );
+ Stream::write ( f );
+ }
+
+
+ } // namespace math
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_math_align.h b/mmdb2/mmdb_math_align.h
new file mode 100644
index 0000000..fca7bc6
--- /dev/null
+++ b/mmdb2/mmdb_math_align.h
@@ -0,0 +1,195 @@
+// $Id: mmdb_math_align.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Align <interface>
+// ~~~~~~~~~
+// **** Classes : mmdb::math::Alignment (char strings alignment)
+// ~~~~~~~~~~~~ mmdb::math::Alignment1 (int vectors alignment)
+//
+// (C) E.Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_MATH_Align__
+#define __MMDB_MATH_Align__
+
+#include "mmdb_io_stream.h"
+
+namespace mmdb {
+
+ namespace math {
+
+ // ===================== AlignParams ======================
+
+ DefineClass(AlignParams);
+ DefineStreamFunctions(AlignParams);
+
+ class AlignParams : public io::Stream {
+
+ public :
+
+ realtype gapWeight,spaceWeight;
+ realtype equalScore,nequalScore;
+ int method;
+
+ AlignParams();
+ AlignParams ( io::RPStream Object );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ void InitAlignParams();
+
+ };
+
+
+ // ====================== Alignment =======================
+
+ DefineClass(Alignment);
+
+ enum ALIGN_METHOD {
+ ALIGN_GLOBAL = 0,
+ ALIGN_LOCAL = 1,
+ ALIGN_GLOBLOC = 2,
+ ALIGN_FREEENDS = 3
+ };
+
+ class Alignment : public io::Stream {
+
+ public :
+
+ Alignment ();
+ Alignment ( io::RPStream Object );
+ ~Alignment ();
+
+ void SetAffineModel ( realtype WGap, realtype WSpace );
+ void SetScores ( realtype SEqual, realtype SNEqual );
+
+ void Align ( cpstr S, cpstr T,
+ ALIGN_METHOD Method=ALIGN_GLOBAL );
+
+ inline pstr GetAlignedS() { return AlgnS; }
+ inline pstr GetAlignedT() { return AlgnT; }
+ inline realtype GetScore () { return VAchieved; }
+ inline char GetSpace () { return Space; }
+
+ realtype GetSimilarity(); // Score-weighted sequence id
+ realtype GetSeqId (); // Primitive sequence id
+
+ virtual void OutputResults ( io::RFile f, cpstr S, cpstr T );
+
+ void read ( io::RFile f );
+ void write ( io::RFile f );
+
+ protected :
+
+ char Space;
+ int AlignKey, SLen,TLen;
+ rmatrix VT,ET,FT;
+ pstr AlgnS,AlgnT;
+ realtype VAchieved;
+ realtype SEq,SNEq, Wg,Ws;
+
+ virtual void InitAlignment();
+ virtual void FreeMemory ();
+ virtual realtype Score ( char A, char B );
+
+ void BuildGATable ( cpstr S, cpstr T,
+ bool FreeSEnd, bool FreeTEnd );
+ void BuildLATable ( cpstr S, cpstr T );
+ void Backtrace ( cpstr S, cpstr T, int J, int I,
+ bool StopAtZero );
+ void AdjustEnds ( cpstr S, cpstr T, int J, int I );
+ void PrintVT ( cpstr S, cpstr T );
+
+ };
+
+
+
+ // ====================== Alignment1 =======================
+
+ DefineClass(Alignment1);
+
+ class Alignment1 : public io::Stream {
+
+ public :
+
+ Alignment1 ();
+ Alignment1 ( io::RPStream Object );
+ ~Alignment1();
+
+ void SetAffineModel ( realtype WGap, realtype WSpace );
+ void SetScores ( realtype SEqual, realtype SNEqual );
+
+ void Align ( ivector S, int SLength,
+ ivector T, int TLength,
+ ALIGN_METHOD Method=ALIGN_GLOBAL );
+
+ inline ivector GetAlignedS () { return AlgnS; }
+ inline ivector GetAlignedT () { return AlgnT; }
+ inline int GetAlignLength() { return AlgnLen; }
+ inline realtype GetScore () { return VAchieved; }
+
+ realtype GetSimilarity(); // Score-weighted sequence id
+
+ virtual void OutputResults ( io::RFile f, ivector S, int lenS,
+ ivector T, int lenT );
+
+ void read ( io::RFile f );
+ void write ( io::RFile f );
+
+ protected :
+
+ int Space;
+ int AlignKey, SLen,TLen, AlgnLen;
+ rmatrix VT,ET,FT;
+ ivector AlgnS,AlgnT;
+ realtype VAchieved;
+ realtype SEq,SNEq, Wg,Ws;
+
+ virtual void InitAlignment1();
+ virtual void FreeMemory ();
+ virtual realtype Score ( int A, int B );
+
+ void BuildGATable ( ivector S, ivector T,
+ bool FreeSEnds, bool FreeTEnds );
+ void BuildLATable ( ivector S, ivector T );
+ void Backtrace ( ivector S, ivector T, int J, int I,
+ bool StopAtZero );
+ void AdjustEnds ( ivector S, ivector T, int J, int I );
+ void PrintVT ( ivector S, ivector T );
+
+ };
+
+ } // namespace math
+
+} // namespace mmdb
+
+#endif
diff --git a/mmdb2/mmdb_math_bfgsmin.cpp b/mmdb2/mmdb_math_bfgsmin.cpp
new file mode 100644
index 0000000..989608a
--- /dev/null
+++ b/mmdb2/mmdb_math_bfgsmin.cpp
@@ -0,0 +1,938 @@
+// $Id: mmdb_math_bfgsmin.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : BFGSMin <implementation>
+// ~~~~~~~~~
+// **** Classes : mmdb::math::BFGSMin ( minimization driver )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <math.h>
+
+#include "mmdb_math_bfgsmin.h"
+
+namespace mmdb {
+
+ namespace math {
+
+ // ==============================================================
+
+ BFGSMin::BFGSMin() {
+
+ MFunc = NULL;
+ MFuncData = NULL;
+ PFunc = NULL;
+ PFuncData = NULL;
+
+ N = 0;
+ NAlloc = 0;
+
+ Hsn = NULL;
+ TL = NULL;
+ LL = NULL;
+ XOpt = NULL;
+ XPlus = NULL;
+ Sx = NULL;
+ SN = NULL;
+ HDiag = NULL;
+ GradX = NULL;
+ GPlus = NULL;
+ StepSize = NULL;
+ FNeighbor = NULL;
+ us = NULL;
+ uy = NULL;
+ ut = NULL;
+ Freese = NULL;
+ Func = 0.0;
+ FPlus = 0.0;
+ FOpt = 0.0;
+ TakenLambda = 0.0;
+ ForDiff = false;
+ CalcHess = false;
+
+ Etha = 0.0;
+ SqrtEtha = 0.0;
+ CubertEtha = 0.0;
+ TpF = 1.0;
+ GrdEps = 0.0;
+ StpEps = 0.0;
+ MxStep = MaxReal;
+ CnsMax = 0;
+ MaxItn = 100;
+ TermCode = BFGS_NoTermination;
+ ModF = false;
+
+ }
+
+ BFGSMin::~BFGSMin() {
+ FreeMemory();
+ }
+
+ void BFGSMin::MinFunc ( rvector X, realtype & F ) {
+ if (MFunc) (*MFunc)(MFuncData,N,X,F);
+ else F = 0.0;
+ }
+
+ void BFGSMin::MinFunc1 ( rvector X, realtype & F ) {
+ int i;
+ MinFunc ( X,F );
+ if (ModF && (F<FOpt)) {
+ for (i=1;i<=N;i++)
+ XOpt[i] = X[i];
+ FOpt = F;
+ }
+ }
+
+ void BFGSMin::Print ( int Itn, rvector X, rvector G, realtype F ) {
+ if (PFunc) (*PFunc)(PFuncData,N,Itn,X,G,F);
+ }
+
+ void BFGSMin::SetMinFunction ( void * UserData, PBFGSMinFunc Fnc ) {
+ MFuncData = UserData;
+ MFunc = Fnc;
+ }
+
+ void BFGSMin::SetPrintFunction ( void * UserData, PBFGSPrintFunc Fnc ) {
+ PFuncData = UserData;
+ PFunc = Fnc;
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::UMInCk ( rvector x0, rvector TypX,
+ int Digits, realtype TypF,
+ realtype GrdTol, realtype StpTol,
+ realtype MaxStp, int ItnLmt ) {
+ int i;
+ realtype S0,S1,S2;
+
+ SqrtEps = sqrt(MachEps);
+
+ if (N<1) {
+ TermCode = BFGS_WrongSpaceDim;
+ return;
+ }
+
+ for (i=1;i<=N;i++)
+ if (fabs(TypX[i])!=0.0) Sx[i] = 1.0/fabs(TypX[i]);
+ else Sx[i] = 1.0;
+
+ if (Digits<=0) Etha = MachEps;
+ else {
+ Etha = Exp((-Digits)*log(10.0));
+ if (MachEps>Etha) Etha = MachEps;
+ }
+ SqrtEtha = sqrt(Etha);
+ CubertEtha = Exp ( log(Etha)/3.0 );
+
+ if (Etha>0.01) {
+ TermCode = BFGS_TooFewDigits;
+ return;
+ }
+
+ if (TypF<=0.0) TpF = 1.0;
+ else TpF = TypF;
+
+ S1 = Exp(log(MachEps)/3.0);
+ if (GrdTol>0.0) GrdEps = GrdTol;
+ else {
+ GrdEps = sqrt(Etha);
+ if (S1>GrdEps) GrdEps = S1;
+ }
+
+ if (StpTol>0.0) StpEps = StpTol;
+ else StpEps = Exp ( log(MachEps)*2.0/3.0 );
+
+ if (MaxStp>0.0) MxStep = MaxStp;
+ else {
+ S1 = 0.0;
+ S2 = 0.0;
+ for (i=1;i<=N;i++) {
+ S0 = Sx[i];
+ S0 *= Sx[i];
+ S2 += S0;
+ S0 *= x0[i];
+ S1 += S0*x0[i];
+ }
+ S1 = sqrt(S1);
+ S2 = sqrt(S2);
+ if (S2>S1) MxStep = S2;
+ else MxStep = S1;
+ MxStep *= 1000.0;
+ }
+
+ if (ItnLmt>0) MaxItn = ItnLmt;
+ else MaxItn = 100;
+
+ TermCode = BFGS_NoTermination;
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::UMStop0 ( rvector x0, rvector Grad ) {
+ int i;
+ realtype S,Fmax,St;
+
+ CnsMax = 0;
+ if (TpF>fabs(Func)) Fmax = TpF;
+ else Fmax = fabs(Func);
+ S = 0.0;
+ for (i=1;i<=N;i++) {
+ St = fabs(x0[i]);
+ if (1.0/Sx[i]>St) St = 1.0/Sx[i];
+ St = fabs(Grad[i])*St/Fmax;
+ if (St>S) S = St;
+ }
+ if (S>=0.001*GrdEps) TermCode = BFGS_NoTermination;
+ else TermCode = BFGS_SmallGradient;
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::UMStop ( rvector x0, rvector Grad,
+ int RetCode, int ItnCnt,
+ bool MaxTkn ) {
+
+ // A7.2.1 : Checking the Stop Conditions
+
+ int i;
+ realtype Max1,Max2,MaxGrad,MaxStep, BB1,BB2;
+
+ TermCode = BFGS_NoTermination;
+ if (RetCode==1) TermCode = BFGS_LineSearchComplete;
+ else {
+ if (fabs(FPlus)>TpF) Max2 = fabs(FPlus);
+ else Max2 = TpF;
+ MaxGrad = 0.0;
+ MaxStep = 0.0;
+ for (i=1;i<=N;i++) {
+ BB1 = fabs(XPlus[i]);
+ BB2 = 1.0/Sx[i];
+ if (BB1>BB2) Max1 = BB1;
+ else Max1 = BB2;
+ BB1 = fabs(Grad[i])*Max1/Max2;
+ if (BB1>MaxGrad) MaxGrad = BB1;
+ BB2 = fabs(XPlus[i]-x0[i])/Max1;
+ if (BB2>MaxStep) MaxStep = BB2;
+ }
+ if (MaxGrad<GrdEps) TermCode = BFGS_SmallGradient;
+ else if (MaxStep<StpEps) TermCode = BFGS_SmallStep;
+ else if (ItnCnt>MaxItn) TermCode = BFGS_IterationLimit;
+ else if (MaxTkn) {
+ CnsMax++;
+ if (CnsMax==5) TermCode = BFGS_LargeSteps;
+ } else
+ CnsMax = 0;
+ }
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::MdHess ( rmatrix H, rvector HDg ) {
+
+ // A5.5.1 : Setting up the hessian of model
+
+ int i,j;
+ realtype MaxDiag,MaxOff, MinEv,Mue,MaxPosDiag;
+ realtype MaxOffl,MinDiag,MaxEv,MaxAdd,Sdd,OffRow;
+ realtype BB;
+
+ // Scaling
+ for (i=1;i<=N;i++)
+ for (j=i;j<=N;j++)
+ H[i][j] /= (Sx[i]*Sx[j]);
+
+ MaxDiag = H[1][1];
+ MinDiag = H[1][1];
+ MaxOff = 0.0;
+ for (i=1;i<=N;i++) {
+ if (H[i][i]>MaxDiag) MaxDiag = H[i][i];
+ if (H[i][i]<MinDiag) MinDiag = H[i][i];
+ if (i<N)
+ for (j=i+1;j<=N;j++) {
+ BB = fabs(H[i][j]);
+ if (BB>MaxOff) MaxOff = BB;
+ }
+ }
+ MaxPosDiag = 0.0;
+ if (MaxDiag>MaxPosDiag) MaxPosDiag = MaxDiag;
+
+ // Computing the shift of the spectra (the Mue)
+ if (MinDiag>SqrtEps*MaxPosDiag) Mue = 0.0;
+ else {
+ Mue = 2.0*(MaxPosDiag-MinDiag)*SqrtEps-MinDiag;
+ MaxDiag += Mue;
+ }
+ BB = MaxOff*(1.0+2.0*SqrtEps);
+ if (BB>MaxDiag) {
+ Mue = Mue+(MaxOff-MaxDiag)+2.0*SqrtEps*MaxOff;
+ MaxDiag = BB;
+ }
+ if (MaxDiag==0.0) { // H = 0
+ Mue = 1.0;
+ MaxDiag = 1.0;
+ }
+ if (Mue>0.0)
+ for (i=1;i<=N;i++)
+ Hsn[i][i] += Mue;
+
+ MaxOffl = MaxOff/N;
+ if (MaxDiag>MaxOffl) MaxOffl = MaxDiag;
+ MaxOffl = sqrt(MaxOffl);
+ for (i=1;i<=N;i++)
+ HDg[i] = H[i][i];
+
+ PbCholDecomp ( N,HDg,MaxOffl,MachEps,H,MaxAdd );
+
+ if (MaxAdd>0.0) {
+ MaxEv = HDg[1];
+ MinEv = HDg[1];
+ for (i=1;i<=N;i++) {
+ OffRow = 0.0;
+ if (i>1)
+ for (j=1;j<i;j++)
+ OffRow += fabs(H[j][i]);
+ if (i<N)
+ for (j=i+1;j<=N;j++)
+ OffRow += fabs(H[i][j]);
+ BB = HDg[i]+OffRow;
+ if (BB>MaxEv) MaxEv = BB;
+ BB = HDg[i]-OffRow;
+ if (BB<MinEv) MinEv = BB;
+ }
+ Sdd = (MaxEv-MinEv)*SqrtEps-MinEv;
+ if (Sdd<0.0) Sdd = 0.0;
+ if (MaxAdd<Sdd) Mue = MaxAdd;
+ else Mue = Sdd;
+ for (i=1;i<=N;i++)
+ HDg[i] += Mue;
+
+ PbCholDecomp ( N,HDg,0.0,MachEps,H,MaxAdd );
+
+ }
+
+ // Scaling back
+ for (i=1;i<=N;i++) {
+ if (i<N)
+ for (j=i+1;j<=N;j++)
+ H[i][j] *= (Sx[i]*Sx[j]);
+ HDg[i] *= Sx[i]*Sx[i];
+ for (j=1;j<=i;j++)
+ H[i][j] *= Sx[i];
+ }
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::FDGrad ( rvector X, rvector G, realtype Fc ) {
+
+ // A5.6.4 : Forward Finite-Differencies Approximation of
+ // the Gradient
+
+ realtype StepSizeJ,TempJ,Fj, BB1,BB2;
+ int j;
+
+ for (j=1;j<=N;j++) {
+ BB1 = fabs(X[j]);
+ BB2 = 1.0/Sx[j];
+ if (BB1>BB2) StepSizeJ = BB1;
+ else StepSizeJ = BB2;
+ if (X[j]<0.0) StepSizeJ = -StepSizeJ;
+ StepSizeJ *= SqrtEtha;
+ TempJ = X[j];
+ X[j] += StepSizeJ;
+ StepSizeJ = X[j]-TempJ;
+ MinFunc1 ( X,Fj );
+ if (TermCode!=BFGS_NoTermination) return;
+ G[j] = (Fj-Fc)/StepSizeJ;
+ X[j] = TempJ;
+ Freese[j] = false;
+ if (TL) {
+ if ((fabs(X[j]-TL[j])<=StepSizeJ) && (G[j]<0.0)) {
+ G[j] = 0.0; Freese[j] = true;
+ }
+ }
+ if (LL) {
+ if ((fabs(X[j]-LL[j])<=StepSizeJ) && (G[j]>0.0)) {
+ G[j] = 0.0; Freese[j] = true;
+ }
+ }
+ }
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::CDGrad ( rvector X, rvector G ) {
+
+ // A5.6.4 : Central Differencies Approximation of
+ // Gradient
+
+ realtype StepSizeJ,TempJ,Fp,Fm, BB1,BB2;
+ int j;
+
+ for (j=1;j<=N;j++) {
+ BB1 = fabs(X[j]);
+ BB2 = 1.0/Sx[j];
+ if (BB1>BB2) StepSizeJ = BB1;
+ else StepSizeJ = BB2;
+ if (X[j]<0.0) StepSizeJ = -StepSizeJ;
+ StepSizeJ *= CubertEtha;
+ TempJ = X[j];
+ X[j] += StepSizeJ;
+ StepSizeJ = X[j]-TempJ;
+ MinFunc1 ( X,Fp );
+ if (TermCode!=BFGS_NoTermination) return;
+ X[j] = TempJ-StepSizeJ;
+ MinFunc1 ( X,Fm );
+ if (TermCode!=BFGS_NoTermination) return;
+ G[j] = (Fp-Fm)/(2.0*StepSizeJ);
+ X[j] = TempJ;
+ }
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::Gradient ( rvector X, rvector G, realtype Fc ) {
+ if (ForDiff) FDGrad ( X,G,Fc );
+ else CDGrad ( X,G );
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::FDHessF ( realtype Fc, rvector X ) {
+
+ // A5.6.2 : Finite-Difference Approximation of
+ // the Hessian employing only the
+ // function's values
+
+ int i,j;
+ realtype S,TempI,Fii,TempJ,Fij, BB1,BB2;
+
+
+ for (i=1;i<=N;i++)
+ if (!Freese[i]) {
+ BB1 = fabs(X[i]);
+ BB2 = 1.0/Sx[i];
+ if (BB1>BB2) S = BB1;
+ else S = BB2;
+ if (X[i]<0.0) S = -S;
+ StepSize[i] = S*CubertEtha;
+ TempI = X[i];
+ X[i] += StepSize[i];
+ StepSize[i] = X[i]-TempI;
+ MinFunc1 ( X,FNeighbor[i] );
+ X[i] = TempI;
+ if (TermCode!=BFGS_NoTermination) return;
+ }
+ for (i=1;i<=N;i++)
+ if (!Freese[i]) {
+ TempI = X[i];
+ X[i] += 2.0*StepSize[i];
+ MinFunc1 ( X,Fii );
+ if (TermCode!=BFGS_NoTermination) return;
+ Hsn[i][i] = (( Fc -FNeighbor[i] ) +
+ ( Fii-FNeighbor[i] )) /
+ (StepSize[i]*StepSize[i]);
+ X[i] = TempI+StepSize[i];
+ if (i<N)
+ for (j=i+1;j<=N;j++)
+ if (!Freese[j]) {
+ TempJ = X[j];
+ X[j] += StepSize[j];
+ MinFunc1 ( X,Fij );
+ if (TermCode!=BFGS_NoTermination) return;
+ Hsn[i][j] = (( Fc -FNeighbor[i] ) +
+ ( Fij-FNeighbor[j] )) /
+ (StepSize[i]*StepSize[j]);
+ X[j] = TempJ;
+ } else
+ Hsn[i][j] = 0.0;
+ X[i] = TempI;
+ } else
+ for (j=i;j<=N;j++)
+ Hsn[i][j] = 0.0;
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::InitHessUnFac ( realtype F, rmatrix H ) {
+
+ // A9.4.3 - Initialization of the unfactorized BFGS
+
+ realtype Temp;
+ int i,j;
+
+ Temp = fabs(F);
+ if (TpF>Temp) Temp = TpF;
+ for (i=1;i<=N;i++) {
+ H[i][i] = Temp*Sx[i]*Sx[i];
+ if (i<N)
+ for (j=i+1;j<=N;j++)
+ H[i][j] = 0.0;
+ }
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::BFGSUnFac ( rvector Xc, rvector Xp,
+ rvector Gc, rvector Gp,
+ bool AnalGrad, rvector HDg,
+ rmatrix H ) {
+
+ // A9.4.1 - Calculation of the Hessian by the
+ // unfactorized BFGS
+
+ int i,j;
+ realtype Temp1,Temp2, NormS,NormY,Tol,tt, BB;
+ bool SkipUpdate;
+
+ Temp1 = 0.0;
+ NormS = 0.0;
+ NormY = 0.0;
+ for (i=1;i<=N;i++) {
+ H[i][i] = HDg[i];
+ us[i] = Xp[i] - Xc[i];
+ uy[i] = Gp[i] - Gc[i];
+ Temp1 += us[i]*uy[i];
+ NormS += us[i]*us[i];
+ NormY += uy[i]*uy[i];
+ }
+
+ if (Temp1>sqrt(MachEps*NormS*NormY)) {
+ if (AnalGrad) Tol = Etha;
+ else Tol = sqrt(Etha);
+ SkipUpdate = true;
+ for (i=1;i<=N;i++) {
+ tt = 0.0;
+ for (j=1;j<=i;j++)
+ tt += H[j][i]*us[j];
+ if (i<N)
+ for (j=i+1;j<=N;j++)
+ tt += H[i][j]*us[j];
+ ut[i] = tt;
+ tt = fabs(Gc[i]);
+ BB = fabs(Gp[i]);
+ if (BB>tt) tt = BB;
+ if (fabs(uy[i]-ut[i])>=Tol*tt)
+ SkipUpdate = false;
+ }
+
+ if (!SkipUpdate) {
+ Temp2 = 0.0;
+ for (i=1;i<=N;i++)
+ Temp2 += us[i]*ut[i];
+ for (i=1;i<=N;i++)
+ for (j=i;j<=N;j++)
+ H[i][j] += uy[i]*uy[j]/Temp1 -
+ ut[i]*ut[j]/Temp2;
+ }
+
+ }
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::Choose_Lambda ( rvector X, rvector S,
+ realtype & Lambda0 ) {
+ int i;
+ realtype SS;
+
+ for (i=1;i<=N;i++)
+ if ((S[i]!=0.0) && (!Freese[i])) {
+ SS = X[i] + Lambda0*S[i];
+ if (TL) {
+ if (SS>TL[i]) Lambda0 = (TL[i]-X[i])/S[i]/(1.0+MachEps);
+ }
+ if (LL) {
+ if (SS<LL[i]) Lambda0 = (LL[i]-X[i])/S[i]/(1.0+MachEps);
+ }
+ } else if (Freese[i]) S[i] = 0.0;
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::Stop() {
+ TermCode = BFGS_Stopped;
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::LineSearch ( rvector px0, rvector G,
+ rvector P, realtype pFunc,
+ int & RetCode, bool & MaxTkn ) {
+
+ // A6.3.1 : Linear Search
+
+ int i;
+ realtype Alpha, NewtLn, S, InitSp, RelLng, MinLam;
+ realtype Lambda,LamTem, LamPre, FplPre, A, B;
+ realtype Disc, B1, B2, Lambda0;
+
+ LamPre = 1.0; // only to keep compiler happy
+ FplPre = 1.0; // only to keep compiler happy
+
+ MaxTkn = false;
+ RetCode = 2;
+ Alpha = 1.0e-4;
+ NewtLn = 0.0;
+ for (i=1;i<=N;i++) { // calculate Newtonian step along the -gradient
+ B1 = Sx[i]*P[i];
+ NewtLn += B1*B1;
+ }
+ NewtLn = sqrt(NewtLn);
+
+ if (NewtLn>MxStep) { // restrict Newtonian step to MxStep
+ S = MxStep/NewtLn;
+ for (i=1;i<=N;i++)
+ P[i] *= S;
+ NewtLn = MxStep;
+ }
+
+ InitSp = 0.0;
+ RelLng = 0.0;
+ Lambda0 = 1.0;
+ Choose_Lambda ( px0,P,Lambda0 );
+ for (i=1;i<=N;i++) {
+ InitSp += G[i]*P[i];
+ B1 = fabs(px0[i]);
+ B2 = 1.0/Sx[i];
+ if (B1>B2) S = B1;
+ else S = B2;
+ S = fabs(P[i])/S;
+ if (S>RelLng) RelLng = S;
+ }
+ InitSp *= Lambda0;
+
+ MinLam = StpEps/RelLng;
+ Lambda = Lambda0;
+ do {
+ for (i=1;i<=N;i++)
+ XPlus[i] = px0[i] + Lambda*P[i];
+
+ MinFunc1 ( XPlus,FPlus );
+ if (TermCode!=BFGS_NoTermination) return;
+ if (FPlus<=pFunc+Alpha*Lambda*InitSp) {
+ RetCode = 0;
+ MaxTkn = (Lambda==Lambda0) && (NewtLn>0.99*MxStep);
+ } else if (Lambda<MinLam) {
+ RetCode = 1;
+ for (i=1;i<=N;i++)
+ XPlus[i] = px0[i];
+ } else if (Lambda==Lambda0) {
+ LamTem = -InitSp/(2.0*(FPlus-pFunc-InitSp));
+ LamTem = LamTem*Lambda;
+ LamPre = Lambda;
+ FplPre = FPlus;
+ if (LamTem>0.1*Lambda) Lambda = LamTem;
+ else {
+ Lambda *= 0.1;
+ Lambda0 = Lambda;
+ }
+ if (Lambda>Lambda0) {
+ Lambda = Lambda0;
+ RetCode = 0;
+ for (i=1;i<=N;i++)
+ XPlus[i] = px0[i] + Lambda*P[i];
+ }
+ } else {
+ B1 = FPlus - pFunc - Lambda*InitSp;
+ B2 = FplPre - pFunc - LamPre*InitSp;
+ A = ( B1/(Lambda*Lambda) - B2/(LamPre*LamPre) ) /
+ ( Lambda - LamPre );
+ B = ( -LamPre*B1/(Lambda*Lambda) +
+ Lambda*B2/(LamPre*LamPre) ) /
+ ( Lambda - LamPre );
+ Disc = B*B - 3.0*A*InitSp;
+ if (A==0.0) LamTem = -InitSp/(2.0*B);
+ else LamTem = (-B+sqrt(RMax(Disc,0.0)))/(3.0*A);
+ B1 = 0.5*Lambda;
+ if (B1<LamTem) LamTem = B1;
+ LamPre = Lambda;
+ FplPre = FPlus;
+ if (LamTem>0.1*Lambda) Lambda = LamTem;
+ else {
+ Lambda *= 0.1;
+ Lambda0 = Lambda;
+ }
+ if (Lambda>Lambda0) {
+ Lambda = Lambda0;
+ RetCode = 0;
+ for (i=1;i<=N;i++)
+ XPlus[i] = px0[i] + Lambda*P[i];
+ }
+ }
+
+ } while (RetCode>=2);
+
+ TakenLambda = Lambda;
+
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::GetMemory() {
+ if (N!=NAlloc) {
+ FreeMemory();
+ GetMatrixMemory ( Hsn , N,N, 1,1 );
+ GetVectorMemory ( GPlus , N, 1 );
+ GetVectorMemory ( GradX , N, 1 );
+ GetVectorMemory ( HDiag , N, 1 );
+ GetVectorMemory ( SN , N, 1 );
+ GetVectorMemory ( Sx , N, 1 );
+ GetVectorMemory ( XPlus , N, 1 );
+ GetVectorMemory ( XOpt , N, 1 );
+ GetVectorMemory ( Freese, N, 1 );
+ if (CalcHess) {
+ GetVectorMemory ( StepSize , N, 1 );
+ GetVectorMemory ( FNeighbor, N, 1 );
+ } else {
+ GetVectorMemory ( us , N, 1 );
+ GetVectorMemory ( uy , N, 1 );
+ GetVectorMemory ( ut , N, 1 );
+ }
+ NAlloc = N;
+ }
+ }
+
+ void BFGSMin::FreeMemory() {
+ if (NAlloc>0) {
+ FreeVectorMemory ( us , 1 );
+ FreeVectorMemory ( uy , 1 );
+ FreeVectorMemory ( ut , 1 );
+ FreeVectorMemory ( Freese , 1 );
+ FreeVectorMemory ( StepSize , 1 );
+ FreeVectorMemory ( FNeighbor, 1 );
+ FreeVectorMemory ( XOpt , 1 );
+ FreeVectorMemory ( XPlus , 1 );
+ FreeVectorMemory ( Sx , 1 );
+ FreeVectorMemory ( SN , 1 );
+ FreeVectorMemory ( HDiag , 1 );
+ FreeVectorMemory ( GradX , 1 );
+ FreeVectorMemory ( GPlus , 1 );
+ FreeMatrixMemory ( Hsn , NAlloc, 1,1 );
+ }
+ NAlloc = 0;
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::Relax() {
+ int i;
+ if (FPlus>FOpt) {
+ for (i=1;i<=N;i++)
+ XPlus[i] = XOpt[i];
+ FPlus = FOpt;
+ } else {
+ for (i=1;i<=N;i++)
+ XOpt[i] = XPlus[i];
+ FOpt = FPlus;
+ }
+ }
+
+ void BFGSMin::CopyPlus ( rvector x0 ) {
+ int i;
+ for (i=1;i<=N;i++) {
+ x0 [i] = XPlus[i];
+ GradX[i] = GPlus[i];
+ }
+ Func = FPlus;
+ }
+
+
+ // -------------------------------------------------------------------
+
+ void BFGSMin::BFGS_Driver ( int MinN,
+ rvector x0,
+ rvector TypX,
+ realtype & FuncValue,
+ int & TerminationCode,
+ int Digits,
+ int ItnLmt,
+ realtype TypF,
+ realtype GrdTol,
+ realtype StpTol,
+ realtype MaxStp,
+ bool Hess,
+ rvector LowLimit,
+ rvector TopLimit ) {
+
+ // D6.1.1 : Unconstrained Minimization Driver
+
+ int i,RetCode;
+ int ItnCnt;
+ bool MaxTkn;
+
+ TL = TopLimit;
+ LL = LowLimit;
+ ForDiff = true;
+ N = MinN;
+ CalcHess = Hess;
+
+ ModF = false;
+
+ GetMemory();
+
+ UMInCk ( x0,TypX,Digits,TypF,
+ GrdTol,StpTol,MaxStp,
+ ItnLmt );
+ if (TermCode!=BFGS_NoTermination) {
+ FreeMemory();
+ FuncValue = Func;
+ TerminationCode = TermCode;
+ return;
+ }
+
+ ItnCnt = 0;
+
+ MinFunc1 ( x0,Func );
+ if (TermCode!=BFGS_NoTermination) {
+ FreeMemory();
+ FuncValue = Func;
+ TerminationCode = TermCode;
+ return;
+ }
+ FOpt = Func;
+ FPlus = Func;
+ for (i=1;i<=N;i++) {
+ XOpt [i] = x0[i];
+ XPlus[i] = x0[i];
+ }
+ ModF = true;
+ Gradient ( x0,GradX,Func );
+ Print ( ItnCnt,x0,GradX,Func );
+ for (i=1;i<=N;i++)
+ GPlus[i] = GradX[i];
+ if (TermCode!=BFGS_NoTermination) {
+ Relax ();
+ CopyPlus ( x0 );
+ FreeMemory();
+ FuncValue = Func;
+ TerminationCode = TermCode;
+ return;
+ }
+
+ UMStop0 ( x0,GradX );
+ if (TermCode!=BFGS_NoTermination) {
+ FreeMemory();
+ FuncValue = Func;
+ TerminationCode = TermCode;
+ return;
+ }
+
+ if (!CalcHess) InitHessUnFac ( Func,Hsn );
+
+ RetCode = 0;
+ while (TermCode==BFGS_NoTermination) {
+ ItnCnt++;
+ if (RetCode>=0) {
+ if (CalcHess) {
+ FDHessF ( Func,x0 );
+ if (TermCode!=BFGS_NoTermination) {
+ Relax ();
+ CopyPlus ( x0 );
+ FreeMemory();
+ FuncValue = Func;
+ TerminationCode = TermCode;
+ return;
+ }
+ }
+ MdHess ( Hsn,HDiag );
+ }
+ ChSolve ( N,Hsn,GradX,SN );
+ LineSearch ( x0,GradX,SN,Func,RetCode,MaxTkn );
+ if ((RetCode==1) && ForDiff) {
+ RetCode = -1;
+ ForDiff = false;
+ } else
+ Relax();
+ if (TermCode!=BFGS_NoTermination) {
+ Relax ();
+ CopyPlus ( x0 );
+ FreeMemory();
+ FuncValue = Func;
+ TerminationCode = TermCode;
+ return;
+ } else
+ Gradient ( XPlus,GPlus,FPlus );
+ if (TermCode!=BFGS_NoTermination) {
+ Relax ();
+ CopyPlus ( x0 );
+ FreeMemory();
+ FuncValue = Func;
+ TerminationCode = TermCode;
+ return;
+ }
+ if (RetCode>=0) {
+ UMStop ( x0,GPlus,RetCode,ItnCnt,MaxTkn );
+ if ((!CalcHess) && (TermCode==BFGS_NoTermination))
+ BFGSUnFac ( x0,XPlus,GradX,GPlus,false,HDiag,Hsn );
+ }
+ CopyPlus ( x0 );
+ Print ( ItnCnt, x0,GradX,Func );
+ }
+
+ Relax ();
+ FreeMemory();
+ FuncValue = Func;
+ TerminationCode = TermCode;
+
+ }
+
+ } // namespace math
+
+} // namespace mmdb
+
diff --git a/mmdb2/mmdb_math_bfgsmin.h b/mmdb2/mmdb_math_bfgsmin.h
new file mode 100644
index 0000000..389ebe4
--- /dev/null
+++ b/mmdb2/mmdb_math_bfgsmin.h
@@ -0,0 +1,260 @@
+// $Id: mmdb_math_bfgsmin.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : BFGSMin <interface>
+// ~~~~~~~~~
+// **** Classes : mmdb::math::BFGSMin ( minimization driver )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_MATH_BFGSMin__
+#define __MMDB_MATH_BFGSMin__
+
+#include <stdlib.h>
+
+#include "mmdb_mattype.h"
+#include "mmdb_math_linalg.h"
+
+
+namespace mmdb {
+
+ namespace math {
+
+ // ==============================================================
+
+ enum BFGS_RC {
+ BFGS_TooFewDigits = -2,
+ BFGS_WrongSpaceDim = -1,
+ BFGS_NoTermination = 0,
+ BFGS_SmallGradient = 1,
+ BFGS_SmallStep = 2,
+ BFGS_LineSearchComplete = 3,
+ BFGS_IterationLimit = 4,
+ BFGS_LargeSteps = 5,
+ BFGS_Stopped = 6
+ };
+
+ typedef void BFGSMinFunc ( void * UserData, int N, rvector X,
+ realtype & F );
+ typedef BFGSMinFunc * PBFGSMinFunc;
+
+ typedef void BFGSPrintFunc ( void * UserData, int N, int Itn,
+ rvector X, rvector G, realtype F );
+ typedef BFGSPrintFunc * PBFGSPrintFunc;
+
+ DefineClass(BFGSMin);
+
+ class BFGSMin {
+
+ public :
+
+ BFGSMin ();
+ virtual ~BFGSMin();
+
+ virtual void MinFunc ( rvector X, realtype & F );
+ virtual void Print ( int Itn, rvector X, rvector G,
+ realtype F );
+
+ void SetMinFunction ( void * UserData, PBFGSMinFunc Fnc );
+ void SetPrintFunction ( void * UserData, PBFGSPrintFunc Fnc );
+
+
+ // ======================================================
+ //
+ // .--------------------------------------------.
+ // | |
+ // | UNCONSTRAINED MINIMIZATION DRIVER |
+ // | |
+ // `--------------------------------------------'
+ //
+ // Finds a minimum of function F(X), X is vector [1..N],
+ // defined by virtual MinFunc. Virtual Print provides
+ // information on every iteration step.
+ //
+ //
+ // Input parameters :
+ // -----------------------
+ //
+ // N is the dimension the minimization space
+ //
+ // x0 [1..N] is the initial point for minimization
+ //
+ // TypX [1..N] is the array of the typical ranges of
+ // X - components, which are used for the scaling.
+ // If TypX<=0.0 then 1.0 will be substituted
+ //
+ // Digits is the number of valid decimal digits in
+ // the calculated value of minimizing function ( F ).
+ // If Digits<=0 then the Driver will consider
+ // that the F is computed with usual machine's
+ // noise
+ //
+ // ItnLmt is the maximum available number of iterations.
+ // If ItnLmt=0 then 100 will be substituted
+ //
+ // TypF is the expected absolute value of F in the
+ // minimum, which is used in the stop criterion.
+ // If TypF<=0.0 then 1.0 will be substituted
+ //
+ // GrdTol is the desired absolute value of the gradient
+ // vector in the minimum of F . If GrdTol<=0.0
+ // then the some value correlated with machine's
+ // noise will be substituted
+ //
+ // StpTol is the minimum available step for the minimi-
+ // zation. The execution stops if the distance
+ // between two consequential approximation will be
+ // less then StpTol . If StpTol<=0.0 then the
+ // some value correlated with machine's noise
+ // will be substituted
+ //
+ // MaxStp is the maximum available step for then minimi-
+ // zation. This parameter only prevents the appea-
+ // rance of the too large steps, but the execution
+ // stops if more than 5 steps with length of MaxStep
+ // will consequently appear.
+ //
+ //
+ //
+ // Outpute parameters :
+ // --------------------------
+ //
+ // x0 will be the point at which the minimisation
+ // had stopped
+ //
+ // Func will be the function's value at x0
+ //
+ // TermCode will be the reason of stopping :
+ //
+ // 1 <=> the norm of gradient vector at x0 is
+ // less than GrdTol ; the x0 is probable
+ // point of the minimum
+ // 2 <=> the distance between two last approxima-
+ // tions was less than StpTol ; the x0
+ // may be the point of minimum
+ // 3 <=> the gradient length is greater than
+ // GrdTol , but future minimization fails ;
+ // it may be the consequence of the errors
+ // at the computing of gradient, but also
+ // x0 could be the point of minimum
+ // 4 <=> the iteration limit had been exchausted
+ // 5 <=> more than 5 steps with length of
+ // MaxStp had been made
+ // 6 <=> the termination key ( Esc or End )
+ // had been pressed.
+ //
+ //
+ // ========================================================
+
+ void BFGS_Driver ( int MinN,
+ rvector x0,
+ rvector TypX,
+ realtype & FuncValue,
+ int & TerminationCode,
+ int Digits = 0,
+ int ItnLmt = 0,
+ realtype TypF = 0.0,
+ realtype GrdTol = 0.0,
+ realtype StpTol = 0.0,
+ realtype MaxStp = MaxReal,
+ bool Hess = false,
+ rvector LowLimit = NULL,
+ rvector TopLimit = NULL );
+
+ void Stop(); // generates stop signal to stop optimization
+
+
+ protected :
+
+ PBFGSMinFunc MFunc;
+ void * MFuncData;
+ PBFGSPrintFunc PFunc;
+ void * PFuncData;
+
+ int N,NAlloc;
+ rmatrix Hsn;
+ rvector TL,LL,XOpt,XPlus,Sx,SN,HDiag,GradX,GPlus;
+ rvector StepSize,FNeighbor;
+ rvector us,uy,ut;
+ bvector Freese;
+ realtype Func,FPlus,FOpt;
+ realtype TakenLambda;
+ bool ForDiff; // if True then forward differences are
+ // used for the 1st estimation of the
+ // Hessian (which is less expensive),
+ // otherwise central differences will
+ // be employed (which is more expensive).
+ bool CalcHess;
+
+ realtype Etha,SqrtEtha,CubertEtha,TpF,GrdEps,StpEps,MxStep;
+ realtype SqrtEps;
+ int CnsMax,MaxItn,TermCode;
+ bool ModF;
+
+ void MinFunc1 ( rvector X, realtype & F );
+ void UMInCk ( rvector x0, rvector TypX,
+ int Digits, realtype TypF,
+ realtype GrdTol, realtype StpTol,
+ realtype MaxStp, int ItnLmt );
+ void UMStop0 ( rvector x0, rvector Grad );
+ void UMStop ( rvector x0, rvector Grad, int RetCode,
+ int ItnCnt, bool MaxTkn );
+
+ virtual void Gradient ( rvector X, rvector G, realtype Fc );
+ virtual void FDHessF ( realtype Fc, rvector X );
+
+ void FDGrad ( rvector X, rvector G, realtype Fc );
+ void CDGrad ( rvector X, rvector G );
+ void MdHess ( rmatrix H, rvector HDg );
+ void InitHessUnFac ( realtype F, rmatrix H );
+ void BFGSUnFac ( rvector Xc, rvector Xp,
+ rvector Gc, rvector Gp,
+ bool AnalGrad, rvector HDg,
+ rmatrix H );
+ void Choose_Lambda ( rvector X, rvector S, realtype & Lambda0 );
+ void LineSearch ( rvector px0, rvector G,
+ rvector P, realtype pFunc,
+ int & RetCode, bool & MaxTkn );
+ void GetMemory ();
+ void FreeMemory ();
+ void Relax ();
+ void CopyPlus ( rvector x0 );
+
+ };
+
+ }
+
+}
+
+#endif
+
+
diff --git a/mmdb2/mmdb_math_fft.cpp b/mmdb2/mmdb_math_fft.cpp
new file mode 100755
index 0000000..bf449b3
--- /dev/null
+++ b/mmdb2/mmdb_math_fft.cpp
@@ -0,0 +1,338 @@
+// $Id: mmdb_math_fft.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2005-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : FFT <implementation>
+// ~~~~~~~~~
+// **** Functions: mmdb::math::FFT
+// ~~~~~~~~~ mmdb::math::RealFFT
+// mmdb::math::TwoFFT
+// mmdb::math::Convolve
+// mmdb::math::mConvolve
+//
+// (C) E.Krissinel 2005-2013
+//
+// =================================================================
+//
+
+#include <math.h>
+
+#include "mmdb_math_fft.h"
+
+namespace mmdb {
+
+ namespace math {
+
+ void FFT ( rvector data, int nn, bool Forward ) {
+ // Replaces data[1:2*nn] by its discrete Fourier transform,
+ // if Forward is true; or replaces data[1:2*nn] by nn times its
+ // inverse discrete Fourier transform if Forward is false.
+ // On call,
+ // data[i], i=1,3,5 ... nn-1 are real parts of function,
+ // data[i], i=2,4,6 ... nn are imaginary parts.
+ // nn MUST be an integer power of 2 (this is not checked for!).
+ // User should allocate data with GetVectorMemory and deallocate
+ // it with FreeVectorMemory to assure correct managing of indices
+ // 1..2*nn (not 0..2*nn-1).
+ // On return,
+ // data[i], i=1,3,5 ... nn-1 are real parts, and
+ // data[i], i=2,4,6 ... nn are imaginary parts of positive part
+ // of spectra, with frequences
+ // 0,1/(nn*D),2/(nn*D) ... (nn/2-1)/(nn*D);
+ // data[nn+1] and data[nn+2] are real and imaginary parts for
+ // the frequances +/-1/(2*D)
+ // data[i], i=nn+3,nn+5,nn+7 ... 2*nn-1 are real parts, and
+ // data[i], i=nn+4,nn+6,nn+8 ... 2*nn are imaginary parts of
+ // negative part of the spectra with frequences
+ // -(nn/2-1)/(nn*D), -(nn/2-2)/(nn*D), -1/(nn*D)
+ //
+ int i,istep,j,m,mmax,n;
+ realtype tempi,tempr;
+ long double theta,wi,wpi,wpr,wr,wtemp; // this should be of
+ // maximal precision
+ n = 2*nn;
+ j = 1;
+ for (i=1;i<=n;i+=2) {
+ if (j>i) {
+ tempr = data[j];
+ tempi = data[j+1];
+ data[j] = data[i];
+ data[j+1] = data[i+1];
+ data[i] = tempr;
+ data[i+1] = tempi;
+ }
+ m = n/2;
+ while ((m>=2) && (j>m)) {
+ j -= m;
+ m /= 2;
+ }
+ j += m;
+ }
+ mmax = 2;
+ while (n>mmax) {
+ istep = 2*mmax;
+ theta = 2.0*Pi/mmax;
+ if (!Forward) theta = -theta;
+ wpr = sin(0.5*theta);
+ wpr = -2.0*wpr*wpr;
+ wpi = sin(theta);
+ wr = 1.0;
+ wi = 0.0;
+ for (m=1;m<=mmax;m+=2) {
+ for (i=m;i<=n;i+=istep) {
+ j = i + mmax;
+ tempr = wr*data[j] - wi*data[j+1];
+ tempi = wr*data[j+1] + wi*data[j];
+ data[j] = data[i] - tempr;
+ data[j+1] = data[i+1] - tempi;
+ data[i] = data[i] + tempr;
+ data[i+1] = data[i+1] + tempi;
+ }
+ wtemp = wr;
+ wr = wr*wpr - wi*wpi + wr;
+ wi = wi*wpr + wtemp*wpi + wi;
+ }
+ mmax = istep;
+ }
+ }
+
+ void RealFFT ( rvector data, int n, bool Forward ) {
+ // Calculates the Fourier transform of a set of n real-valued data
+ // points. Replaces this data (which is stored in array data[1:n])
+ // by the positive frequency half of its complex Fourier transform.
+ // The real-valued first and last components of the complex transform
+ // are returned as elements data[1] and data[2], respectively.
+ // n MUST be a power of 2. This routine also calculates the
+ // inverse transform of a complex data array if it is the transform
+ // of real data (Result in this case must be multiplied by 2/n).
+ // Array data should be allocated with GetVectorMemory.
+ //
+ int i,i1,i2,i3,i4,n2p3;
+ realtype c1,c2,h1i,h1r,h2i,h2r;
+ long double theta,wi,wpi,wpr,wr,wtemp;
+
+ theta = 2.0*Pi/n;
+ c1 = 0.5;
+ if (Forward) {
+ c2 = -0.5;
+ FFT ( data,n/2,true );
+ } else {
+ c2 = 0.5;
+ theta = -theta;
+ }
+ wpr = sin(0.5*theta);
+ wpr = -2.0*wpr*wpr;
+ wpi = sin(theta);
+ wr = 1.0 + wpr;
+ wi = wpi;
+ n2p3 = n + 3;
+ for (i=2;i<=n/4;i++) {
+ i1 = 2*i - 1;
+ i2 = i1 + 1;
+ i3 = n2p3 - i2;
+ i4 = i3 + 1;
+ h1r = c1*(data[i1] + data[i3]);
+ h1i = c1*(data[i2] - data[i4]);
+ h2r = -c2*(data[i2] + data[i4]);
+ h2i = c2*(data[i1] - data[i3]);
+ data[i1] = h1r + wr*h2r - wi*h2i;
+ data[i2] = h1i + wr*h2i + wi*h2r;
+ data[i3] = h1r - wr*h2r + wi*h2i;
+ data[i4] = -h1i + wr*h2i + wi*h2r;
+ wtemp = wr;
+ wr = wr*wpr - wi*wpi + wr;
+ wi = wi*wpr + wtemp*wpi + wi;
+ }
+ if (Forward) {
+ h1r = data[1];
+ data[1] = h1r + data[2];
+ data[2] = h1r - data[2];
+ } else {
+ h1r = data[1];
+ data[1] = c1*(h1r+data[2]);
+ data[2] = c1*(h1r-data[2]);
+ FFT ( data,n/2,false );
+ }
+ }
+
+ void TwoFFT ( rvector data1, rvector data2,
+ rvector fft1, rvector fft2, int n ) {
+ // Given two real input arrays data1[1:n] and data2[1:n],
+ // this routine calls FFT and returns two "complex" output
+ // arrays fft1[1:2*n] and fft2[1:2*n] (2*i-1 ith real,
+ // 2*i ith imaginary), which contain the discrete Fourier
+ // transforms of the respective data arrays. n MUST be
+ // an integer power of 2.
+ int i,j,n2, bj,bn;
+ realtype h1r,h1i,h2r,h2i;
+ i = 1;
+ for (j=1;j<=n;j++) {
+ fft1[i++] = data1[j];
+ fft1[i++] = data2[j];
+ }
+ FFT ( fft1,n,true );
+ fft2[1] = fft1[2]; fft2[2] = 0.0;
+ fft1[2] = 0.0;
+ n2 = n + 2;
+ for (j=2;j<=n/2+1;j++) {
+ bj = 2*j-1; bn = 2*(n2-j)-1;
+ h1r = 0.5*(fft1[bj] + fft1[bn]);
+ h1i = 0.5*(fft1[bj+1] - fft1[bn+1]);
+ h2r = 0.5*(fft1[bj+1] + fft1[bn+1]);
+ h2i = 0.5*(fft1[bn] - fft1[bj]);
+ fft1[bj] = h1r; fft1[bj+1] = h1i;
+ fft1[bn] = h1r; fft1[bn+1] = -h1i;
+ fft2[bj] = h2r; fft2[bj+1] = h2i;
+ fft2[bn] = h2r; fft2[bn+1] = -h2i;
+ }
+ }
+
+ void Convolve ( rvector data, int n, rvector respns, int m,
+ rvector ans, bool Conv ) {
+ // Convolves or Deconvolves a real data set data[1:n] (including
+ // any user-supplied zero padding) with a response function
+ // respns[1..n], stored in wrap-around order in a real array of
+ // length m<n (m should be an odd (3,5,7...) integer). Wrap-around
+ // order means that the first half of the array contains the impulse
+ // response function at positive times, while the second half of
+ // the array contains the impulse response function at negative
+ // times, counting down from the highest element respns[m]. On
+ // input Conv=true for convolution, false for deconvolution.
+ // The answer is returned in the first n component of ans.
+ // However, ans must be supplied in the calling program with
+ // length at least 2*n, for consistency with TwoFFT. n MUST
+ // be an integer power of 2.
+ //
+ int i,no2,rp,ip;
+ rvector fft;
+ realtype B,D;
+
+ GetVectorMemory ( fft,2*n,1 );
+ for (i=1;i<=(m-1)/2;i++)
+ respns[n+1-i] = respns[m+1-i];
+ for (i=(m+3)/2;i<=n-(m-1)/2;i++)
+ respns[i] = 0.0;
+
+ TwoFFT ( data,respns,fft,ans,n );
+
+ no2 = n/2;
+ rp = 1; // pointer to real part
+ ip = 2; // pointer to imaginary part
+ for (i=1;i<=no2+1;i++) {
+ if (Conv) {
+ B = (fft[rp]*ans[rp] - fft[ip]*ans[ip])/no2;
+ ans[ip] = (fft[ip]*ans[rp] + fft[rp]*ans[ip])/no2;
+ ans[rp] = B;
+ } else {
+ D = (ans[rp]*ans[rp] + ans[ip]*ans[ip])*no2;
+ if (D==0.0) {
+ // poor deconvolve at zero response
+ ans[rp] = 0.0;
+ ans[ip] = 0.0;
+ } else {
+ B = (fft[rp]*ans[rp] + fft[ip]*ans[ip])/D;
+ ans[ip] = (fft[ip]*ans[rp] - fft[rp]*ans[ip])/D;
+ ans[rp] = B;
+ }
+ }
+ rp += 2;
+ ip += 2;
+ }
+
+ ans[2] = ans[2*no2+1];
+ FreeVectorMemory ( fft,1 );
+
+ RealFFT ( ans,n,false );
+
+ }
+
+
+ void mConvolve ( rvector data, int n, int m ) {
+ //
+ // Replaces array data[0..n-1] with the result of m recursive
+ // convolutions (m>1) defined as
+ //
+ // data_m = data (*) data_{m-1}
+ //
+ // where data_m is the result of mth convolution, data_0=data.
+ // The definition of the convolution is
+ //
+ // [a (*) b]_i = Sum_j { a_j * b_{i-j} }
+ //
+ // On input, data[] is considered as containing the signal
+ // sampled at both positive and negative times in the wrap-around
+ // order, that is
+ //
+ // data[i], 0<=i<n/2 signal sampled at times dt*i
+ // data[i], n/2<=i<n signal sampled at times -dt*(n-i)
+ //
+ // and the same wrap-around order is used to interprete the output
+ // data. This means that if only m positive sampling times are
+ // used, the length of data must be at least n=2*m, the rest being
+ // padded with zeroes.
+ //
+ // The number of sampling nodes n *must* be an integer power of
+ // two, i.e. 2,4,8,16 ... .
+ //
+ realtype R,G,phi,B,m2,n2,d1;
+ int i,m1;
+
+ if (m<1) return;
+
+ RealFFT ( data-1,n,true );
+
+ m1 = m+1;
+ m2 = m1/2.0;
+ n2 = 2.0/n;
+ d1 = data[1];
+ for (i=0;i<=n;i+=2) {
+ if (i<n) {
+ R = data[i];
+ if (i>1) G = data[i+1];
+ else G = 0.0;
+ } else {
+ R = d1;
+ G = 0.0;
+ }
+ phi = atan2(G,R) * m1;
+ B = pow(R*R+G*G,m2);
+ R = B*cos(phi);
+ G = B*sin(phi);
+ if (i<n) {
+ data[i] = R*n2;
+ data[i+1] = G*n2;
+ } else
+ data[1] = R*n2;
+ }
+
+ RealFFT ( data-1,n,false );
+
+ }
+
+ } // namespace math
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_math_fft.h b/mmdb2/mmdb_math_fft.h
new file mode 100755
index 0000000..6d91380
--- /dev/null
+++ b/mmdb2/mmdb_math_fft.h
@@ -0,0 +1,93 @@
+// $Id: mmdb_math_fft.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2005-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : FFT <interface>
+// ~~~~~~~~~
+// **** Functions: mmdb::math::FFT
+// ~~~~~~~~~ mmdb::math::RealFFT
+// mmdb::math::TwoFFT
+// mmdb::math::Convolve
+// mmdb::math::mConvolve
+//
+// (C) E.Krissinel 2005-2013
+//
+// =================================================================
+//
+
+#ifndef __FFT__
+#define __FFT__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb {
+
+ namespace math {
+
+ extern void FFT ( rvector data, int nn, bool Forward=true );
+
+ extern void RealFFT ( rvector data, int n, bool Forward=true );
+
+ extern void TwoFFT ( rvector data1, rvector data2,
+ rvector fft1, rvector fft2, int n );
+
+ extern void Convolve ( rvector data, int n, rvector respns, int m,
+ rvector ans, bool Conv=true );
+
+
+ // mConvolve ( data,n,m ) replaces array data[0..n-1] with the result
+ // of m recursive convolutions (m>1) defined as
+ //
+ // data_m = data (*) data_{m-1}
+ //
+ // where data_m is the result of mth convolution, data_0=data.
+ // The definition of the convolution is
+ //
+ // [a (*) b]_i = Sum_j { a_j * b_{i-j} }
+ //
+ // On input, data[] is considered as containing the signal
+ // sampled at both positive and negative times in the wrap-around
+ // order, that is
+ //
+ // data[i], 0<=i<n/2 signal sampled at times dt*i
+ // data[i], n/2<=i<n signal sampled at times -dt*(n-i)
+ //
+ // and the same wrap-around order is used to interprete the output
+ // data. This means that if only m positive sampling times are
+ // used, the length of data must be at least n=2*m, the rest being
+ // padded with zeroes.
+ //
+ // The number of sampling nodes n *must* be an integer power of
+ // two, i.e. 2,4,8,16 ... .
+ //
+ extern void mConvolve ( rvector data, int n, int m );
+
+ } // namespace math
+
+} // namespace mmdb
+
+#endif
diff --git a/mmdb2/mmdb_math_graph.cpp b/mmdb2/mmdb_math_graph.cpp
new file mode 100644
index 0000000..b927665
--- /dev/null
+++ b/mmdb2/mmdb_math_graph.cpp
@@ -0,0 +1,2461 @@
+// $Id: mmdb_math_graph.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_math_graph <implementation>
+// ~~~~~~~~~
+// **** Namespace: mmdb::math::
+// ~~~~~~~~~~
+// **** Classes : Vertex ( graph vertex )
+// ~~~~~~~~~ Edge ( graph edge )
+// Graph ( structural graph )
+// GMatch ( GMatch of structural graphs )
+// GraphMatch ( CSIA algorithms for graphs GMatching )
+//
+// (C) E. Krissinel 2000-2013
+//
+// When used, please cite:
+//
+// Krissinel, E. and Henrick, K. (2004)
+// Common subgraph isomorphism detection by backtracking search.
+// Software - Practice and Experience, 34, 591-607.
+//
+// =================================================================
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mmdb_math_graph.h"
+#include "mmdb_tables.h"
+
+
+namespace mmdb {
+
+ namespace math {
+
+ // ========================= Vertex ==========================
+
+ Vertex::Vertex() : io::Stream() {
+ InitVertex();
+ }
+
+ Vertex::Vertex ( io::RPStream Object ) : io::Stream(Object) {
+ InitVertex();
+ }
+
+ Vertex::Vertex ( cpstr chem_elem ) : io::Stream() {
+ InitVertex();
+ SetVertex ( chem_elem );
+ }
+
+ Vertex::Vertex ( int vtype ) : io::Stream() {
+ InitVertex();
+ SetVertex ( vtype );
+ }
+
+ Vertex::Vertex ( int vtype, cpstr vname ) : io::Stream() {
+ InitVertex();
+ SetVertex ( vtype,vname );
+ }
+
+ Vertex::Vertex ( cpstr chem_elem, cpstr vname ) : io::Stream() {
+ InitVertex ();
+ SetVertex ( chem_elem );
+ CreateCopy ( name,vname );
+ }
+
+ Vertex::~Vertex() {
+ if (name) delete[] name;
+ }
+
+ void Vertex::InitVertex() {
+ name = NULL;
+ type = 0;
+ type_ext = 0;
+ property = 0;
+ id = 0;
+ user_id = 0;
+ }
+
+
+ void Vertex::SetVertex ( cpstr chem_elem ) {
+ // This function generates vertex type according to a chemical
+ // element name passed in chem_elem.
+ //
+ // The element type has the following meaning:
+ //
+ // 0xCHSSTTTT
+ //
+ // where
+ // T - resreved for elemenmt type
+ // S - resreved for symmetry relief
+ // H - reserved for hydrogen bonds
+ // C - resreved for chirality flags
+ //
+ // Note that when more than 2 symbols are used for chemical element
+ // name (custom use), fields S may be reallocated for element type
+ // and then symmetry relief becomes impossible.
+ //
+ CreateCopy ( name,chem_elem );
+ type = getElementNo ( chem_elem );
+ if (type==ELEMENT_UNKNOWN) {
+ type = 0;
+ if (name[0]) {
+ type = (int)name[0];
+ if (name[1]) {
+ type = type*256+(int)name[1];
+ if (name[2]) type = type*256+(int)name[2];
+ }
+ }
+ type += nElementNames;
+ }
+ }
+
+ void Vertex::SetVertex ( int vtype ) {
+ // This function sets vertex type. See comments above for
+ // the general rule for vertex types implied by this code.
+ char N[50];
+ int type0;
+ type = vtype;
+ type0 = vtype & TYPE_MASK;
+ if ((type0>=1) && (type0<=nElementNames))
+ CreateCopy ( name,ElementName[type0-1] );
+ else {
+ sprintf ( N,"%i",type );
+ CreateCopy ( name,N );
+ }
+ }
+
+ void Vertex::SetType ( int vtype ) {
+ type = vtype;
+ }
+
+ void Vertex::SetTypeExt ( int typeExt ) {
+ type_ext = typeExt;
+ }
+
+ void Vertex::SetVertex ( int vtype, cpstr vname ) {
+ type = vtype;
+ CreateCopy ( name,vname );
+ }
+
+ void Vertex::SetName ( cpstr vname ) {
+ CreateCopy ( name,vname );
+ }
+
+ void Vertex::SetID ( int vid ) {
+ id = vid;
+ }
+
+ void Vertex::SetProperty ( int vprop ) {
+ property = vprop;
+ }
+
+ int Vertex::GetNBonds() {
+ return ((type & HYDROGEN_BOND) >> 24);
+ }
+
+ void Vertex::AddBond() {
+ int nb = GetNBonds()+1;
+ type &= ~HYDROGEN_BOND;
+ type |= nb << 24;
+ }
+
+ void Vertex::CopyNBonds ( PVertex V ) {
+ int nb = V->GetNBonds();
+ type &= ~HYDROGEN_BOND;
+ type |= nb << 24;
+ }
+
+ void Vertex::RemoveChirality() {
+ type &= CHIRAL_MASK;
+ }
+
+ void Vertex::LeaveChirality ( int eltype ) {
+ // leaves chirality only on specified elements
+ int vtype;
+ vtype = type & CHIRAL_MASK;
+ if (vtype!=eltype) type = vtype;
+ }
+
+ void Vertex::SaveType() {
+ user_id = type;
+ }
+
+ void Vertex::RestoreType() {
+ type = user_id;
+ }
+
+ void Vertex::CopyType ( PVertex V ) {
+ type = V->type;
+ }
+
+
+ void Vertex::Print ( int PKey ) {
+ if (PKey!=0)
+ printf ( " name type" );
+ else printf ( " %10s %5i",name,type );
+ }
+
+ void Vertex::Copy ( PVertex V ) {
+ CreateCopy ( name,V->name );
+ type = V->type;
+ type_ext = V->type_ext;
+ property = V->property;
+ id = V->id;
+ user_id = V->user_id;
+ }
+
+ void Vertex::write ( io::RFile f ) {
+ int Version=2;
+ f.WriteInt ( &Version );
+ f.CreateWrite ( name );
+ f.WriteInt ( &type );
+ f.WriteInt ( &property );
+ f.WriteInt ( &id );
+ f.WriteInt ( &user_id );
+ f.WriteInt ( &type_ext );
+ }
+
+ void Vertex::read ( io::RFile f ) {
+ int Version;
+ f.ReadInt ( &Version );
+ f.CreateRead ( name );
+ f.ReadInt ( &type );
+ f.ReadInt ( &property );
+ f.ReadInt ( &id );
+ f.ReadInt ( &user_id );
+ if (Version>1) f.ReadInt ( &type_ext );
+ else type_ext = 0;
+ }
+
+ void Vertex::mem_write ( pstr S, int & l ) {
+ byte Version=2;
+ mmdb::mem_write_byte ( Version,S,l );
+ mmdb::mem_write ( name ,S,l );
+ mmdb::mem_write ( type ,S,l );
+ mmdb::mem_write ( property,S,l );
+ mmdb::mem_write ( id ,S,l );
+ mmdb::mem_write ( user_id ,S,l );
+ mmdb::mem_write ( type_ext,S,l );
+ }
+
+ void Vertex::mem_read ( cpstr S, int & l ) {
+ byte Version;
+ mmdb::mem_read_byte ( Version,S,l );
+ mmdb::mem_read ( name ,S,l );
+ mmdb::mem_read ( type ,S,l );
+ mmdb::mem_read ( property,S,l );
+ mmdb::mem_read ( id ,S,l );
+ mmdb::mem_read ( user_id ,S,l );
+ mmdb::mem_read ( type_ext,S,l );
+ }
+
+ MakeStreamFunctions(Vertex)
+
+
+
+ // =========================== Edge =============================
+
+ Edge::Edge() : io::Stream() {
+ InitEdge();
+ }
+
+ Edge::Edge ( io::RPStream Object ) : io::Stream(Object) {
+ InitEdge();
+ }
+
+ Edge::Edge ( int vx1, int vx2, int btype ) {
+ InitEdge();
+ SetEdge ( vx1,vx2,btype );
+ }
+
+ Edge::~Edge() {}
+
+ void Edge::InitEdge() {
+ v1 = 0;
+ v2 = 0;
+ type = 0;
+ property = 0;
+ }
+
+
+ #define NofBondTypes 4
+
+ static pstr BondType[NofBondTypes+1] = {
+ pstr("SING"), pstr("DOUB"), pstr("AROM"), pstr("TRIP"),
+ pstr("") // should be here for safety
+ };
+
+
+ void Edge::SetEdge ( int vx1, int vx2, cpstr btype ) {
+ v1 = vx1;
+ v2 = vx2;
+ type = 0;
+ while (type<NofBondTypes)
+ if (!strncasecmp(btype,BondType[type],4)) break;
+ else type++;
+ if (type>=NofBondTypes) {
+ type = 0;
+ if (btype[0]) type = (int)btype[0];
+ if (btype[1]) type = type*16+(int)btype[1];
+ if (btype[2]) type = type*16+(int)btype[2];
+ type += NofBondTypes;
+ }
+ type++;
+ }
+
+ void Edge::SetEdge ( int vx1, int vx2, int btype ) {
+ v1 = vx1;
+ v2 = vx2;
+ type = btype;
+ }
+
+ void Edge::SetType ( int btype ) {
+ type = btype;
+ }
+
+ void Edge::SetProperty ( int eprop ) {
+ property = eprop;
+ }
+
+ void Edge::SaveType() {
+ property = type;
+ }
+
+ void Edge::RestoreType() {
+ type = property;
+ }
+
+ void Edge::Print ( int PKey ) {
+ if (PKey!=0)
+ printf ( " v1 v2 type" );
+ else printf ( " %5i %5i %5i",v1,v2,type );
+ }
+
+ void Edge::Copy ( PEdge G ) {
+ v1 = G->v1;
+ v2 = G->v2;
+ type = G->type;
+ property = G->property;
+ }
+
+ void Edge::write ( io::RFile f ) {
+ int Version=1;
+ f.WriteInt ( &Version );
+ f.WriteInt ( &v1 );
+ f.WriteInt ( &v2 );
+ f.WriteInt ( &type );
+ f.WriteInt ( &property );
+ }
+
+ void Edge::read ( io::RFile f ) {
+ int Version;
+ f.ReadInt ( &Version );
+ f.ReadInt ( &v1 );
+ f.ReadInt ( &v2 );
+ f.ReadInt ( &type );
+ f.ReadInt ( &property );
+ }
+
+ void Edge::mem_write ( pstr S, int & l ) {
+ byte Version=1;
+ mmdb::mem_write_byte ( Version,S,l );
+ mmdb::mem_write ( v1 ,S,l );
+ mmdb::mem_write ( v2 ,S,l );
+ mmdb::mem_write ( type ,S,l );
+ mmdb::mem_write ( property,S,l );
+ }
+
+ void Edge::mem_read ( cpstr S, int & l ) {
+ byte Version;
+ mmdb::mem_read_byte ( Version,S,l );
+ mmdb::mem_read ( v1 ,S,l );
+ mmdb::mem_read ( v2 ,S,l );
+ mmdb::mem_read ( type ,S,l );
+ mmdb::mem_read ( property,S,l );
+ }
+
+ MakeStreamFunctions(Edge)
+
+
+ // ========================== Graph ============================
+
+ Graph::Graph() : io::Stream() {
+ InitGraph();
+ }
+
+ Graph::Graph ( PResidue R, cpstr altLoc ) : io::Stream() {
+ InitGraph();
+ MakeGraph ( R,altLoc );
+ }
+
+ Graph::Graph ( io::RPStream Object ) : io::Stream(Object) {
+ InitGraph();
+ }
+
+ Graph::~Graph() {
+ FreeMemory();
+ }
+
+ void Graph::InitGraph() {
+ nVAlloc = 0;
+ nEAlloc = 0;
+ nGAlloc = 0;
+ nVertices = 0;
+ nEdges = 0;
+ nAllVertices = 0;
+ nAllEdges = 0;
+ vertex = NULL;
+ edge = NULL;
+ graph = NULL;
+ name = NULL;
+ CreateCopy ( name,pstr("UNNAMED") );
+ }
+
+ void Graph::FreeMemory() {
+ int i;
+
+ if (vertex) {
+ for (i=0;i<nVAlloc;i++)
+ if (vertex[i])
+ delete vertex[i];
+ delete[] vertex;
+ }
+ nVAlloc = 0;
+ nVertices = 0;
+ nAllVertices = 0;
+ vertex = NULL;
+
+ if (edge) {
+ for (i=0;i<nEAlloc;i++)
+ if (edge[i])
+ delete edge[i];
+ delete[] edge;
+ }
+ nEAlloc = 0;
+ nEdges = 0;
+ nAllEdges = 0;
+ edge = NULL;
+
+ FreeMatrixMemory ( graph,nGAlloc,1,1 );
+ nGAlloc = 0;
+
+ if (name) delete[] name;
+ name = NULL;
+
+ }
+
+ void Graph::Reset() {
+ FreeMemory();
+ CreateCopy ( name,pstr("UNNAMED") );
+ }
+
+ void Graph::SetName ( cpstr gname ) {
+ CreateCopy ( name,gname );
+ }
+
+
+ static int AllocPortion = 100;
+
+ void SetGraphAllocPortion ( int alloc_portion ) {
+ AllocPortion = alloc_portion;
+ }
+
+ void Graph::AddVertex ( PVertex V ) {
+ int i;
+ PVertex * V1;
+
+ if (nAllVertices>=nVAlloc) {
+ nVAlloc += AllocPortion;
+ V1 = new PVertex[nVAlloc];
+ for (i=0;i<nAllVertices;i++)
+ V1[i] = vertex[i];
+ for (i=nAllVertices;i<nVAlloc;i++)
+ V1[i] = NULL;
+ if (vertex) delete[] vertex;
+ vertex = V1;
+ }
+ if (vertex[nAllVertices])
+ delete vertex[nAllVertices];
+ vertex[nAllVertices] = V;
+ nAllVertices++;
+ nVertices = nAllVertices;
+
+ }
+
+ void Graph::SetVertices ( PPVertex V, int vlen ) {
+ if (nVAlloc>0) FreeMemory();
+ vertex = V;
+ nVertices = vlen;
+ nAllVertices = vlen;
+ nVAlloc = vlen;
+ }
+
+ int Graph::GetVertexID ( int vertexNo ) {
+ if ((vertexNo>0) && (vertexNo<=nAllVertices))
+ return vertex[vertexNo-1]->GetID();
+ else return MinInt4;
+ }
+
+ int Graph::GetNBondedVertices ( int vertexNo ) {
+ if ((vertexNo>0) && (vertexNo<=nAllVertices)) {
+ if (vertex[vertexNo-1])
+ return vertex[vertexNo-1]->GetNBonds();
+ }
+ return 0;
+ }
+
+ int Graph::GetBondedVertexID ( int vertexNo, int bond_vx_type,
+ int bondNo ) {
+ int i,k, v1,v2;
+ if ((vertexNo>0) && (vertexNo<=nAllVertices)) {
+ if (vertex[vertexNo-1]) {
+ if (vertex[vertexNo-1]->GetNBonds()>=bondNo) {
+ k = 0;
+ for (i=0;(i<nAllEdges) && (!k);i++)
+ if (edge[i]) {
+ v1 = edge[i]->v1;
+ v2 = edge[i]->v2;
+ if ((v1==vertexNo) &&
+ ((vertex[v2-1]->type & (int)TYPE_MASK) ==
+ bond_vx_type) &&
+ (vertex[v2-1]->GetNBonds()==bondNo))
+ k = v2;
+ if ((v2==vertexNo) &&
+ ((vertex[v1-1]->type & (int)TYPE_MASK) ==
+ bond_vx_type) &&
+ (vertex[v2-1]->GetNBonds()==bondNo))
+ k = v1;
+ }
+ if (k) return vertex[k-1]->GetID();
+ }
+ }
+ }
+ return MinInt4;
+ }
+
+ PVertex Graph::GetVertex ( int vertexNo ) {
+ if ((vertexNo>0) && (vertexNo<=nAllVertices))
+ return vertex[vertexNo-1];
+ else return NULL;
+ }
+
+ int Graph::GetVertexNo ( cpstr vname ) {
+ int i,k;
+ k = 0;
+ if (vname)
+ for (i=0;(i<nAllVertices) && (!k);i++)
+ if (!strcmp(vname,vertex[i]->name))
+ k = i+1;
+ return k;
+ }
+
+ PEdge Graph::GetEdge ( int edgeNo ) {
+ if ((edgeNo>0) && (edgeNo<=nAllEdges))
+ return edge[edgeNo-1];
+ else return NULL;
+ }
+
+ void Graph::AddEdge ( PEdge G ) {
+ int i;
+ PPEdge G1;
+
+ if (nAllEdges>=nEAlloc) {
+ nEAlloc += AllocPortion;
+ G1 = new PEdge[nEAlloc];
+ for (i=0;i<nAllEdges;i++)
+ G1[i] = edge[i];
+ for (i=nAllEdges;i<nEAlloc;i++)
+ G1[i] = NULL;
+ if (edge) delete[] edge;
+ edge = G1;
+ }
+ if (edge[nAllEdges])
+ delete edge[nAllEdges];
+ edge[nAllEdges] = G;
+ nAllEdges++;
+ nEdges = nAllEdges;
+
+ }
+
+ void Graph::SetEdges ( PPEdge G, int glen ) {
+ if (nEAlloc>0) FreeMemory();
+ edge = G;
+ nEdges = glen;
+ nAllEdges = glen;
+ nEAlloc = glen;
+ }
+
+ void Graph::GetVertices ( PPVertex & V, int & nV ) {
+ V = vertex;
+ nV = nVertices;
+ }
+
+ void Graph::GetEdges ( PPEdge & E, int & nE ) {
+ E = edge;
+ nE = nEdges;
+ }
+
+
+ int Graph::MakeGraph ( PResidue R, cpstr altLoc ) {
+ int i,j, a1,a2,e1,e2, nAltLocs,alflag, rc;
+ bool B;
+ rvector occupancy;
+ AltLoc aLoc;
+ PAltLoc aL;
+ realtype dx,dy,dz, sr;
+ PEdge G;
+
+ rc = MKGRAPH_Ok;
+ // reset graph
+ FreeMemory();
+
+ occupancy = NULL;
+ aL = NULL;
+ R->GetAltLocations ( nAltLocs,aL,occupancy,alflag );
+ if (nAltLocs<=0) return MKGRAPH_NoAtoms;
+
+ if (altLoc) strcpy ( aLoc,altLoc );
+ else aLoc[0] = char(0);
+ if (nAltLocs<=1) {
+ // Only one alt code is there, check if it is what was ordered
+ if (strcmp(aLoc,aL[0])) {
+ rc = MKGRAPH_ChangedAltLoc;
+ strcpy ( aLoc,aL[0] );
+ }
+ } else if ((alflag & ALF_Mess) ||
+ ((alflag & ALF_NoEmptyAltLoc) && (!aLoc[0]))) {
+ // There is a mess in the residue alt codes, or empty alt code
+ // does not designate a conformation but ordered. In this
+ // situation build graph for maximal-occupancy conformation
+ // and store its altLoc in aLoc.
+ rc = MKGRAPH_MaxOccupancy;
+ dx = -2.0;
+ for (i=0;i<nAltLocs;i++)
+ if ((aL[i][0]) && (occupancy[i]>dx)) {
+ dx = occupancy[i];
+ strcpy ( aLoc,aL[i] );
+ }
+ }
+
+ SetName ( R->name );
+
+ nVAlloc = R->nAtoms; // upper estimate for vertices to allocate
+ if (nVAlloc<=0) {
+ if (aL) delete[] aL;
+ FreeVectorMemory ( occupancy,0 );
+ return MKGRAPH_NoAtoms;
+ }
+
+ // allocate vertex array
+ vertex = new PVertex[nVAlloc];
+ for (i=0;i<nVAlloc;i++)
+ vertex[i] = NULL;
+
+ // make vertices
+ for (i=0;i<R->nAtoms;i++)
+ if (R->atom[i]) {
+ if (!R->atom[i]->Ter) {
+ if (nAltLocs>1) {
+ // This is a many-altcode residue. aLoc contains the altcode
+ // that has to be included. Check on it:
+ B = !strcmp(aLoc,R->atom[i]->altLoc);
+ if ((!B) && (!R->atom[i]->altLoc[0])) {
+ // We got a non-aLoc code that is an "empty-altcode".
+ // Check if this atom has the altcode that we need.
+ for (j=i+1;(j<R->nAtoms) && (!B);j++)
+ if (R->atom[j]) {
+ if ((!R->atom[j]->Ter) &&
+ (!strcmp(R->atom[j]->name,R->atom[i]->name)))
+ B = !strcmp(aLoc,R->atom[j]->altLoc);
+ }
+ // if altcode=aLoc is not there for the atom (B is set
+ // false) then we take its "empty-code" location
+ B = !B;
+ }
+ } else
+ B = true;
+ if (B) {
+ vertex[nVertices] = new Vertex ( R->atom[i]->element,
+ R->atom[i]->name );
+ vertex[nVertices]->id = nVertices;
+ vertex[nVertices]->user_id = i;
+ nVertices++;
+ }
+ }
+ }
+
+ if (nVertices<=0) {
+ if (aL) delete[] aL;
+ FreeVectorMemory ( occupancy,0 );
+ return MKGRAPH_NoAtoms;
+ }
+
+ // make edges
+ nEAlloc = 3*nVertices;
+ edge = new PEdge[nEAlloc];
+ for (i=0;i<nEAlloc;i++)
+ edge[i] = NULL;
+
+ for (i=0;i<nVertices;i++) {
+ a1 = vertex[i]->user_id;
+ e1 = vertex[i]->type;
+ if (e1>nElementNames) e1 = 6;
+ e1--;
+ for (j=i+1;j<nVertices;j++) {
+ a2 = vertex[j]->user_id;
+ e2 = vertex[j]->type;
+ if (e2>nElementNames) e2 = 6;
+ e2--;
+ dx = R->atom[a2]->x - R->atom[a1]->x;
+ dy = R->atom[a2]->y - R->atom[a1]->y;
+ dz = R->atom[a2]->z - R->atom[a1]->z;
+ // sr = CovalentRadius[e1] + CovalentRadius[e2] + 0.15;
+ sr = CovalentRadius[e1] + CovalentRadius[e2] + 0.25;
+ if (dx*dx+dy*dy+dz*dz<sr*sr) { // it's a bond
+ G = new Edge(i+1,j+1,1);
+ AddEdge ( G );
+ }
+ }
+ vertex[i]->id = i+1;
+ }
+
+ if (aL) delete[] aL;
+ FreeVectorMemory ( occupancy,0 );
+
+ nAllVertices = nVertices;
+ nAllEdges = nEdges;
+
+ return rc;
+
+ }
+
+ int Graph::MakeGraph ( PPAtom atom, int nAtoms ) {
+ PEdge G;
+ char atomID[100];
+ realtype dx,dy,dz, sr;
+ int i,j, a1,a2,e1,e2, rc;
+
+ rc = MKGRAPH_Ok;
+ // reset graph
+ FreeMemory();
+
+ nVAlloc = nAtoms; // upper estimate for vertices to allocate
+ if (nVAlloc<=0) return MKGRAPH_NoAtoms;
+
+ // allocate vertex array
+ vertex = new PVertex[nVAlloc];
+ for (i=0;i<nVAlloc;i++)
+ vertex[i] = NULL;
+
+ // make vertices
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter) {
+ vertex[nVertices] = new Vertex ( atom[i]->element,
+ atom[i]->GetAtomIDfmt(atomID) );
+ vertex[nVertices]->user_id = i;
+ nVertices++;
+ }
+ }
+
+ if (nVertices<=0) {
+ FreeMemory();
+ return MKGRAPH_NoAtoms;
+ }
+
+ // make edges
+ nEAlloc = 3*nVertices; // just an inital guess
+ edge = new PEdge[nEAlloc];
+ for (i=0;i<nEAlloc;i++)
+ edge[i] = NULL;
+
+ for (i=0;i<nVertices;i++) {
+ a1 = vertex[i]->user_id;
+ e1 = vertex[i]->type;
+ if (e1>nElementNames) e1 = 6;
+ e1--;
+ for (j=i+1;j<nVertices;j++) {
+ a2 = vertex[j]->user_id;
+ e2 = vertex[j]->type;
+ if (e2>nElementNames) e2 = 6;
+ e2--;
+ dx = atom[a2]->x - atom[a1]->x;
+ dy = atom[a2]->y - atom[a1]->y;
+ dz = atom[a2]->z - atom[a1]->z;
+ sr = CovalentRadius[e1] + CovalentRadius[e2] + 0.25;
+ if (dx*dx+dy*dy+dz*dz<sr*sr) { // it's a bond
+ G = new Edge(i+1,j+1,1); // don't guess on bond order here
+ AddEdge ( G );
+ }
+ }
+ vertex[i]->id = i+1;
+ }
+
+ nAllVertices = nVertices;
+ nAllEdges = nEdges;
+
+ return rc;
+
+ }
+
+
+ void Graph::MakeVertexIDs() {
+ int i;
+ for (i=0;i<nAllVertices;i++)
+ vertex[i]->id = i+1;
+ }
+
+ void Graph::HideType ( int bond_vx_type ) {
+ // 1. Moves vertices bond_vx_type to the end of vertex array
+ // 2. Moves edges to bond_vx_type vertices to the end of edge array
+ // 3. Saves lengths of full vertex and edge arrays, and redefines
+ // lengths to initial parts of the arrays not containing
+ // bond_vx_type vertices.
+ PPEdge Edge1;
+ PPVertex Vertex1;
+ int i,k,v1,v2, nEdges1,nVertices1;
+ ivector iv;
+
+ Edge1 = new PEdge[nEdges];
+ Vertex1 = new PVertex[nVertices];
+ GetVectorMemory ( iv,nVertices,1 );
+
+ for (i=0;i<nEdges;i++)
+ if (edge[i]) {
+ v1 = edge[i]->v1-1;
+ v2 = edge[i]->v2-1;
+ if (vertex[v1] && vertex[v2]) {
+ if ((vertex[v1]->type & (int)TYPE_MASK)==bond_vx_type) {
+ vertex[v2]->AddBond();
+ vertex[v1]->CopyNBonds ( vertex[v2] );
+ }
+ if ((vertex[v2]->type & (int)TYPE_MASK)==bond_vx_type) {
+ vertex[v1]->AddBond();
+ vertex[v2]->CopyNBonds ( vertex[v1] );
+ }
+ }
+ }
+
+ nVertices1 = 0;
+ for (i=0;i<nVertices;i++)
+ if (vertex[i]) {
+ if ((vertex[i]->type & (int)TYPE_MASK)!=bond_vx_type) {
+ Vertex1[nVertices1++] = vertex[i];
+ iv[i+1] = nVertices1;
+ }
+ }
+ k = nVertices1;
+ for (i=0;i<nVertices;i++)
+ if (vertex[i]) {
+ if ((vertex[i]->type & (int)TYPE_MASK)==bond_vx_type) {
+ Vertex1[k++] = vertex[i];
+ iv[i+1] = k;
+ }
+ }
+
+ nEdges1 = 0;
+ for (i=0;i<nEdges;i++)
+ if (edge[i]) {
+ edge[i]->v1 = iv[edge[i]->v1];
+ edge[i]->v2 = iv[edge[i]->v2];
+ if (((Vertex1[edge[i]->v1-1]->type & (int)TYPE_MASK) !=
+ bond_vx_type) &&
+ ((Vertex1[edge[i]->v2-1]->type & (int)TYPE_MASK) !=
+ bond_vx_type))
+ Edge1[nEdges1++] = edge[i];
+ }
+ k = nEdges1;
+ for (i=0;i<nEdges;i++)
+ if (edge[i]) {
+ if (((Vertex1[edge[i]->v1-1]->type & (int)TYPE_MASK) ==
+ bond_vx_type) ||
+ ((Vertex1[edge[i]->v2-1]->type & (int)TYPE_MASK) ==
+ bond_vx_type))
+ Edge1[k++] = edge[i];
+ }
+
+ nAllVertices = nVertices;
+ nAllEdges = nEdges;
+ nVAlloc = nVertices;
+ nEAlloc = nEdges;
+ nVertices = nVertices1;
+ nEdges = nEdges1;
+
+ if (vertex) delete[] vertex;
+ if (edge) delete[] edge;
+ FreeVectorMemory ( iv,1 );
+
+ vertex = Vertex1;
+ edge = Edge1;
+
+ }
+
+ void Graph::ExcludeType ( int type ) {
+ int i,k;
+ ivector iv;
+ GetVectorMemory ( iv,nAllVertices,1 );
+ k = 0;
+ for (i=0;i<nAllVertices;i++)
+ if ((vertex[i]->type & (int)TYPE_MASK)!=type) {
+ if (k<i) {
+ vertex[k] = vertex[i];
+ vertex[i] = NULL;
+ }
+ k++;
+ iv[i+1] = k;
+ } else {
+ delete vertex[i];
+ vertex[i] = NULL;
+ iv[i+1] = 0;
+ }
+ nAllVertices = k;
+ nVertices = nAllVertices;
+ k = 0;
+ for (i=0;i<nAllEdges;i++)
+ if ((iv[edge[i]->v1]!=0) && (iv[edge[i]->v2]!=0)) {
+ if (k<i) {
+ edge[k] = edge[i];
+ edge[i] = NULL;
+ }
+ edge[k]->v1 = iv[edge[k]->v1];
+ edge[k]->v2 = iv[edge[k]->v2];
+ k++;
+ } else {
+ delete edge[i];
+ edge[i] = NULL;
+ }
+ nAllEdges = k;
+ nEdges = nAllEdges;
+ FreeVectorMemory ( iv,1 );
+ }
+
+ void Graph::RemoveChirality() {
+ int i;
+ for (i=0;i<nAllVertices;i++)
+ if (vertex[i]) vertex[i]->RemoveChirality();
+ }
+
+ void Graph::LeaveChirality ( int eltype ) {
+ // leaves chirality for specified atom types
+ int i;
+ for (i=0;i<nAllVertices;i++)
+ if (vertex[i]) vertex[i]->LeaveChirality ( eltype );
+ }
+
+ void Graph::MakeSymmetryRelief ( bool noCO2 ) {
+ // This function looks for groups of equivalent vertices
+ // attached to a single vertice (e.g. chemical SO3 or
+ // PO3 groups), and re-lables them by adding a unique
+ // symmetry-relief number. This eliminates equivalent
+ // GMatches (3! for each SO3/PO3 group), and increases
+ // vertex diversity, which considerably speeds up GMatching.
+ // The function is cheap and harmless even if such groups
+ // of vertices are not found.
+ // If noCO2 is true then CO2 symmetry is not releaved.
+ ivector v,vc;
+ int i,j,k,n,m,almask,vjtype, ctype,otype;
+ bool noOxygens;
+
+ otype = 0;
+ ctype = 0;
+
+ GetVectorMemory ( v ,nVertices,0 );
+ GetVectorMemory ( vc,nVertices,1 );
+
+ for (i=1;i<=nVertices;i++)
+ vc[i] = 0;
+
+ for (j=0;j<nEdges;j++) {
+ if ((edge[j]->v1>0) && (edge[j]->v1<=nVertices))
+ vc[edge[j]->v1]++;
+ if ((edge[j]->v2>0) && (edge[j]->v2<=nVertices))
+ vc[edge[j]->v2]++;
+ }
+
+ almask = ~ATOM_LEAVING;
+
+ if (noCO2) {
+ ctype = getElementNo ( "C" );
+ otype = getElementNo ( "O" );
+ }
+
+ noOxygens = false;
+
+ for (i=1;i<=nVertices;i++)
+ if (vc[i]>1) { // vertex at more than 1 edge
+ // v[] will list connected vertices, k will be their number
+ k = 0;
+ for (j=0;j<nEdges;j++) {
+ if ((edge[j]->v1==i) && (vc[edge[j]->v2]==1) && (k<nVertices))
+ v[k++] = edge[j]->v2-1;
+ if ((edge[j]->v2==i) && (vc[edge[j]->v1]==1) && (k<nVertices))
+ v[k++] = edge[j]->v1-1;
+ }
+ if (k>1) {
+ if (noCO2) noOxygens = ((vertex[i-1]->type & almask)==ctype);
+ // A group of vertices with single connection is
+ // identified. Assign symmetry relief modifiers
+ // to *equivalent* vertices in the group
+ for (j=0;j<k;j++)
+ if ((v[j]>=0) && (v[j]<nVertices)) {
+ vjtype = vertex[v[j]]->type & almask;
+ if ((!noOxygens) || (vjtype!=otype)) {
+ n = 1; // symmetry relief modifier
+ for (m=j+1;m<k;m++)
+ if ((v[m]>=0) && (v[m]<nVertices)) {
+ if (vertex[v[j]]->type==
+ (vertex[v[m]]->type & almask)) {
+ vertex[v[m]]->type |= (n << 16);
+ n++;
+ v[m] = -1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeVectorMemory ( v ,0 );
+ FreeVectorMemory ( vc,1 );
+
+ }
+
+ int Graph::Build ( bool bondOrder ) {
+ int i,j, rc;
+
+ if (nVertices<=0) return 2;
+
+ if (nGAlloc<nVertices) {
+ FreeMatrixMemory ( graph,nGAlloc,1,1 );
+ nGAlloc = nVertices;
+ GetMatrixMemory ( graph,nGAlloc,nGAlloc,1,1 );
+ }
+
+ for (i=1;i<=nVertices;i++)
+ for (j=1;j<=nVertices;j++)
+ graph[i][j] = 0;
+
+ rc = 0;
+ if (bondOrder) {
+
+ for (i=0;(i<nEdges) && (!rc);i++)
+ if ((edge[i]->v1>=1) && (edge[i]->v1<=nVertices) &&
+ (edge[i]->v2>=1) && (edge[i]->v2<=nVertices)) {
+ graph[edge[i]->v1][edge[i]->v2] = edge[i]->type;
+ graph[edge[i]->v2][edge[i]->v1] = edge[i]->type;
+ } else
+ rc = 1;
+
+ } else {
+
+ for (i=0;i<nEdges;i++)
+ if ((edge[i]->v1>=1) && (edge[i]->v1<=nVertices) &&
+ (edge[i]->v2>=1) && (edge[i]->v2<=nVertices)) {
+ graph[edge[i]->v1][edge[i]->v2] = 1;
+ graph[edge[i]->v2][edge[i]->v1] = 1;
+ } else
+ rc = 1;
+
+ }
+
+ return rc;
+
+ }
+
+
+ const int ring_mask[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000001,
+ 0x00000002,
+ 0x00000004,
+ 0x00000008,
+ 0x00000010,
+ 0x00000020,
+ 0x00000040,
+ 0x00000080
+ };
+
+ void Graph::IdentifyRings() {
+ GraphMatch GM;
+ Graph ring;
+ ivector F1,F2;
+ AtomName aname;
+ realtype p1,p2;
+ int i,j,n,nrings,nv;
+
+ Build ( false );
+
+ for (i=0;i<nVertices;i++)
+ vertex[i]->type_ext = 0;
+
+ GM.SetFlag ( GMF_UniqueMatch );
+
+ for (n=3;n<=10;n++) {
+
+ ring.Reset();
+
+ for (i=1;i<=n;i++) {
+ sprintf ( aname,"C%i",i );
+ ring.AddVertex ( new Vertex("C",aname) );
+ }
+
+ ring.MakeVertexIDs();
+
+ for (i=1;i<=n;i++) {
+ j = i+1;
+ if (j>n) j = 1;
+ ring.AddEdge ( new Edge(i,j,1) );
+ }
+
+ ring.Build ( false );
+
+ GM.MatchGraphs ( this,&ring,n,false,EXTTYPE_Ignore );
+
+ nrings = GM.GetNofMatches();
+ for (i=0;i<nrings;i++) {
+ GM.GetMatch ( i,F1,F2,nv,p1,p2 );
+ for (j=1;j<nv;j++)
+ vertex[F1[j]-1]->type_ext |= ring_mask[n];
+ }
+
+ }
+
+ }
+
+ void Graph::markConnected ( int vno, int cno ) {
+ int i;
+
+ vertex[vno]->type_ext = cno;
+ for (i=0;i<nVertices;i++)
+ if (graph[vno+1][i+1] && (!vertex[i]->type_ext))
+ markConnected ( i,cno );
+
+ }
+
+
+ int Graph::IdentifyConnectedComponents() {
+ // Returns the number of connected components and sets
+ // vertex[]->type_ext equal to component number >=1.
+ int nComponents,i;
+
+ nComponents = 0;
+
+ Build ( false );
+
+ for (i=0;i<nVertices;i++)
+ vertex[i]->type_ext = 0;
+
+ i = 0;
+ while (i<nVertices) {
+ while (i<nVertices)
+ if (vertex[i]->type_ext) i++;
+ else break;
+ if (i<nVertices) {
+ nComponents++;
+ markConnected ( i,nComponents );
+ }
+ }
+
+ return nComponents;
+
+ }
+
+
+
+ void Graph::Print() {
+ int i;
+
+ printf ( " ===== Graph %s \n\n",name );
+
+ if (nVertices>0) {
+ printf ( " Vertices:\n"" ## " );
+ vertex[0]->Print(1);
+ printf ( "\n" );
+ for (i=0;i<nVertices;i++) {
+ printf ( " %4i ",i+1 );
+ vertex[i]->Print(0);
+ printf ( "\n" );
+ }
+ }
+
+ if (nEdges>0) {
+ printf ( " Edges:\n"" ## " );
+ edge[0]->Print(1);
+ printf ( "\n" );
+ for (i=0;i<nEdges;i++) {
+ printf ( " %4i ",i+1 );
+ edge[i]->Print(0);
+ printf ( "\n" );
+ }
+ }
+
+
+ }
+
+ void Graph::Print1() {
+ int i,j;
+ for (i=0;i<nVertices;i++) {
+ printf ( " %4i %5i %3i %7s ",
+ i+1,vertex[i]->id,vertex[i]->type,vertex[i]->name );
+ for (j=0;j<nEdges;j++)
+ if (edge[j]->v1==i+1)
+ printf ( " %4i(%i)",edge[j]->v2,edge[j]->type );
+ else if (edge[j]->v2==i+1)
+ printf ( " %4i(%i)",edge[j]->v1,edge[j]->type );
+ printf ( "\n" );
+ }
+ }
+
+
+ void Graph::Copy ( PGraph G ) {
+ int i;
+
+ FreeMemory();
+
+ CreateCopy ( name,G->name );
+ nVertices = G->nVertices;
+ nEdges = G->nEdges;
+ nAllVertices = G->nAllVertices;
+ nAllEdges = G->nAllEdges;
+ if (nAllVertices>0) {
+ nVAlloc = nAllVertices;
+ vertex = new PVertex[nVAlloc];
+ for (i=0;i<nAllVertices;i++) {
+ vertex[i] = new Vertex();
+ vertex[i]->Copy ( G->vertex[i] );
+ }
+ }
+ if (nAllEdges>0) {
+ nEAlloc = nAllEdges;
+ edge = new PEdge[nEAlloc];
+ for (i=0;i<nAllEdges;i++) {
+ edge[i] = new Edge();
+ edge[i]->Copy ( G->edge[i] );
+ }
+ }
+
+ }
+
+ void Graph::write ( io::RFile f ) {
+ int i;
+ int Version=2;
+ bool bondOrder=false;
+ f.WriteInt ( &Version );
+ f.WriteBool ( &bondOrder );
+ f.CreateWrite ( name );
+ f.WriteInt ( &nVertices );
+ f.WriteInt ( &nEdges );
+ f.WriteInt ( &nAllVertices );
+ f.WriteInt ( &nAllEdges );
+ for (i=0;i<nAllVertices;i++)
+ StreamWrite ( f,vertex[i] );
+ for (i=0;i<nAllEdges;i++)
+ StreamWrite ( f,edge[i] );
+ }
+
+ void Graph::read ( io::RFile f ) {
+ int i,Version;
+ bool bondOrder;
+
+ FreeMemory();
+
+ f.ReadInt ( &Version );
+ f.ReadBool ( &bondOrder );
+ f.CreateRead ( name );
+ f.ReadInt ( &nVertices );
+ f.ReadInt ( &nEdges );
+ if (Version>1) {
+ f.ReadInt ( &nAllVertices );
+ f.ReadInt ( &nAllEdges );
+ } else {
+ nAllVertices = nVertices;
+ nAllEdges = nEdges;
+ }
+ if (nAllVertices>0) {
+ nVAlloc = nAllVertices;
+ vertex = new PVertex[nVAlloc];
+ for (i=0;i<nAllVertices;i++) {
+ vertex[i] = NULL;
+ StreamRead ( f,vertex[i] );
+ }
+ }
+ if (nAllEdges>0) {
+ nEAlloc = nAllEdges;
+ edge = new PEdge[nEAlloc];
+ for (i=0;i<nAllEdges;i++) {
+ edge[i] = NULL;
+ StreamRead ( f,edge[i] );
+ }
+ }
+
+ // Build ( bondOrder );
+
+ }
+
+ void Graph::mem_write ( pstr S, int & l ) {
+ int i,k;
+ byte Version=2;
+ bool bondOrder=false;
+
+ mmdb::mem_write_byte ( Version,S,l );
+ mmdb::mem_write ( bondOrder ,S,l );
+ mmdb::mem_write ( name ,S,l );
+ mmdb::mem_write ( nVertices ,S,l );
+ mmdb::mem_write ( nEdges ,S,l );
+ mmdb::mem_write ( nAllVertices,S,l );
+ mmdb::mem_write ( nAllEdges ,S,l );
+ for (i=0;i<nAllVertices;i++)
+ if (vertex[i]) {
+ k = 1;
+ mmdb::mem_write ( k,S,l );
+ vertex[i]->mem_write ( S,l );
+ } else {
+ k = 0;
+ mmdb::mem_write ( k,S,l );
+ }
+ for (i=0;i<nAllEdges;i++)
+ if (edge[i]) {
+ k = 1;
+ mmdb::mem_write ( k,S,l );
+ edge[i]->mem_write ( S,l );
+ } else {
+ k = 0;
+ mmdb::mem_write ( k,S,l );
+ }
+
+ }
+
+ void Graph::mem_read ( cpstr S, int & l ) {
+ int i,k;
+ byte Version;
+ bool bondOrder;
+
+ FreeMemory();
+
+ mmdb::mem_read_byte ( Version,S,l );
+ mmdb::mem_read ( bondOrder ,S,l );
+ mmdb::mem_read ( name ,S,l );
+ mmdb::mem_read ( nVertices ,S,l );
+ mmdb::mem_read ( nEdges ,S,l );
+ mmdb::mem_read ( nAllVertices,S,l );
+ mmdb::mem_read ( nAllEdges ,S,l );
+ if (nAllVertices>0) {
+ nVAlloc = nAllVertices;
+ vertex = new PVertex[nVAlloc];
+ for (i=0;i<nAllVertices;i++) {
+ mmdb::mem_read ( k,S,l );
+ if (k) {
+ vertex[i] = new Vertex();
+ vertex[i]->mem_read ( S,l );
+ } else
+ vertex[i] = NULL;
+ }
+ }
+ if (nAllEdges>0) {
+ nEAlloc = nAllEdges;
+ edge = new PEdge[nEAlloc];
+ for (i=0;i<nAllEdges;i++) {
+ mmdb::mem_read ( k,S,l );
+ if (k) {
+ edge[i] = new Edge();
+ edge[i]->mem_read ( S,l );
+ } else {
+ edge[i] = NULL;
+ }
+ }
+ }
+
+ // Build ( bondOrder );
+
+ }
+
+ MakeStreamFunctions(Graph)
+
+
+ // ========================== GMatch ============================
+
+ GMatch::GMatch() : io::Stream() {
+ InitGMatch();
+ }
+
+ GMatch::GMatch ( io::RPStream Object ) : io::Stream ( Object ) {
+ InitGMatch();
+ }
+
+ GMatch::GMatch ( ivector FV1, ivector FV2, int nv, int n, int m ) {
+ int i;
+ if (FV1 && FV2) {
+ n1 = n;
+ n2 = m;
+ nAlloc = n;
+ GetVectorMemory ( F1,nAlloc,1 );
+ GetVectorMemory ( F2,nAlloc,1 );
+ mlength = nv;
+ for (i=1;i<=mlength;i++) {
+ F1[i] = FV1[i];
+ F2[i] = FV2[i];
+ }
+ } else
+ InitGMatch();
+ }
+
+ void GMatch::InitGMatch() {
+ mlength = 0;
+ n1 = 0;
+ n2 = 0;
+ nAlloc = 0;
+ F1 = NULL;
+ F2 = NULL;
+ }
+
+ GMatch::~GMatch() {
+ FreeVectorMemory ( F1,1 );
+ FreeVectorMemory ( F2,1 );
+ }
+
+ void GMatch::SetMatch ( ivector FV1, ivector FV2,
+ int nv, int n, int m ) {
+ int i;
+ if (FV1 && FV2) {
+ if (nv>nAlloc) {
+ FreeVectorMemory ( F1,1 );
+ FreeVectorMemory ( F2,1 );
+ nAlloc = n;
+ GetVectorMemory ( F1,nAlloc,1 );
+ GetVectorMemory ( F2,nAlloc,1 );
+ }
+ n1 = n;
+ n2 = m;
+ mlength = nv;
+ for (i=1;i<=mlength;i++) {
+ F1[i] = FV1[i];
+ F2[i] = FV2[i];
+ }
+ } else {
+ FreeVectorMemory ( F1,1 );
+ FreeVectorMemory ( F2,1 );
+ mlength = 0;
+ n1 = 0;
+ n2 = 0;
+ }
+ }
+
+
+ bool GMatch::isMatch ( ivector FV1, ivector FV2, int nv ) {
+ int i,j;
+ bool B;
+ if (FV1 && FV2 && (nv<=mlength)) {
+ B = true;
+ for (i=1;(i<=nv) && B;i++) {
+ B = false;
+ for (j=1;(j<=mlength) && (!B);j++)
+ B = (FV1[i]==F1[j]) && (FV2[i]==F2[j]);
+ }
+ return B;
+ }
+ return false;
+ }
+
+ bool GMatch::isCombination ( ivector FV1, ivector FV2, int nv ) {
+ int i,j;
+ bool B;
+ if (FV1 && FV2 && (nv==mlength)) {
+ B = true;
+ for (i=1;(i<=nv) && B;i++) {
+ B = false;
+ for (j=1;(j<=mlength) && (!B);j++)
+ B = (FV1[i]==F1[j]);
+ if (B) {
+ B = false;
+ for (j=1;(j<=mlength) && (!B);j++)
+ B = (FV2[i]==F2[j]);
+ }
+ }
+ return B;
+ }
+ return false;
+ }
+
+
+ void GMatch::GetMatch ( ivector & FV1, ivector & FV2, int & nv,
+ realtype & p1, realtype & p2 ) {
+ FV1 = F1;
+ FV2 = F2;
+ nv = mlength;
+ p1 = mlength;
+ if (p1>0.0) p1 /= n1;
+ p2 = mlength;
+ if (p2>0.0) p2 /= n2;
+ }
+
+ void GMatch::write ( io::RFile f ) {
+ int i;
+ int Version=1;
+ f.WriteInt ( &Version );
+ f.WriteInt ( &mlength );
+ f.WriteInt ( &n1 );
+ f.WriteInt ( &n2 );
+ for (i=1;i<=mlength;i++) {
+ f.WriteInt ( &(F1[i]) );
+ f.WriteInt ( &(F2[i]) );
+ }
+ }
+
+ void GMatch::read ( io::RFile f ) {
+ int i,Version;
+ FreeVectorMemory ( F1,1 );
+ FreeVectorMemory ( F2,1 );
+ f.ReadInt ( &Version );
+ f.ReadInt ( &mlength );
+ f.ReadInt ( &n1 );
+ f.ReadInt ( &n2 );
+ if (mlength>0) {
+ nAlloc = n1;
+ GetVectorMemory ( F1,nAlloc,1 );
+ GetVectorMemory ( F2,nAlloc,1 );
+ for (i=1;i<=mlength;i++) {
+ f.ReadInt ( &(F1[i]) );
+ f.ReadInt ( &(F2[i]) );
+ }
+ }
+ }
+
+ void GMatch::mem_write ( pstr S, int & l ) {
+ int i;
+ mmdb::mem_write ( mlength,S,l );
+ mmdb::mem_write ( n1 ,S,l );
+ mmdb::mem_write ( n2 ,S,l );
+ for (i=1;i<=mlength;i++) {
+ mmdb::mem_write ( F1[i],S,l );
+ mmdb::mem_write ( F2[i],S,l );
+ }
+ }
+
+ void GMatch::mem_read ( cpstr S, int & l ) {
+ int i;
+ FreeVectorMemory ( F1,1 );
+ FreeVectorMemory ( F2,1 );
+ mmdb::mem_read ( mlength,S,l );
+ mmdb::mem_read ( n1 ,S,l );
+ mmdb::mem_read ( n2 ,S,l );
+ if (mlength>0) {
+ nAlloc = n1;
+ GetVectorMemory ( F1,nAlloc,1 );
+ GetVectorMemory ( F2,nAlloc,1 );
+ for (i=1;i<=mlength;i++) {
+ mmdb::mem_read ( F1[i],S,l );
+ mmdb::mem_read ( F2[i],S,l );
+ }
+ }
+ }
+
+
+ MakeStreamFunctions(GMatch)
+
+
+
+ // ======================== GraphMatch ==========================
+
+ GraphMatch::GraphMatch()
+ : io::Stream() {
+ InitGraphMatch();
+ }
+
+ GraphMatch::GraphMatch ( io::RPStream Object )
+ : io::Stream ( Object ) {
+ InitGraphMatch();
+ }
+
+ GraphMatch::~GraphMatch() {
+ FreeMemory();
+ }
+
+ void GraphMatch::InitGraphMatch() {
+ G1 = NULL;
+ G2 = NULL;
+ n = 0;
+ m = 0;
+ P = NULL;
+ nAlloc = 0;
+ mAlloc = 0;
+ nMatches = 0;
+ maxNMatches = -1; // unlimited
+ Match = NULL;
+ nMAlloc = 0;
+ flags = 0;
+ swap = false;
+ wasFullMatch = false;
+ maxMatch = 0;
+ timeLimit = 0; // no time limit
+ Stop = false;
+ stopOnMaxNMathches = false;
+ F1 = NULL;
+ F2 = NULL;
+ iF1 = NULL;
+ ix = NULL;
+ #ifndef _UseRecursion
+ jj = NULL;
+ #endif
+ }
+
+
+ void GraphMatch::SetFlag ( word flag ) {
+ flags |= flag;
+ }
+
+ void GraphMatch::RemoveFlag ( word flag ) {
+ flags &= ~flag;
+ }
+
+ void GraphMatch::SetMaxNofMatches ( int maxNofGMatches,
+ bool stopOnMaxN ) {
+ maxNMatches = maxNofGMatches;
+ stopOnMaxNMathches = stopOnMaxN;
+ }
+
+ void GraphMatch::SetTimeLimit ( int maxTimeToRun ) {
+ timeLimit = maxTimeToRun;
+ }
+
+ void GraphMatch::Reset() {
+ FreeMemory();
+ }
+
+ void GraphMatch::FreeMemory() {
+ int i;
+
+ if (P) {
+ FreeMatrixMemory ( P[1],nAlloc,1,0 );
+ FreeRecHeap ();
+ P = P + 1;
+ delete[] P;
+ P = NULL;
+ }
+
+ FreeMatrixMemory ( iF1,nAlloc,1,1 );
+
+ FreeVectorMemory ( F1 ,1 );
+ FreeVectorMemory ( F2 ,1 );
+ FreeVectorMemory ( ix ,1 );
+ nAlloc = 0;
+ mAlloc = 0;
+
+ if (Match) {
+ for (i=0;i<nMAlloc;i++)
+ if (Match[i]) delete Match[i];
+ delete[] Match;
+ }
+ Match = NULL;
+ nMatches = 0;
+ nMAlloc = 0;
+
+ #ifndef _UseRecursion
+ FreeVectorMemory ( jj,1 );
+ #endif
+
+ }
+
+ void GraphMatch::FreeRecHeap() {
+ int i;
+ if (P)
+ for (i=2;i<=nAlloc;i++)
+ FreeMatrixMemory ( P[i],nAlloc,1,0 );
+ }
+
+
+ void GraphMatch::GetMemory() {
+ int i;
+
+ FreeMemory();
+
+ P = new imatrix[n];
+ P = P-1;
+ GetMatrixMemory ( P[1],n,m+1,1,0 );
+ for (i=2;i<=n;i++)
+ P[i] = NULL;
+
+ GetMatrixMemory ( iF1,n,n,1,1 );
+
+ GetVectorMemory ( F1,n,1 );
+ GetVectorMemory ( F2,n,1 );
+ GetVectorMemory ( ix,n,1 );
+
+ #ifndef _UseRecursion
+ GetVectorMemory ( jj,n,1 );
+ #endif
+
+ nAlloc = n;
+ mAlloc = m;
+
+ }
+
+ void GraphMatch::GetRecHeap() {
+ int i,j;
+ for (i=2;i<=n;i++) {
+ P[i] = new ivector[nAlloc];
+ P[i] = P[i]-1;
+ for (j=1;j<=n;j++)
+ GetVectorMemory ( P[i][j],P[1][j][0]+1,0 );
+ for (j=n+1;j<=nAlloc;j++)
+ P[i][j] = NULL;
+ }
+ }
+
+
+ void GraphMatch::MatchGraphs ( PGraph Gh1, PGraph Gh2,
+ int minMatch,
+ bool vertexType,
+ VERTEX_EXT_TYPE vertexExt ) {
+ // GMatchGraphs looks for maximal common subgraphs of size
+ // not less than minGMatch. The number of found subgraphs
+ // is returned by GetNofGMatches(), the subgraph vertices
+ // are returned by GetGMatch(..). Control parameters:
+ // vertexType true if vertex type should be taken
+ // into account and false otherwise
+ // vertexExt key to use extended vertex types (defined
+ // as type_ext in Vertex).
+ int n1;
+
+ if (Gh1->nVertices<=Gh2->nVertices) {
+ G1 = Gh1;
+ G2 = Gh2;
+ swap = false;
+ } else {
+ G1 = Gh2;
+ G2 = Gh1;
+ swap = true;
+ }
+ n = G1->nVertices;
+ m = G2->nVertices;
+ V1 = G1->vertex;
+ V2 = G2->vertex;
+ c1 = G1->graph;
+ c2 = G2->graph;
+
+ nMatches = 0;
+
+ if (n<=0) return;
+
+ if ((n>nAlloc) || (m>mAlloc)) GetMemory();
+ else FreeRecHeap();
+
+ n1 = Initialize ( vertexType,vertexExt );
+ if (n1<=0) return;
+
+ GetRecHeap();
+
+ maxMatch = IMax(1,IMin(n,minMatch));
+ Stop = false;
+ startTime = time(NULL);
+
+ // Use of Backtrack(..) and Ullman() is completely
+ // equivalent. One of them should be commented.
+
+ if (minMatch<n) {
+
+ if (n1>=minMatch) Backtrack1 ( 1,n1 );
+
+ } else if (n1>=n) {
+
+ #ifdef _UseRecursion
+ Backtrack ( 1 );
+ #else
+ Ullman();
+ #endif
+
+ }
+
+ }
+
+
+ int GraphMatch::Initialize ( bool vertexType, int vertexExt ) {
+ ivector jF1;
+ int i,j,v1type,v1type_ext,v2type_ext,almask,iW,pl;
+
+ wasFullMatch = false;
+
+ jF1 = iF1[1];
+ for (i=1;i<=n;i++)
+ jF1[i] = i;
+
+ almask = ~ATOM_LEAVING;
+
+ /* -- experiment for symmetry reliefs
+ int v2type,v1type_sr,srmask;
+ srmask = ~SYMREL_MASK;
+
+ for (i=1;i<=n;i++) {
+ if (vertexType) {
+ ix[i] = 0;
+ v1type = V1[i-1]->type & almask;
+ v1type_sr = v1type & srmask;
+ pl = 0;
+ for (j=1;j<=m;j++) {
+ v2type = V2[j-1]->type & almask;
+ if ((v1type==v2type) ||
+ (v1type_sr==v2type) ||
+ (v1type==(v2type & srmask)))
+ P[1][i][++pl] = j;
+ }
+ P[1][i][0] = pl;
+ if (pl) ix[i] = i;
+ } else {
+ ix[i] = i;
+ for (j=1;j<=m;j++)
+ P[1][i][j] = j;
+ P[1][i][0] = m;
+ }
+ F1[i] = 0;
+ F2[i] = 0;
+ }
+ */
+
+ for (i=1;i<=n;i++) {
+ ix[i] = 0;
+ v1type = V1[i-1]->type & almask;
+ v1type_ext = V1[i-1]->type_ext;
+ pl = 0;
+ for (j=1;j<=m;j++)
+ if ((v1type==(V2[j-1]->type & almask)) || (!vertexType)) {
+ if (vertexExt==EXTTYPE_Ignore)
+ P[1][i][++pl] = j;
+ else {
+ v2type_ext = V2[j-1]->type_ext;
+ if ((!v1type_ext) && (!v2type_ext))
+ P[1][i][++pl] = j;
+ else
+ switch (vertexExt) {
+ default :
+ case EXTTYPE_Ignore : P[1][i][++pl] = j;
+ break;
+ case EXTTYPE_Equal : if (v1type_ext==v2type_ext)
+ P[1][i][++pl] = j;
+ break;
+ case EXTTYPE_AND : if (v1type_ext & v2type_ext)
+ P[1][i][++pl] = j;
+ break;
+ case EXTTYPE_OR : if (v1type_ext | v2type_ext)
+ P[1][i][++pl] = j;
+ break;
+ case EXTTYPE_XOR : if (v1type_ext ^ v2type_ext)
+ P[1][i][++pl] = j;
+ break;
+ case EXTTYPE_NotEqual : if (v1type_ext!=v2type_ext)
+ P[1][i][++pl] = j;
+ break;
+ case EXTTYPE_NotAND : if ((v1type_ext & v2type_ext)
+ ==0)
+ P[1][i][++pl] = j;
+ break;
+ case EXTTYPE_NotOR : if ((v1type_ext | v2type_ext)
+ ==0)
+ P[1][i][++pl] = j;
+ }
+ }
+ }
+ P[1][i][0] = pl;
+ if (pl) ix[i] = i;
+ F1[i] = 0;
+ F2[i] = 0;
+ }
+ /*
+ } else {
+ for (i=1;i<=n;i++) {
+ ix[i] = i;
+ for (j=1;j<=m;j++)
+ P[1][i][j] = j;
+ P[1][i][0] = m;
+ F1[i] = 0;
+ F2[i] = 0;
+ }
+ }
+ */
+
+ i = 1;
+ j = n;
+ while (i<j)
+ if (ix[j]==0) // make sure that j points on a true-containing
+ j--; // row of P[1]
+ else {
+ if (ix[i]==0) { // swap lower empty row of P[1]
+ iW = ix[i]; // with the lth one, which
+ ix[i] = ix[j]; // is surely not empty
+ ix[j] = iW;
+ iW = jF1[i];
+ jF1[i] = jF1[j];
+ jF1[j] = iW;
+ }
+ i++;
+ }
+
+ if (ix[i]==0) return i-1;
+ else return i;
+
+ }
+
+
+ #ifdef _UseRecursion
+
+ void GraphMatch::Backtrack ( int i ) {
+ // Recursive version of Ullman's algorithm for exact
+ // (structure-to-structure or substructure-to-structure)
+ // GMatching
+ int i1,pli,cntj,j,k,pl1,pl2,cntl,l,c1ik;
+ ivector c1i,c2j;
+ ivector p1,p2;
+
+ if (Stop) return;
+ if (timeLimit>0)
+ Stop = (difftime(time(NULL),startTime)>timeLimit);
+
+ F1[i] = i;
+ pli = P[i][i][0];
+
+ if (i>=n) {
+
+ for (cntj=1;(cntj<=pli) && (!Stop);cntj++) {
+ F2[n] = P[n][n][cntj];
+ CollectMatch ( n );
+ }
+
+ } else {
+
+ i1 = i+1;
+ c1i = c1[i];
+
+ for (cntj=1;(cntj<=pli) && (!Stop);cntj++) {
+ j = P[i][i][cntj];
+ F2[i] = j; // mapped F1[i]:F2[i], i.e. i:j
+ // Forward checking
+ c2j = c2[j];
+ pl2 = 1;
+ for (k=i1;(k<=n) && (pl2>0);k++) {
+ p1 = P[i][k];
+ p2 = P[i1][k];
+ c1ik = c1i[k];
+ pl1 = p1[0];
+ pl2 = 0;
+ for (cntl=1;cntl<=pl1;cntl++) {
+ l = p1[cntl];
+ if ((c1ik==c2j[l]) && // check that bonds are compatible
+ (l!=j)) // and make sure jth vertex is excluded
+ p2[++pl2] = l;
+ }
+ p2[0] = pl2; // new length of P-row
+ }
+ if (pl2>0) Backtrack ( i1 );
+ }
+
+ }
+
+ }
+
+ #else
+
+ void GraphMatch::Ullman() {
+ // A non-recursive translation of Ullman's Backtrack.
+ // It might give some gain in performance, although tests
+ // on SGI machine show that the gain is negligible, (if
+ // there is any at all) if compiler's optimization is
+ // switched on.
+ int i,pl,i1,pli,cntj,j,pl1,pl2,k,cntl,l,l1,cik;
+ ivector ci,cj;
+ ivector p1,p2;
+
+ if (Stop) return;
+ if (timeLimit>0)
+ Stop = (difftime(time(NULL),startTime)>timeLimit);
+
+ i = 1;
+ jj[1] = 1;
+ pl = P[1][1][0];
+
+ do {
+
+ F1[i] = i;
+ pli = P[i][i][0];
+
+ if (i>=n) {
+
+ for (cntj=jj[n];(cntj<=pli) && (!Stop);cntj++) {
+ jj[n]++;
+ F2[n] = P[n][n][cntj];
+ CollectGMatch ( n );
+ }
+
+ } else {
+
+ i1 = i+1;
+ ci = c1[i];
+ for (cntj=jj[i];(cntj<=pli) && (!Stop);cntj++) {
+ jj[i]++;
+ j = P[i][i][cntj];
+ F2[i] = j;
+ // Forward checking
+ cj = c2[j];
+ pl2 = 1;
+ for (k=i1;(k<=n) && (pl2>0);k++) {
+ p1 = P[i][k];
+ p2 = P[i1][k];
+ cik = ci[k];
+ pl1 = p1[0];
+ pl2 = 0;
+ for (cntl=1;cntl<=pl1;cntl++) {
+ l = p1[cntl];
+ if ((cik==cj[l]) && // check that bonds are compatible
+ (l!=j)) // and make sure jth vertex is excluded
+ p2[++pl2] = l;
+ }
+ p2[0] = pl2; // new length of P-row
+ }
+ if (pl2>0) {
+ i++;
+ jj[i] = 1;
+ i++; // in order to compensate the following decrement
+ break;
+ }
+ }
+
+ }
+ i--;
+
+ } while ((!Stop) && ((jj[1]<=pl) || (i>1)));
+
+ }
+
+ #endif
+
+ void GraphMatch::Backtrack1 ( int i, int k0 ) {
+ // Recursive version of CSIA algorithm for partial
+ // (substructure-to-substructure) GMatching
+ int i1,pl0,cntj,j,k,pl1,pl2,cntl,l,c1ik,ii,iW,k1;
+ ivector jF1,c1i,c2j;
+ ivector p0,p1,p2;
+
+ if (Stop) return;
+ if (timeLimit>0)
+ Stop = (difftime(time(NULL),startTime)>timeLimit);
+
+ jF1 = iF1[i];
+
+ if (i>=k0) {
+
+ F1[i] = jF1[i];
+ p0 = P[i][jF1[i]];
+ pl0 = p0[0];
+
+ // collect GMatches of k0-th (the upmost) level
+ if (pl0>0) {
+ maxMatch = k0;
+ for (cntj=1;cntj<=pl0;cntj++) {
+ F2[k0] = p0[cntj];
+ CollectMatch ( k0 );
+ }
+ }
+
+ } else {
+
+ i1 = i+1;
+
+ pl0 = P[i][jF1[i]][0];
+ j = i;
+ for (k=i1;k<=k0;k++)
+ if (P[i][jF1[k]][0]<pl0) {
+ pl0 = P[i][jF1[k]][0];
+ j = k;
+ }
+ if (j>i) {
+ iW = jF1[i];
+ jF1[i] = jF1[j];
+ jF1[j] = iW;
+ }
+
+ F1[i] = jF1[i];
+ p0 = P[i][jF1[i]];
+ pl0 = p0[0];
+
+ c1i = c1[jF1[i]];
+
+ // 1. Find all GMatches that include jF1[i]th vertex of graph G1
+
+ for (cntj=1;(cntj<=pl0) && (!Stop);cntj++) {
+ j = p0[cntj];
+ F2[i] = j; // mapped F1[i]:F2[i], i.e. iF1[i][i]:j
+ // Forward checking
+ c2j = c2[j];
+ k1 = k0; // k1 is the limit for GMatch size
+ for (k=i1;(k<=k0) && (k1>=maxMatch);k++) {
+ ix[k] = 0;
+ p1 = P[i] [jF1[k]];
+ p2 = P[i1][jF1[k]];
+ c1ik = c1i [jF1[k]];
+ pl1 = p1[0];
+ pl2 = 0;
+ for (cntl=1;cntl<=pl1;cntl++) {
+ l = p1[cntl];
+ if ((c1ik==c2j[l]) && // check that bonds are compatible
+ (l!=j)) // and make sure jth vertex is excluded
+ p2[++pl2] = l;
+ }
+ p2[0] = pl2; // new length of P-row
+ if (pl2>0) {
+ ix[k] = k;
+ } else if (wasFullMatch) {
+ k1 = maxMatch-1; // we are not interested in partial
+ } else { // GMatch anymore
+ k1--;
+ }
+ }
+ if (k1>=maxMatch) {
+ // shift unGMatching vertices to the end
+ for (ii=1;ii<=n;ii++)
+ iF1[i1][ii] = jF1[ii];
+ k = i1;
+ l = k0;
+ while (k<l)
+ if (ix[l]==0) // make sure that l points on a true-containing
+ l--; // row of P[i1]
+ else {
+ if (ix[k]==0) { // swap lower empty row of P[i1]
+ iW = ix[k]; // with the lth one, which
+ ix[k] = ix[l]; // is surely not empty
+ ix[l] = iW;
+ iW = iF1[i1][k];
+ iF1[i1][k] = iF1[i1][l];
+ iF1[i1][l] = iW;
+ }
+ k++;
+ }
+ if (ix[i1]) Backtrack1 ( i1,k1 );
+ else if (i>=maxMatch) {
+ CollectMatch ( i ); // collect GMatch of ith level
+ maxMatch = i;
+ }
+ }
+ }
+
+ // 2. Find all GMatches that do not include jF1[i]th vertex
+ // of graph G1
+
+ if (k0>maxMatch) {
+ // Shift jF1[i]th vertex to the end
+ iW = jF1[i];
+ jF1[i] = jF1[k0];
+ jF1[k0] = iW;
+ Backtrack1 ( i,k0-1 );
+ }
+
+ }
+
+ }
+
+
+ void GraphMatch::CollectMatch ( int nm ) {
+ int i;
+ bool B;
+ PPGMatch M1;
+
+ if (maxNMatches==0) return;
+
+ // find out if this should be a new GMatch
+ if (nMatches>0) {
+ // a GMatch is already found; check with it
+ if (nm<Match[0]->mlength) return;
+ if (nm>Match[0]->mlength) {
+ nMatches = 0;
+ } else if (flags & GMF_UniqueMatch) {
+ // check if such a GMatch was already found
+ B = false;
+ for (i=0;(i<nMatches) && (!B);i++)
+ B = Match[i]->isMatch(F1,F2,nm);
+ if (B) return; // repeating GMatch -- just quit.
+ } else if (flags & GMF_NoCombinations) {
+ // check if such a GMatch was already found
+ B = false;
+ for (i=0;(i<nMatches) && (!B);i++)
+ B = Match[i]->isCombination(F1,F2,nm);
+ if (B) return; // repeating GMatch -- just quit.
+ }
+ }
+
+ if (nMatches>=nMAlloc) {
+ if ((nMAlloc<maxNMatches) || (maxNMatches<=0)) {
+ if (maxNMatches>0) nMAlloc = IMin(maxNMatches,nMAlloc+100);
+ else nMAlloc += 100;
+ M1 = new PGMatch[nMAlloc];
+ for (i=0;i<nMatches;i++)
+ M1[i] = Match[i];
+ for (i=nMatches;i<nMAlloc;i++)
+ M1[i] = NULL;
+ if (Match) delete[] Match;
+ Match = M1;
+ } else
+ nMatches--;
+ }
+
+ if (!Match[nMatches])
+ Match[nMatches] = new GMatch ( F1,F2,nm,n,m );
+ else Match[nMatches]->SetMatch ( F1,F2,nm,n,m );
+
+ if (nm==n) wasFullMatch = true;
+
+ if (nm>maxMatch) maxMatch = nm;
+
+ nMatches++;
+
+ if (stopOnMaxNMathches && (maxNMatches>0) &&
+ (nMatches>=maxNMatches))
+ Stop = true;
+
+ }
+
+ void GraphMatch::PrintMatches() {
+ int i,j,k;
+ if (nMatches<=0)
+ printf ( "\n\n *** NO GMatchES FOUND\n\n" );
+ else {
+ if (flags & GMF_UniqueMatch)
+ printf ( "\n\n *** FOUND Unique GMatches\n\n" );
+ else printf ( "\n\n *** FOUND GMatches\n\n" );
+ printf ( " ## Vertices\n" );
+ for (i=0;i<nMatches;i++) {
+ printf ( " %5i ",i+1 );
+ k = 8;
+ for (j=1;j<=Match[i]->mlength;j++) {
+ if (swap)
+ printf ( " (%i,%i)",Match[i]->F2[j],Match[i]->F1[j] );
+ else printf ( " (%i,%i)",Match[i]->F1[j],Match[i]->F2[j] );
+ k += 8;
+ if (k>70) {
+ printf ( "\n" );
+ k = 8;
+ }
+ }
+ printf ( "\n" );
+ }
+ }
+ printf ( "\n **************************\n" );
+ }
+
+ void GraphMatch::GetMatch ( int MatchNo, ivector & FV1,
+ ivector & FV2, int & nv,
+ realtype & p1, realtype & p2 ) {
+ // do not allocate or dispose FV1 and FV2 in application!
+ // FV1/p1 will always correspond to Gh1, and FV2/p2 -
+ // to Gh2 as specified in GMatchGraphs(..)
+ if ((MatchNo<0) || (MatchNo>=nMatches)) {
+ FV1 = NULL;
+ FV2 = NULL;
+ nv = 0;
+ p1 = 0.0;
+ p2 = 0.0;
+ } else if (swap)
+ Match[MatchNo]->GetMatch ( FV2,FV1,nv,p2,p1 );
+ else Match[MatchNo]->GetMatch ( FV1,FV2,nv,p1,p2 );
+
+ }
+
+
+ void GraphMatch::write ( io::RFile f ) {
+ int i;
+ int Version=1;
+ f.WriteInt ( &Version );
+ f.WriteInt ( &nMatches );
+ f.WriteWord ( &flags );
+ f.WriteBool ( &swap );
+ for (i=0;i<nMatches;i++)
+ Match[i]->write ( f );
+ }
+
+ void GraphMatch::read ( io::RFile f ) {
+ int i,Version;
+ FreeMemory ();
+ f.ReadInt ( &Version );
+ f.ReadInt ( &nMatches );
+ f.ReadWord ( &flags );
+ f.ReadBool ( &swap );
+ if (nMatches>0) {
+ nMAlloc = nMatches;
+ Match = new PGMatch[nMatches];
+ for (i=0;i<nMatches;i++) {
+ Match[i] = new GMatch();
+ Match[i]->read ( f );
+ }
+ }
+ }
+
+
+ void GraphMatch::mem_write ( pstr S, int & l ) {
+ int i;
+ mmdb::mem_write ( nMatches,S,l );
+ mmdb::mem_write ( flags ,S,l );
+ mmdb::mem_write ( swap ,S,l );
+ for (i=0;i<nMatches;i++)
+ Match[i]->mem_write ( S,l );
+ }
+
+ void GraphMatch::mem_read ( cpstr S, int & l ) {
+ int i;
+ FreeMemory ();
+ mmdb::mem_read ( nMatches,S,l );
+ mmdb::mem_read ( flags ,S,l );
+ mmdb::mem_read ( swap ,S,l );
+ if (nMatches>0) {
+ nMAlloc = nMatches;
+ Match = new PGMatch[nMatches];
+ for (i=0;i<nMatches;i++) {
+ Match[i] = new GMatch();
+ Match[i]->mem_read ( S,l );
+ }
+ }
+ }
+
+ MakeStreamFunctions(GraphMatch)
+
+
+ } // namespace math
+
+} // namespace mmdb
+
+
+// =============================================================
+
+/*
+static char Mol1[][3] = {
+ "C", "C", "C", "C", "C", "C" };
+
+static int Bond1[] = {
+ 1, 2,
+ 1, 6,
+ 2, 3,
+ 3, 4,
+ 4, 5,
+ 5, 6
+};
+
+static char Mol2[][3] = {
+ "C", "C", "C", "C", "C", "C",
+ "C", "C", "C", "C", "C", "C" };
+
+static int Bond2[] = {
+ 1, 2,
+ 1, 6,
+ 2, 3,
+ 3, 4,
+ 4, 5,
+ 5, 6,
+ 1, 7,
+ 2, 8,
+ 3, 9,
+ 4, 10,
+ 5, 11,
+ 6, 12
+};
+
+
+static char Mol1[][3] = {
+ "C", "C", "N", "C" };
+
+static int Bond1[] = {
+ 1, 2,
+ 2, 3,
+ 3, 4
+};
+
+static char Mol2[][3] = {
+ "C", "C", "N", "C" };
+
+static int Bond2[] = {
+ 1, 2,
+ 2, 3,
+ 2, 4,
+ 3, 4
+};
+
+void TestGraphMatch() {
+int i,k1,k2, nv1,nb1, nv2,nb2;
+PVertex V;
+PEdge G;
+Graph G1,G2;
+GraphMatch U;
+
+ G1.Reset ();
+ G1.SetName ( "#1" );
+
+ nv1 = sizeof(Mol1)/3;
+ for (i=0;i<nv1;i++) {
+ V = new Vertex();
+ V->SetVertex ( Mol1[i] );
+ G1.AddVertex ( V );
+ }
+ nb1 = sizeof(Bond1)/(2*sizeof(int));
+ k1 = 0;
+ k2 = 1;
+ for (i=0;i<nb1;i++) {
+ G = new Edge();
+ G->SetEdge ( Bond1[k1],Bond1[k2],1 );
+ G1.AddEdge ( G );
+ k1 += 2;
+ k2 += 2;
+ }
+
+ G2.Reset ();
+ G2.SetName ( "#2" );
+
+ nv2 = sizeof(Mol2)/3;
+ for (i=0;i<nv2;i++) {
+ V = new Vertex();
+ V->SetVertex ( Mol2[i] );
+ G2.AddVertex ( V );
+ }
+ nb2 = sizeof(Bond2)/(2*sizeof(int));
+ k1 = 0;
+ k2 = 1;
+ for (i=0;i<nb2;i++) {
+ G = new Edge();
+ G->SetEdge ( Bond2[k1],Bond2[k2],1 );
+ G2.AddEdge ( G );
+ k1 += 2;
+ k2 += 2;
+ }
+
+ G1.Build();
+ G2.Build();
+
+ U.GMatchGraphs ( &G1,&G2,nv1 );
+
+ U.PrintGMatches();
+
+
+}
+*/
+
diff --git a/mmdb2/mmdb_math_graph.h b/mmdb2/mmdb_math_graph.h
new file mode 100644
index 0000000..f30625f
--- /dev/null
+++ b/mmdb2/mmdb_math_graph.h
@@ -0,0 +1,494 @@
+// $Id: mmdb_math_graph.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_math_graph <interface>
+// ~~~~~~~~~
+// **** Namespace: mmdb::math::
+// ~~~~~~~~~~
+// **** Classes : Vertex ( graph vertex )
+// ~~~~~~~~~ Edge ( graph edge )
+// Graph ( structural graph )
+// Match ( match of structural graphs )
+// GraphMatch ( CSIA algorithms for graphs matching )
+//
+// (C) E. Krissinel 2000-2013
+//
+// When used, please cite:
+//
+// Krissinel, E. and Henrick, K. (2004)
+// Common subgraph isomorphism detection by backtracking search.
+// Software - Practice and Experience, 34, 591-607.
+//
+// =================================================================
+//
+
+#ifndef __MMDB_MATH_Graph__
+#define __MMDB_MATH_Graph__
+
+#include <time.h>
+
+#include "mmdb_atom.h"
+
+namespace mmdb {
+
+ namespace math {
+
+ // ========================= Vertex ==========================
+
+ DefineClass(Vertex);
+
+ enum GRAPH_FLAG {
+ CHIRAL_RIGHT = 0x10000000,
+ CHIRAL_LEFT = 0x20000000,
+ ATOM_LEAVING = 0x40000000,
+ HYDROGEN_BOND = 0x0F000000,
+ SYMREL_MASK = 0x00FF0000,
+ CHIRAL_MASK = 0xCFFFFFFF,
+ TYPE_MASK = 0x00FFFFFF
+ };
+
+ class Vertex : public io::Stream {
+
+ friend class Graph;
+ friend class GraphMatch;
+
+ public:
+
+ Vertex ();
+ Vertex ( io::RPStream Object );
+ Vertex ( int vtype, cpstr vname );
+ Vertex ( int vtype );
+ Vertex ( cpstr chem_elem );
+ Vertex ( cpstr chem_elem, cpstr name );
+ ~Vertex();
+
+ void SetVertex ( cpstr chem_elem );
+ void SetVertex ( int vtype, cpstr vname );
+ void SetVertex ( int vtype );
+ void SetType ( int vtype );
+ void SetTypeExt ( int typeExt );
+
+ void RemoveChirality();
+ void LeaveChirality ( int eltype );
+
+ void SetName ( cpstr vname );
+ void SetProperty ( int vprop );
+ void SetID ( int vid );
+ void AddBond ();
+ void CopyNBonds ( PVertex V );
+ inline void SetUserID ( int vid ) { user_id = vid; }
+ inline int GetProperty () { return property; }
+ inline int GetID () { return id; }
+ inline int GetUserID () { return user_id; }
+ inline cpstr GetName () { return name; }
+ inline int GetType () { return type; }
+ inline int GetTypeExt () { return type_ext; }
+ int GetNBonds ();
+
+ void SaveType (); // in userid
+ void RestoreType (); // from userid
+ void CopyType ( PVertex V );
+
+ virtual void Print ( int PKey );
+
+ virtual void Copy ( PVertex V );
+
+ void read ( io::RFile f );
+ void write ( io::RFile f );
+
+ void mem_read ( cpstr S, int & l );
+ void mem_write ( pstr S, int & l );
+
+ protected:
+ pstr name; // name may be general, "C", "Hg", "Cl" etc.
+ int type; // type of vertex, see comments in
+ // mmdb_math_graph.cpp
+ int type_ext; // vertex type extention
+ int property; // flagwise properties -- user-defined
+ int id; // a graph-defined vertex id
+ int user_id; // a user-defined vertex id
+
+ void InitVertex();
+
+ };
+
+ DefineStreamFunctions(Vertex);
+
+
+ // ========================== Edge ===========================
+
+ enum GRAPH_BOND {
+ BOND_SINGLE = 1,
+ BOND_DOUBLE = 2,
+ BOND_AROMATIC = 3,
+ BOND_TRIPLE = 4
+ };
+
+ DefineClass(Edge);
+
+ class Edge : public io::Stream {
+
+ friend class Graph;
+ friend class CGMatch;
+
+ public:
+
+ Edge ();
+ Edge ( io::RPStream Object );
+ Edge ( int vx1, int vx2, int btype ); // vx1,vx2 are numbered
+ // as 1,2,3 on and refer
+ // to vertices in the order
+ // as they were added to
+ // the graph; btype>0
+ ~Edge();
+
+ void SetEdge ( int vx1, int vx2, cpstr btype );
+ void SetEdge ( int vx1, int vx2, int btype ); // btype>0
+
+ void SetType ( int btype );
+ void SetProperty ( int eprop );
+ void SaveType (); // in property
+ void RestoreType (); // from property
+
+ inline int GetVertex1 () { return v1; }
+ inline int GetVertex2 () { return v2; }
+ inline int GetType () { return type; }
+ inline int GetProperty () { return property; }
+
+ virtual void Print ( int PKey );
+
+ virtual void Copy ( PEdge G );
+
+ void read ( io::RFile f );
+ void write ( io::RFile f );
+
+ void mem_read ( cpstr S, int & l );
+ void mem_write ( pstr S, int & l );
+
+ protected:
+ int v1,v2; // >=1
+ int type;
+ int property;
+
+ void InitEdge();
+
+ };
+
+ DefineStreamFunctions(Edge);
+
+
+ // ========================== Graph ============================
+
+ enum GRAPH_RC {
+ MKGRAPH_Ok = 0,
+ MKGRAPH_NoAtoms = -1,
+ MKGRAPH_ChangedAltLoc = 1,
+ MKGRAPH_MaxOccupancy = 2
+ };
+
+ DefineClass(Graph);
+
+ class Graph : public io::Stream {
+
+ friend class GraphMatch;
+ friend class CSBase0;
+
+ public :
+
+ Graph ();
+ Graph ( PResidue R, cpstr altLoc=NULL );
+ Graph ( io::RPStream Object );
+ ~Graph();
+
+ void Reset ();
+ void SetName ( cpstr gname );
+ inline pstr GetName() { return name; }
+
+ // AddVertex(..) and AddEdge(..) do not copy the objects, but
+ // take them over. This means that application should forget
+ // about pointers to V and G once they were given to Graph.
+ // Vertices and edges must be allocated newly prior each call
+ // to AddVertex(..) and AddEdge(..).
+ void AddVertex ( PVertex V );
+ void AddEdge ( PEdge G );
+ void SetVertices ( PPVertex V, int vlen );
+ void SetEdges ( PPEdge G, int glen );
+
+ void RemoveChirality();
+ void LeaveChirality ( int eltype );
+
+ // MakeGraph(..) makes a graph corresponding to residue R.
+ // The graphs vertices then correspond to the residue's atoms
+ // (Vertex::userid points to atom R->atom[Vertex::userid]),
+ // edges are calculated as chemical bonds between atoms basing
+ // on the table of cut-off distances.
+ // altCode specifies a particular conformation that should be
+ // used for making the graph. If it is set to "" or NULL ("empty"
+ // altcode) but the residue does not have conformation which
+ // contains *only* ""-altcode atoms, a conformation corresponding
+ // to maximal occupancy will be used. The same will happen if
+ // altcode information in residue is not correct, whatever altCode
+ // is specified.
+ // After making the graph, Build(..) should be called as usual
+ // before graph matching.
+ // Non-negative return means that graph has been made.
+ // MakeGraph(..) may return:
+ // MKGRAPH_Ok everything is Ok
+ // MKGRAPH_NoAtoms residue does not have atoms, graph
+ // is not made
+ // MKGRAPH_ChangedAltLoc a different altcode was used because
+ // the residue has only one altcode and
+ // that is different of
+ // MKGRAPH_MaxOccupancy a maximal-occupancy conformation has
+ // been chosen because of default
+ // ""-altcode supplied or incorrect
+ // altcode information in the residue
+ int MakeGraph ( PResidue R, cpstr altLoc=NULL );
+
+ int MakeGraph ( PPAtom atom, int nAtoms );
+
+ void HideType ( int bond_vx_type );
+ void ExcludeType ( int type );
+
+ void MakeSymmetryRelief ( bool noCO2 );
+ void IdentifyRings ();
+ int IdentifyConnectedComponents(); // returns their number >= 1
+
+ int Build ( bool bondOrder ); // returns 0 if Ok
+
+ void MakeVertexIDs (); // simply numbers vertices as 1.. on
+ int GetVertexID ( int vertexNo );
+ int GetVertexNo ( cpstr vname );
+ // GetBondedVertexID(..) works after MoveType(..)
+ int GetNBondedVertices ( int vertexNo );
+ int GetBondedVertexID ( int vertexNo, int bond_vx_type,
+ int bondNo );
+
+ PVertex GetVertex ( int vertexNo ); // 1<=vertexNo<=nVertices
+ inline int GetNofVertices() { return nVertices; }
+
+ PEdge GetEdge ( int edgeNo ); // 1<=edgeNo<=nEdges
+ inline int GetNofEdges() { return nEdges; }
+
+ void GetVertices ( PPVertex & V, int & nV );
+ void GetEdges ( PPEdge & E, int & nE );
+
+ virtual void Print();
+ void Print1();
+
+ virtual void Copy ( PGraph G );
+
+ void read ( io::RFile f );
+ void write ( io::RFile f );
+
+ void mem_read ( cpstr S, int & l );
+ void mem_write ( pstr S, int & l );
+
+ protected :
+ pstr name;
+ int nVertices,nEdges, nAllVertices,nAllEdges;
+ PPVertex vertex;
+ PPEdge edge;
+ imatrix graph;
+
+ void InitGraph ();
+ void FreeMemory();
+
+ void markConnected ( int vno, int cno );
+
+ private :
+ int nVAlloc,nEAlloc,nGAlloc;
+
+ };
+
+ DefineStreamFunctions(Graph);
+
+
+ // ========================= GMatch ==========================
+
+ DefineClass(GMatch);
+ DefineStreamFunctions(GMatch);
+
+ class GMatch : public io::Stream {
+
+ friend class GraphMatch;
+
+ public :
+
+ GMatch ();
+ GMatch ( io::RPStream Object );
+ GMatch ( ivector FV1, ivector FV2, int nv, int n, int m );
+ ~GMatch();
+
+ // FV1[] and FV2[] are copied into internal buffers
+ void SetMatch ( ivector FV1, ivector FV2, int nv, int n, int m );
+
+ bool isMatch ( ivector FV1, ivector FV2, int nv );
+ bool isCombination ( ivector FV1, ivector FV2, int nv );
+
+ // do not allocate or dispose FV1 and FV2 in application!
+ void GetMatch ( ivector & FV1, ivector & FV2, int & nv,
+ realtype & p1, realtype & p2 );
+
+ void read ( io::RFile f );
+ void write ( io::RFile f );
+
+ void mem_read ( cpstr S, int & l );
+ void mem_write ( pstr S, int & l );
+
+ protected :
+ int n1,n2,mlength;
+ ivector F1,F2;
+
+ void InitGMatch();
+
+ private :
+ int nAlloc;
+
+ };
+
+
+ // ======================= GraphMatch =========================
+
+ #define _UseRecursion
+
+ enum GRAPH_MATCH_FLAG {
+ GMF_UniqueMatch = 0x00000001,
+ GMF_NoCombinations = 0x00000002
+ };
+
+ enum VERTEX_EXT_TYPE {
+ EXTTYPE_Ignore = 0,
+ EXTTYPE_Equal = 1,
+ EXTTYPE_AND = 2,
+ EXTTYPE_OR = 3,
+ EXTTYPE_XOR = 4,
+ EXTTYPE_NotEqual = 5,
+ EXTTYPE_NotAND = 6,
+ EXTTYPE_NotOR = 7
+ };
+
+ DefineClass(GraphMatch);
+
+ class GraphMatch : public io::Stream {
+
+ public :
+
+ GraphMatch ();
+ GraphMatch ( io::RPStream Object );
+ ~GraphMatch();
+
+ void SetFlag ( word flag );
+ void RemoveFlag ( word flag );
+ void SetMaxNofMatches ( int maxNofMatches, bool stopOnMaxN );
+ void SetTimeLimit ( int maxTimeToRun=0 );
+ inline bool GetStopSignal() { return Stop; }
+
+ void Reset();
+
+ // MatchGraphs looks for maximal common subgraphs of size
+ // not less than minMatch. The number of found subgraphs
+ // is returned by GetNofMatches(), the subgraph vertices
+ // are returned by GetMatch(..). Control parameters:
+ // vertexType true if vertex type should be taken
+ // into account and False otherwise
+ // vertexExt key to use extended vertex types (defined
+ // as type_ext in Vertex).
+ void MatchGraphs ( PGraph Gh1, PGraph Gh2, int minMatch,
+ bool vertexType=true,
+ VERTEX_EXT_TYPE vertexExt=EXTTYPE_Ignore );
+ void PrintMatches ();
+ inline int GetNofMatches () { return nMatches; }
+ inline int GetMaxMatchSize() { return maxMatch; }
+
+ // do not allocate or dispose FV1 and FV2 in application!
+ // FV1/p1 will always correspond to Gh1, and FV2/p2 -
+ // to Gh2 as specified in MatchGraphs(..)
+ void GetMatch ( int MatchNo, ivector & FV1, ivector & FV2,
+ int & nv, realtype & p1, realtype & p2 );
+
+ void read ( io::RFile f );
+ void write ( io::RFile f );
+
+ void mem_read ( cpstr S, int & l );
+ void mem_write ( pstr S, int & l );
+
+ protected :
+ PGraph G1,G2;
+ PPVertex V1;
+ PPVertex V2;
+ imatrix c1,c2;
+ bool swap;
+ #ifndef _UseRecursion
+ ivector jj;
+ #endif
+ int n,m;
+
+ imatrix3 P;
+ imatrix iF1;
+ ivector F1,F2,ix;
+
+ int nMatches,maxNMatches;
+ PPGMatch Match;
+ bool wasFullMatch,Stop,stopOnMaxNMathches;
+ word flags;
+ int maxMatch,timeLimit;
+
+ void InitGraphMatch();
+ void FreeMemory ();
+ void FreeRecHeap ();
+ void GetMemory ();
+ void GetRecHeap ();
+ int Initialize ( bool vertexType, int vertexExt );
+ #ifdef _UseRecursion
+ void Backtrack ( int i ); // exact matching
+ #else
+ void Ullman ();
+ #endif
+ void Backtrack1 ( int i, int k0 ); // exact/partial matching
+ void CollectMatch ( int nm );
+
+ private :
+ int nAlloc,mAlloc,nMAlloc;
+ time_t startTime;
+
+ };
+
+ DefineStreamFunctions(GraphMatch);
+
+ extern void SetGraphAllocPortion ( int alloc_portion );
+
+ /*
+ extern void TestGraphMatch();
+ */
+
+ } // namespace math
+
+} // namespace mmdb
+
+#endif
diff --git a/mmdb2/mmdb_math_linalg.cpp b/mmdb2/mmdb_math_linalg.cpp
new file mode 100644
index 0000000..3709101
--- /dev/null
+++ b/mmdb2/mmdb_math_linalg.cpp
@@ -0,0 +1,990 @@
+// $Id: mmdb_math_linalg.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : LinAlg <implementation>
+// ~~~~~~~~~
+// **** Project : MMDB ( MacroMolecular Data Base )
+// ~~~~~~~~~
+//
+// (C) E.Krissinel 2000-2013
+//
+// =================================================================
+//
+//
+
+#include <stdio.h>
+#include <math.h>
+
+#include "mmdb_math_linalg.h"
+
+namespace mmdb {
+
+ namespace math {
+
+
+ // ========================== Jacobi =============================
+
+
+ void Jacobi ( int N, // dimension of the matrix
+ rmatrix A, // matrix to diagonalize; the lower
+ // triangle, except the diagonal,
+ // will remain unchanged
+ rmatrix T, // eigenvectors placed as columns
+ rvector Eigen, // vector of eigenvalues, orderd
+ // by increasing
+ rvector Aik, // working array
+ int & Signal // 0 <=> Ok, ItMax <=> iteration limit
+ // exchausted.
+ ) {
+ // Diagonalization of symmetric matrices by the method of Jacobi.
+ // Key variables:
+ // ItMax - the maximum available number of iterations
+ // Eps1 - is used in SNA and CSA calculations
+ // Eps2 - is the level of the elimination of the
+ // non-diagonal matrix elements
+ // Eps3 - the criterion to stop the iterations.
+ // The iterations stop if (1-Sigma1/Sigma2)<=Eps3
+ // where Sigma1 is the dekart norm of the eigenvalues
+ // at the preceding iteration and Sigma2 is
+ // the same for the current iteration.
+
+ realtype Eps1,Eps2,Eps3;
+ realtype Sigma1,Sigma2,OffDsq, SPQ,CSA,SNA,Q,P, HoldIK,HoldKI;
+ int ItMax;
+ int i,j,k,Iter;
+
+ Eps1 = 6.0e-9;
+ Eps2 = 9.0e-12;
+ Eps3 = 1.0e-8;
+ ItMax = 9999;
+
+ Signal = 0;
+
+ if (N<=1) {
+ T[1][1] = 1.0;
+ Eigen[1] = A[1][1];
+ return;
+ }
+
+ for (i=1;i<=N;i++) {
+ for (j=1;j<=N;j++)
+ T[i][j] = 0.0;
+ T[i][i] = 1.0;
+ Eigen[i] = A[i][i];
+ }
+
+ Sigma1 = 0.0;
+ OffDsq = 0.0;
+
+ // Sigma1 is the Dekart measure of the diagonal elements
+ // OffDsq is the Dekart measure of the non-diagonal elements
+
+ for (i=1;i<=N;i++) {
+ Sigma1 += A[i][i]*A[i][i];
+ if (i<N)
+ for (j=i+1;j<=N;j++)
+ OffDsq += A[i][j]*A[i][j];
+ }
+
+ if (OffDsq<Eps2*Eps2) return;
+
+ // S = OffDsq*2.0+Sigma1;
+ Iter = 1;
+ HoldIK = 1.0;
+
+ while ((Iter<=ItMax) && (HoldIK>Eps3)) {
+
+ for (i=1;i<N;i++)
+ for (j=i+1;j<=N;j++) {
+
+ Q = fabs(A[i][i]-A[j][j]);
+
+ if ((Q<=Eps1) || (fabs(A[i][j])>Eps2)) {
+ if (Q>Eps1) {
+ P = 2.0*A[i][j]*(Q/(A[i][i]-A[j][j]));
+ SPQ = sqrt(P*P+Q*Q);
+ CSA = sqrt((1.0+Q/SPQ)/2.0);
+ SNA = P/(SPQ*CSA*2.0);
+ } else {
+ CSA = sqrt(0.5);
+ SNA = CSA;
+ }
+ for (k=1;k<=N;k++) {
+ HoldKI = T[k][i];
+ T[k][i] = HoldKI*CSA + T[k][j]*SNA;
+ T[k][j] = HoldKI*SNA - T[k][j]*CSA;
+ }
+
+ for (k=i;k<=N;k++)
+ if (k<=j) {
+ Aik[k] = A[i][k];
+ A[i][k] = CSA*Aik[k] + SNA*A[k][j];
+ if (k==j) {
+ A[j][k] = SNA*Aik[k] - CSA*A[j][k];
+ Aik[j] = SNA*Aik[i] - CSA*Aik[j];
+ }
+ } else {
+ HoldIK = A[i][k];
+ A[i][k] = CSA*HoldIK + SNA*A[j][k];
+ A[j][k] = SNA*HoldIK - CSA*A[j][k];
+ }
+
+ for (k=1;k<=j;k++)
+ if (k>i)
+ A[k][j] = SNA*Aik[k] - CSA*A[k][j];
+ else {
+ HoldKI = A[k][i];
+ A[k][i] = CSA*HoldKI + SNA*A[k][j];
+ A[k][j] = SNA*HoldKI - CSA*A[k][j];
+ }
+
+ }
+
+ }
+
+ Sigma2 = 0.0;
+ for (i=1;i<=N;i++) {
+ Eigen[i] = A[i][i];
+ Sigma2 += Eigen[i]*Eigen[i];
+ }
+
+ HoldIK = fabs(1.0-Sigma1/Sigma2);
+ Sigma1 = Sigma2;
+ Iter++;
+
+ }
+
+ if (Iter>ItMax) Signal = ItMax;
+
+ for (i=1;i<=N;i++) {
+ k = i;
+ for (j=i;j<=N;j++)
+ if (Eigen[j]<Eigen[k]) k = j;
+ if (k!=i) {
+ P = Eigen[k];
+ Eigen[k] = Eigen[i];
+ Eigen[i] = P;
+ for (j=1;j<=N;j++) {
+ P = T[j][k];
+ T[j][k] = T[j][i];
+ T[j][i] = P;
+ }
+ }
+ }
+
+
+ }
+
+
+ // -----------------------------------------------------
+
+ void PbCholDecomp ( int N,
+ rvector HDiag,
+ realtype MaxOff,
+ realtype MachEps,
+ rmatrix L,
+ realtype & MaxAdd ) {
+
+ // A5.5.2 : Perturbed Cholesky Decomposition
+ // Part of the modular software system from
+ // the appendix of the book "Numerical Methods for Unconstrained
+ // Optimization and Nonlinear Equations" by Dennis & Schnabel 1983.
+
+ int i,j,k;
+ realtype MinL,MinL2,S,MinLjj,MaxOffl, BB;
+
+ MaxOffl = MaxOff;
+ MinL = sqrt(sqrt(MachEps))*MaxOffl;
+ if (MaxOffl==0.0) {
+ for (i=1;i<=N;i++) {
+ BB = fabs(HDiag[i]);
+ if (BB>MaxOffl) MaxOffl = BB;
+ }
+ MaxOffl = sqrt(MaxOffl);
+ }
+
+ MinL2 = sqrt(MachEps)*MaxOffl;
+ MaxAdd = 0.0;
+ for (j=1;j<=N;j++) {
+ S = 0.0;
+ if (j>1)
+ for (i=1;i<j;i++)
+ S += L[j][i]*L[j][i];
+ L[j][j] = HDiag[j] - S;
+ MinLjj = 0.0;
+ if (j<N)
+ for (i=j+1;i<=N;i++) {
+ S = 0.0;
+ if (j>1)
+ for (k=1;k<j;k++)
+ S += L[i][k]*L[j][k];
+ L[i][j] = L[j][i] - S;
+ BB = fabs(L[i][j]);
+ if (BB>MinLjj) MinLjj = BB;
+ }
+ BB = MinLjj/MaxOffl;
+ if (BB>MinL) MinLjj = BB;
+ else MinLjj = MinL;
+ if (L[j][j]>MinLjj*MinLjj) L[j][j] = sqrt(L[j][j]);
+ else {
+ if (MinL2>MinLjj) MinLjj = MinL2;
+ BB = MinLjj*MinLjj-L[j][j];
+ if (BB>MaxAdd) MaxAdd = BB;
+ L[j][j] = MinLjj;
+ }
+ if (j<N)
+ for (i=j+1;i<=N;i++)
+ L[i][j] /= L[j][j];
+ }
+
+ }
+
+
+
+ // -----------------------------------------------------
+
+ void LSolve ( int N, rmatrix L, rvector B, rvector Y ) {
+ // A3.2.3a : Cholesky's L - Solution of
+ // L*Y = B ( given B )
+ int i,j;
+ Y[1] = B[1]/L[1][1];
+ if (N>1)
+ for (i=2;i<=N;i++) {
+ Y[i] = B[i];
+ for (j=1;j<i;j++)
+ Y[i] -= L[i][j]*Y[j];
+ Y[i] /= L[i][i];
+ }
+ }
+
+
+ // -----------------------------------------------------
+
+ void LTSolve ( int N, rmatrix L, rvector Y, rvector X ) {
+ // A3.2.3b : Cholesky's LT - Solution of
+ // LT*X = Y ( given Y )
+ int i,j;
+ X[N] = Y[N]/L[N][N];
+ if (N>1)
+ for (i=N-1;i>=1;i--) {
+ X[i] = Y[i];
+ for (j=i+1;j<=N;j++)
+ X[i] -= L[j][i]*X[j];
+ X[i] /= L[i][i];
+ }
+ }
+
+
+ // -----------------------------------------------------
+
+ void ChSolve ( int N, rmatrix L, rvector G, rvector S ) {
+ // A3.2.3 : Solution of the equation L*LT*S = G
+ // by the Cholesky's method
+ //int i;
+ LSolve ( N,L,G,S );
+ LTSolve ( N,L,S,S );
+ // for (i=1;i<=N;i++)
+ // S[i] = -S[i];
+ }
+
+
+
+ // ----------------------------------------------------
+
+ void FastInverse ( int N, rmatrix A, ivector J0,
+ //#D realtype & Det,
+ int & Signal ) {
+ //
+ // 17.01.91 <-- Last Date of Modification.
+ // ----------------------------
+ //
+ // ================================================
+ //
+ // Fast Inversion of the matrix A
+ // by the method of GAUSS - JOIRDAN .
+ //
+ // ------------------------------------------------
+ //
+ // Input parameters are :
+ //
+ // N - dimension of the matrix
+ // A - the matrix [1..N][1..N] to be inverted.
+ //
+ // ------------------------------------------------
+ //
+ // J0 - integer vector [1..N] for temporal storage
+ //
+ //
+ // ------------------------------------------------
+ //
+ // Output parameters are :
+ //
+ // A - the inverted matrix
+ // Signal - the error key :
+ // = 0 <=> O'K
+ // else
+ // degeneration was found, and
+ // the rang of matrix is Signal-1.
+ //
+ // Variable Det may return the determinant
+ // of matrix A. To obtain it, remove all comments
+ // of form //#D .
+ //
+ // ------------------------------------------------
+ //
+ // Key Variables are :
+ //
+ // Eps - is the level for the degeneration
+ // detection. Keep in mind, that
+ // this routine does not norm the
+ // matrix given, and thus Eps1
+ // is the ABSOLUTE value.
+ //
+ // ================================================
+ //
+
+ realtype Eps = 1.0e-16;
+
+ int i,j,k,i0;
+ realtype A0,B;
+ rvector Ai,Ai0;
+
+ Signal = 0;
+ if (N<=1) {
+ if (fabs(A[1][1])<Eps) {
+ Signal = 1;
+ return;
+ }
+ A[1][1] = 1.0/A[1][1];
+ //#D Det = A[1][1];
+ return;
+ }
+
+ if (N==2) {
+ A0 = A[1][1];
+ B = A0*A[2][2] - A[1][2]*A[2][1];
+ //#D Det = B;
+ if (fabs(B)<Eps) {
+ Signal = 1;
+ return;
+ }
+ A[1][1] = A[2][2]/B;
+ A[2][2] = A0/B;
+ B = -B;
+ A[1][2] /= B;
+ A[2][1] /= B;
+ return;
+ }
+
+ for (i=1;i<=N;i++) {
+ // 1. Finding of the leading element ( in A0 );
+ // i0 is the number of the leading string
+ A0 = 0.0;
+ i0 = 0;
+ for (j=i;j<=N;j++) {
+ if (fabs(A[j][i])>A0) {
+ A0 = fabs(A[j][i]);
+ i0 = j;
+ }
+ }
+ if (A0<Eps) {
+ Signal = i; // Degeneration is found here
+ return;
+ }
+
+ // 2. Swapping the string
+ J0[i] = i0;
+ B = 1.0/A[i0][i];
+ Ai = A[i0];
+ Ai0 = A[i];
+ A[i] = Ai;
+ A[i0] = Ai0;
+ for (j=1;j<=N;j++)
+ Ai[j] = Ai[j]*B;
+ Ai[i] = B;
+
+ // 3. Substracting the strings
+ for (j=1;j<=N;j++)
+ if (i!=j) {
+ Ai0 = A[j];
+ B = Ai0[i];
+ Ai0[i] = 0.0;
+ for (k=1;k<=N;k++)
+ Ai0[k] = Ai0[k] - B*Ai[k];
+ }
+
+ //#D Det = Det/Ai[i];
+
+ }
+
+ // 4. Back Swapping the columns
+ for (i=N;i>=1;i--) {
+ j = J0[i];
+ if (j!=i) {
+ //#D Det = -Det;
+ for (k=1;k<=N;k++) {
+ B = A[k][i];
+ A[k][i] = A[k][j];
+ A[k][j] = B;
+ }
+ }
+ }
+
+ return;
+
+ } // End of the procedure FastInverse
+
+
+
+
+ // ----------------------------------------------------
+
+ realtype Sign ( realtype A, realtype B ) {
+ if (B>=0.0) return A;
+ else return -A;
+ }
+
+ realtype SrX2Y2 ( realtype X, realtype Y ) {
+ realtype Ax,Ay;
+ Ax = fabs(X);
+ Ay = fabs(Y);
+ if (Ay>Ax) return Ay*sqrt((X*X)/(Y*Y)+1.0);
+ if (Ay==Ax) return Ax*sqrt(2.0);
+ return Ax*sqrt((Y*Y)/(X*X)+1.0);
+ }
+
+
+ // ----------------------------------------------------
+
+ void SVD ( int NA, int M, int N,
+ rmatrix A, rmatrix U, rmatrix V,
+ rvector W, rvector RV1,
+ bool MatU, bool MatV,
+ int & RetCode ) {
+ //
+ // 13.12.01 <-- Last Modification Date
+ // ------------------------
+ //
+ // ================================================
+ //
+ // The Singular Value Decomposition
+ // of the matrix A by the algorithm from
+ // G.Forsait, M.Malkolm, K.Mouler. Numerical
+ // methods of mathematical calculations
+ // M., Mir, 1980.
+ //
+ // Matrix A is represented as
+ //
+ // A = U * W * VT
+ //
+ // ------------------------------------------------
+ //
+ // All dimensions are indexed from 1 on.
+ //
+ // ------------------------------------------------
+ //
+ // Input parameters:
+ //
+ // NA - number of lines in A. NA may be
+ // equal to M or N only. If NA=M
+ // then usual SVD will be made. If MA=N
+ // then matrix A is transposed before
+ // the decomposition, and the meaning of
+ // output parameters U and V is
+ // swapped (U accepts VT and VT accepts U).
+ // In other words, matrix A has physical
+ // dimension of M x N , same as U and V;
+ // however the logical dimension of it
+ // remains that of N x M .
+ // M - number of lines in U
+ // N - number of columns in U,V and length
+ // of W,RV1 . Always provide M >= N !
+ // A - matrix [1..M][1..N] or [1..N][1..M]
+ // to be decomposed. The matrix does not
+ // change, and it may coincide with U or
+ // V, if NA=M (in which case A does change)
+ // MatU - compute U , if set True
+ // MatV - compute V , if set True
+ // RV1 - temporary array [1..N].
+ // U - should be always supplied as an array of
+ // [1..M][1..N], M>=N .
+ // V - should be suuplied as an array of
+ // [1..N][1..N] if MatV is True .
+ //
+ // ------------------------------------------------
+ //
+ // Output parameters are :
+ //
+ // W - N non-ordered singular values,
+ // if RetCode=0. If RetCode<>0, the
+ // RetCode+1 ... N -th values are still
+ // valid
+ // U - matrix of right singular vectors
+ // (arranged in columns), corresponding
+ // to the singular values in W, if
+ // RetCode=0 and MatU is True. If MatU
+ // is False, U is still used as a
+ // temporary array. If RetCode<>0 then
+ // the RetCode+1 ... N -th vectors
+ // are valid
+ // V - matrix of left singular vectors
+ // (arranged in columns), corresponding
+ // to the singular values in W, if
+ // RetCode=0 and MatV is True. If MatV
+ // is False, V is not used and may be set
+ // to NULL. If RetCode<>0 then the
+ // RetCode+1 ... N -th vectors are valid
+ // RetCode - the error key :
+ // = 0 <=> O'K
+ // else
+ // = k, if the k-th singular value
+ // was not computed after 30 iterations.
+ //
+ // ------------------------------------------------
+ //
+ // Key Variables are :
+ //
+ // ItnLimit - the limit for iterations
+ //
+ // This routine does not use any machine-dependent
+ // constants.
+ //
+ // ================================================
+ //
+ //
+ int ItnLimit=300;
+ int i,j,k,l,i1,k1,l1,its,mn,ExitKey;
+ realtype C,G,F,X,S,H,Y,Z,Scale,ANorm,GG;
+
+ l1 = 0; // this is to keep compiler happy
+ RetCode = 0;
+
+ if (U!=A) {
+ if (NA==M)
+ for (i=1;i<=M;i++)
+ for (j=1;j<=N;j++)
+ U[i][j] = A[i][j];
+ else
+ for (i=1;i<=M;i++)
+ for (j=1;j<=N;j++)
+ U[i][j] = A[j][i];
+ }
+
+ G = 0.0;
+ Scale = 0.0;
+ ANorm = 0.0;
+
+ for (i=1;i<=N;i++) {
+ l = i+1;
+ RV1[i] = Scale*G;
+ G = 0.0;
+ S = 0.0;
+ Scale = 0.0;
+ if (i<=M) {
+ for (k=i;k<=M;k++)
+ Scale += fabs(U[k][i]);
+ if (Scale!=0.0) {
+ for (k=i;k<=M;k++) {
+ U[k][i] /= Scale;
+ S += U[k][i]*U[k][i];
+ }
+ F = U[i][i];
+ G = -Sign(sqrt(S),F);
+ H = F*G-S;
+ U[i][i] = F-G;
+ if (i!=N)
+ for (j=l;j<=N;j++) {
+ S = 0.0;
+ for (k=i;k<=M;k++)
+ S += U[k][i]*U[k][j];
+ F = S/H;
+ for (k=i;k<=M;k++)
+ U[k][j] += F*U[k][i];
+ }
+ for (k=i;k<=M;k++)
+ U[k][i] *= Scale;
+ }
+ }
+
+ W[i] = Scale*G;
+ G = 0.0;
+ S = 0.0;
+ Scale = 0.0;
+
+ if ((i<=M) && (i!=N)) {
+ for (k=l;k<=N;k++)
+ Scale += fabs(U[i][k]);
+ if (Scale!=0.0) {
+ for (k=l;k<=N;k++) {
+ U[i][k] /= Scale;
+ S += U[i][k]*U[i][k];
+ }
+ F = U[i][l];
+ G = -Sign(sqrt(S),F);
+ H = F*G-S;
+ U[i][l] = F-G;
+ for (k=l;k<=N;k++)
+ RV1[k] = U[i][k]/H;
+ if (i!=M)
+ for (j=l;j<=M;j++) {
+ S = 0.0;
+ for (k=l;k<=N;k++)
+ S += U[j][k]*U[i][k];
+ for (k=l;k<=N;k++)
+ U[j][k] += S*RV1[k];
+ }
+ for (k=l;k<=N;k++)
+ U[i][k] *= Scale;
+ }
+ }
+
+ ANorm = RMax( ANorm,fabs(W[i])+fabs(RV1[i]) );
+
+ }
+
+ // Accumulation of the right-hand transformations
+
+ if (MatV)
+ for (i=N;i>=1;i--) {
+ if (i!=N) {
+ if (G!=0.0) {
+ for (j=l;j<=N;j++)
+ V[j][i] = (U[i][j]/U[i][l]) / G;
+ for (j=l;j<=N;j++) {
+ S = 0.0;
+ for (k=l;k<=N;k++)
+ S += U[i][k]*V[k][j];
+ for (k=l;k<=N;k++)
+ V[k][j] += S*V[k][i];
+ }
+ }
+ for (j=l;j<=N;j++) {
+ V[i][j] = 0.0;
+ V[j][i] = 0.0;
+ }
+ }
+
+ V[i][i] = 1.0;
+ G = RV1[i];
+ l = i;
+
+ }
+
+
+ // Accumulation of the left-hand transformations
+
+ if (MatU) {
+ mn = N;
+ if (M<N) mn = M;
+
+ for (i=mn;i>=1;i--) {
+ l = i+1;
+ G = W[i];
+ if (i!=N)
+ for (j=l;j<=N;j++)
+ U[i][j] = 0.0;
+ if (G!=0.0) {
+ if (i!=mn)
+ for (j=l;j<=N;j++) {
+ S = 0.0;
+ for (k=l;k<=M;k++)
+ S += U[k][i]*U[k][j];
+ F = (S/U[i][i]) / G;
+ for (k=i;k<=M;k++)
+ U[k][j] += F*U[k][i];
+ }
+ for (j=i;j<=M;j++)
+ U[j][i] /= G;
+ } else
+ for (j=i;j<=M;j++)
+ U[j][i] = 0.0;
+
+ U[i][i] += 1.0;
+
+ }
+ }
+
+ // Diagonalization of the two-diagonal form.
+
+ for (k=N;k>=1;k--) {
+ k1 = k-1;
+ its = 0;
+
+ do {
+ ExitKey = 0;
+ l = k+1;
+ while ((ExitKey==0) && (l>1)) {
+ l--;
+ l1 = l-1;
+ if (fabs(RV1[l])+ANorm==ANorm) ExitKey=1;
+ else if (l1>0) {
+ if (fabs(W[l1])+ANorm==ANorm) ExitKey=2;
+ }
+ }
+
+ // if (ExitKey!=1) { <-- this is original statement
+ if (ExitKey>1) { // <-- prevents from corruption due to l1<1.
+ // This is a rare case as RV1[1] should be
+ // always 0.0 . Apparently this logics is
+ // on the edge of float-point arithmetic,
+ // therefore extra precaution for the case
+ // of l1<1 was found necessary.
+ C = 0.0;
+ S = 1.0;
+ ExitKey = 0;
+ i = l;
+ while ((ExitKey==0) && (i<=k)) {
+ F = S*RV1[i];
+ RV1[i] = C*RV1[i];
+ if (fabs(F)+ANorm==ANorm) ExitKey = 1;
+ else {
+ G = W[i];
+ H = SrX2Y2(F,G);
+ W[i] = H;
+ C = G/H;
+ S = -F/H;
+ if (MatU)
+ for (j=1;j<=M;j++) {
+ Y = U[j][l1];
+ Z = U[j][i];
+ U[j][l1] = Y*C+Z*S;
+ U[j][i] = -Y*S+Z*C;
+ }
+ i++;
+ }
+ }
+ }
+
+ // Convergence Checking
+
+ Z = W[k];
+ if (l!=k) {
+ if (its>=ItnLimit) {
+ RetCode = k;
+ return;
+ }
+ its++;
+ X = W[l];
+ Y = W[k1];
+ G = RV1[k1];
+ H = RV1[k];
+ F = ((Y-Z)*(Y+Z) + (G-H)*(G+H)) / ( 2.0*H*Y );
+ if (fabs(F)<=1.0) GG = Sign(sqrt(F*F+1.0),F);
+ else GG = F*sqrt(1.0+1.0/F/F);
+ F = ((X-Z)*(X+Z) + H*(Y/(F+GG)-H)) / X;
+
+ // Next QR - Transformation
+
+ C = 1.0;
+ S = 1.0;
+ for (i1=l;i1<=k1;i1++) {
+ i = i1+1;
+ G = RV1[i];
+ Y = W[i];
+ H = S*G;
+ G = C*G;
+ Z = SrX2Y2(F,H);
+ RV1[i1] = Z;
+ C = F/Z;
+ S = H/Z;
+ F = X*C+G*S;
+ G = -X*S+G*C;
+ H = Y*S;
+ Y = Y*C;
+ if (MatV)
+ for (j=1;j<=N;j++) {
+ X = V[j][i1];
+ Z = V[j][i];
+ V[j][i1] = X*C+Z*S;
+ V[j][i] = -X*S+Z*C;
+ }
+
+ Z = SrX2Y2(F,H);
+ W[i1] = Z;
+ if (Z!=0.0) {
+ C = F/Z;
+ S = H/Z;
+ }
+ F = C*G+S*Y;
+ X = -S*G+C*Y;
+ if (MatU)
+ for (j=1;j<=M;j++) {
+ Y = U[j][i1];
+ Z = U[j][i];
+ U[j][i1] = Y*C+Z*S;
+ U[j][i] = -Y*S+Z*C;
+ }
+
+ }
+
+ RV1[l] = 0.0;
+ RV1[k] = F;
+ W[k] = X;
+
+ } else if (Z<0.0) {
+
+ W[k] = -Z;
+ if (MatV)
+ for (j=1;j<=N;j++)
+ V[j][k] = -V[j][k];
+ }
+
+ } while (l!=k);
+
+ }
+
+ }
+
+ // -----------------------------------------------------
+
+ void OrderSVD ( int M, int N, rmatrix U, rmatrix V,
+ rvector W, bool MatU, bool MatV ) {
+
+ int i,k,j;
+ realtype P;
+
+ // External loop of the re-ordering
+ for (i=1;i<N;i++) {
+ k = i;
+ P = W[i];
+
+ // Internal loop : finding of the index of greatest
+ // singular value over the remaining ones.
+ for (j=i+1;j<=N;j++)
+ if (W[j]>P) {
+ k = j;
+ P = W[j];
+ }
+
+ if (k!=i) {
+ // Swapping the singular value
+ W[k] = W[i];
+ W[i] = P;
+ // Swapping the U's columns ( if needed )
+ if (MatU)
+ for (j=1;j<=M;j++) {
+ P = U[j][i];
+ U[j][i] = U[j][k];
+ U[j][k] = P;
+ }
+ // Swapping the V's columns ( if needed )
+ if (MatV)
+ for (j=1;j<=N;j++) {
+ P = V[j][i];
+ V[j][i] = V[j][k];
+ V[j][k] = P;
+ }
+ }
+
+ }
+
+ }
+
+
+ /*
+
+ #ifndef __STDIO_H
+ #include <stdio.h>
+ #endif
+
+ int main ( int argc, char ** argv, char ** env ) {
+ // Test Jacobi
+ matrix A,T,A1;
+ vector Eigen,Aik;
+ realtype SR;
+ int N,i,j,k,Signal;
+
+ N = 4;
+
+ GetMatrixMemory ( A,N,N,1,1 );
+ GetMatrixMemory ( T,N,N,1,1 );
+ GetMatrixMemory ( A1,N,N,1,1 );
+ GetVectorMemory ( Eigen,N,1 );
+ GetVectorMemory ( Aik ,N,1 );
+
+ k = 1;
+ for (i=1;i<=N;i++)
+ for (j=i;j<=N;j++) {
+ A[i][j] = k++;
+ A[i][j] *= 1000.0;
+ A[j][i] = A[i][j];
+ }
+
+ printf ( " INITIAL MATRIX:\n" );
+ for (i=1;i<=N;i++) {
+ for (j=1;j<=N;j++)
+ printf ( " %10.4f",A[i][j] );
+ printf ( "\n" );
+ }
+
+ Jacobi ( N,A,T,Eigen,Aik,Signal );
+
+ printf ( "\n EIGEN VALUES AND EIGEN VECTORS:\n" );
+ for (i=1;i<=N;i++) {
+ printf ( " %10.4f ",Eigen[i] );
+ for (j=1;j<=N;j++)
+ printf ( " %10.4f",T[j][i] );
+ printf ( "\n" );
+ }
+ printf ( "\n measure: " );
+ for (i=1;i<=N;i++) {
+ SR = 0.0;
+ for (j=1;j<=N;j++)
+ SR += T[j][i]*T[j][i];
+ printf ( " %10.4f",sqrt(SR) );
+ }
+ printf ( "\n" );
+
+ for (i=1;i<=N;i++)
+ for (j=1;j<=N;j++) {
+ A1[i][j] = 0.0;
+ for (k=1;k<=N;k++)
+ A1[i][j] += T[i][k]*Eigen[k]*T[j][k];
+ }
+
+ printf ( "\n RESTORED INITIAL MATRIX:\n" );
+ for (i=1;i<=N;i++) {
+ for (j=1;j<=N;j++)
+ printf ( " %10.4f",A1[j][i] );
+ printf ( "\n" );
+ }
+
+ FreeMatrixMemory ( A,N,1,1 );
+ FreeMatrixMemory ( T,N,1,1 );
+ FreeMatrixMemory ( A1,N,1,1 );
+ FreeVectorMemory ( Eigen,1 );
+ FreeVectorMemory ( Aik ,1 );
+
+
+ }
+
+ */
+
+ }
+
+}
diff --git a/mmdb2/mmdb_math_linalg.h b/mmdb2/mmdb_math_linalg.h
new file mode 100644
index 0000000..b646166
--- /dev/null
+++ b/mmdb2/mmdb_math_linalg.h
@@ -0,0 +1,236 @@
+// $Id: mmdb_math_linalg.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : LinAlg <interface>
+// ~~~~~~~~~
+// **** Project : MMDB ( MacroMolecular Data Base )
+// ~~~~~~~~~
+//
+// (C) E.Krissinel 2000-2013
+//
+// =================================================================
+//
+//
+
+#ifndef __MMDB_MATH_LinAlg__
+#define __MMDB_MATH_LinAlg__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb {
+
+ namespace math {
+
+ // ========================== Jacobi =============================
+
+
+ /// Diagonalization of symmetric matrices A[1..N][1..N]
+ /// by the method of Jacobi.
+ extern void Jacobi ( int N, //!< dimension of the matrix
+ rmatrix A, //!< matrix to diagonalize; the
+ /// lower triangle, except the
+ /// diagonal, will remain unchanged
+ rmatrix T, //!< eigenvectors placed as columns
+ rvector Eigen, //!< vector of eigenvalues, orderd
+ /// by increasing
+ rvector Aik, //!< working array
+ int & Signal //!< 0 <=> Ok, ItMax <=> iteration
+ /// limit exchausted.
+ );
+
+
+ // A5.5.2 : Perturbed Cholesky Decomposition
+ extern void PbCholDecomp ( int N,
+ rvector HDiag,
+ realtype MaxOff,
+ realtype MachEps,
+ rmatrix L,
+ realtype & MaxAdd );
+
+ // A3.2.3a : Cholesky's L - Solution of
+ // L*Y = B ( given B )
+ extern void LSolve ( int N, rmatrix L, rvector B, rvector Y );
+
+ // A3.2.3b : Cholesky's LT - Solution of
+ // LT*X = Y ( given Y )
+ extern void LTSolve ( int N, rmatrix L, rvector Y, rvector X );
+
+ // A3.2.3 : Solution of the equation L*LT*S = G
+ // by the Cholesky's method
+ extern void ChSolve ( int N, rmatrix L, rvector G, rvector S );
+
+
+ // ----------------------------------------------------
+
+ extern void FastInverse ( int N, rmatrix A, ivector J0,
+ //#D realtype & Det,
+ int & Signal );
+ //
+ // 13.09.90 <-- Last Modification Date
+ // ------------------------
+ //
+ // ================================================
+ //
+ // Fast Inversion of the matrix A
+ // by the method of GAUSS - JORDAN .
+ //
+ // ------------------------------------------------
+ //
+ // Input parameters are :
+ //
+ // N - dimension of the matrix
+ // A - the matrix [1..N][1..N] to be inverted.
+ // ------------------------------------------------
+ //
+ // J0 - integer vector [1..N] for temporal storage
+ //
+ // ------------------------------------------------
+ //
+ // Output parameters are :
+ //
+ // A - the inverted matrix
+ // Signal - the error key :
+ // = 0 <=> O'K
+ // else
+ // degeneration was found, and
+ // the rang of matrix is Signal-1.
+ //
+ // Variable Det may return the determinant
+ // of matrix A. To obtain it, remove all comments
+ // of form //#D.
+ //
+ // ================================================
+
+
+ // ----------------------------------------------------
+
+ extern void SVD ( int NA, int M, int N,
+ rmatrix A, rmatrix U, rmatrix V,
+ rvector W, rvector RV1,
+ bool MatU, bool MatV,
+ int & RetCode );
+ //
+ // 13.12.01 <-- Last Modification Date
+ // ------------------------
+ //
+ // ================================================
+ //
+ // The Singular Value Decomposition
+ // of the matrix A by the algorithm from
+ // G.Forsait, M.Malkolm, K.Mouler. Numerical
+ // methods of mathematical calculations //
+ // M., Mir, 1980.
+ //
+ // Matrix A is represented as
+ //
+ // A = U * W * VT
+ //
+ // ------------------------------------------------
+ //
+ // All dimensions are indexed from 1 on.
+ //
+ // ------------------------------------------------
+ //
+ // Input parameters:
+ //
+ // NA - number of lines in A. NA may be
+ // equal to M or N only. If NA=M
+ // then usual SVD will be made. If MA=N
+ // then matrix A is transposed before
+ // the decomposition, and the meaning of
+ // output parameters U and V is
+ // swapped (U accepts VT and VT accepts U).
+ // In other words, matrix A has physical
+ // dimension of M x N , same as U and V;
+ // however the logical dimension of it
+ // remains that of N x M .
+ // M - number of lines in U
+ // N - number of columns in U,V and length
+ // of W,RV1 . Always provide M >= N !
+ // A - matrix [1..M][1..N] or [1..N][1..M]
+ // to be decomposed. The matrix does not
+ // change, and it may coincide with U or
+ // V, if NA=M (in which case A does change)
+ // MatU - compute U , if set True
+ // MatV - compute V , if set True
+ // RV1 - temporary array [1..N].
+ // U - should be always supplied as an array of
+ // [1..M][1..N], M>=N .
+ // V - should be suuplied as an array of
+ // [1..N][1..N] if MatV is True .
+ //
+ // ------------------------------------------------
+ //
+ // Output parameters are :
+ //
+ // W - N non-ordered singular values,
+ // if RetCode=0. If RetCode<>0, the
+ // RetCode+1 ... N -th values are still
+ // valid
+ // U - matrix of right singular vectors
+ // (arranged in columns), corresponding
+ // to the singular values in W, if
+ // RetCode=0 and MatU is True. If MatU
+ // is False, U is still used as a
+ // temporary array. If RetCode<>0 then
+ // the RetCode+1 ... N -th vectors
+ // are valid
+ // V - matrix of left singular vectors
+ // (arranged in columns), corresponding
+ // to the singular values in W, if
+ // RetCode=0 and MatV is True. If MatV
+ // is False, V is not used and may be set
+ // to NULL. If RetCode<>0 then the
+ // RetCode+1 ... N -th vectors are valid
+ // RetCode - the error key :
+ // = 0 <=> O'K
+ // else
+ // = k, if the k-th singular value
+ // was not computed after 30 iterations.
+ //
+ // ------------------------------------------------
+ //
+ // Key Variables are :
+ //
+ // ItnLimit - the limit for iterations
+ //
+ // This routine does not use any machine-dependent
+ // constants.
+ //
+ // ================================================
+ //
+ //
+
+ extern void OrderSVD ( int M, int N, rmatrix U, rmatrix V,
+ rvector W, bool MatU, bool MatV );
+
+
+ }
+}
+
+#endif
diff --git a/mmdb2/mmdb_math_rand.cpp b/mmdb2/mmdb_math_rand.cpp
new file mode 100644
index 0000000..1122c89
--- /dev/null
+++ b/mmdb2/mmdb_math_rand.cpp
@@ -0,0 +1,241 @@
+// $Id: mmdb_math_rand.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Rand <implementation>
+// ~~~~~~~~~
+// **** Classes : RandomNumber ( random number generator )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 1997-2013
+//
+// =================================================================
+//
+
+#include <math.h>
+
+#include "mmdb_math_rand.h"
+
+
+namespace mmdb {
+
+ namespace math {
+
+ // =================== RandomNumber ==========================
+
+ RandomNumber::RandomNumber ( long IJ, long KL ) {
+ Init ( IJ,KL );
+ }
+
+ void RandomNumber::Init ( long IJ, long KL ) {
+ long i,j,k,l,m, ii,jj;
+ realtype s,t;
+
+ iset = 0;
+ gset = 0.0;
+
+ if ((IJ<0) || (IJ>_RN_MAX_IJ) ||
+ (KL<0) || (KL>_RN_MAX_KL)) return;
+
+ i = mod(IJ/177,177) + 2;
+ j = mod(IJ,177) + 2;
+ k = mod(KL/169,178) + 1;
+ l = mod(KL,169);
+
+ for (ii=0;ii<97;ii++) {
+ s = 0.0;
+ t = 0.5;
+ for (jj=1;jj<=24;jj++) {
+ m = mod(mod(i*j,179)*k,179);
+ i = j;
+ j = k;
+ k = m;
+ l = mod(53*l+1,169);
+ if (mod(l*m,64)>=32) s += t;
+ t *= 0.5;
+ }
+ U[ii] = s;
+ }
+
+ C = 362436.0 / 16777216.0;
+ CD = 7654321.0 / 16777216.0;
+ CM = 16777213.0 / 16777216.0;
+
+ I97 = 96;
+ J97 = 32;
+
+ }
+
+
+ // uniform [0..1] random number generator
+ realtype RandomNumber::random() {
+ realtype uni;
+
+ uni = U[I97] - U[J97];
+ if (uni<0.0) uni += 1.0;
+ U[I97] = uni;
+ I97--;
+ if (I97<0) I97 = 96;
+ J97--;
+ if (J97<0) J97 = 96;
+ C -= CD;
+ if (C<0.0) C += CM;
+ uni -= C;
+ if (uni<0.0) uni += 1.0;
+
+ return uni;
+
+ }
+
+
+ // uniform [-1..1] random number generator
+ realtype RandomNumber::srandom() {
+ realtype uni;
+
+ uni = U[I97] - U[J97];
+ if (uni<0.0) uni += 1.0;
+ U[I97] = uni;
+ I97--;
+ if (I97<0) I97 = 96;
+ J97--;
+ if (J97<0) J97 = 96;
+ C -= CD;
+ if (C<0.0) C += CM;
+ uni -= C;
+ if (uni<0.0) uni += 1.0;
+
+ return 2.0*uni - 1.0;
+
+ }
+
+ // gaussian random numbers
+ realtype RandomNumber::gauss_rnd() {
+ realtype v1,v2,r,fac;
+ if (iset==0) {
+ do {
+ v1 = srandom();
+ v2 = srandom();
+ r = v1*v1 + v2*v2;
+ } while ((r>=1.0) || (r==0.0));
+ fac = sqrt(-2.0*log(r)/r);
+ gset = v1*fac;
+ iset = 1;
+ return v2*fac;
+ } else {
+ iset = 0;
+ return gset;
+ }
+ }
+
+ void RandomNumber::write ( io::RFile f ) {
+ int Version=1;
+ f.WriteFile ( &Version,sizeof(Version) );
+ f.WriteFile ( &I97 ,sizeof(I97) );
+ f.WriteFile ( &J97 ,sizeof(J97) );
+ f.WriteFile ( U ,sizeof(U) );
+ f.WriteFile ( &C ,sizeof(C) );
+ f.WriteFile ( &CD ,sizeof(CD) );
+ f.WriteFile ( &CM ,sizeof(CM) );
+ f.WriteFile ( &gset ,sizeof(gset) );
+ f.WriteFile ( &iset ,sizeof(iset) );
+ }
+
+ void RandomNumber::read ( io::RFile f ) {
+ int Version;
+ f.ReadFile ( &Version,sizeof(Version) );
+ f.ReadFile ( &I97 ,sizeof(I97) );
+ f.ReadFile ( &J97 ,sizeof(J97) );
+ f.ReadFile ( U ,sizeof(U) );
+ f.ReadFile ( &C ,sizeof(C) );
+ f.ReadFile ( &CD ,sizeof(CD) );
+ f.ReadFile ( &CM ,sizeof(CM) );
+ f.ReadFile ( &gset ,sizeof(gset) );
+ f.ReadFile ( &iset ,sizeof(iset) );
+ }
+
+
+ } // namespace math
+
+} // namespace mmdb
+
+
+/*
+
+static int m1 = 259200;
+static int ia1 = 7141;
+static int ic1 = 54773;
+static realtype rm1 = 1.0/259200.0;
+
+static int m2 = 134456;
+static int ia2 = 8121;
+static int ic2 = 28411;
+static realtype rm2 = 1.0/134456.0;
+
+static int m3 = 243000;
+static int ia3 = 4561;
+static int ic3 = 51349;
+
+static int ix1 = 0;
+static int ix2 = 0;
+static int ix3 = 0;
+
+static realtype R[97];
+
+void randomize ( int iseed ) {
+int j;
+ RndInit = True;
+ ix1 = mod(ic1-iseed,m1);
+ ix1 = mod(ia1*ix1+ic1,m1);
+ ix2 = mod(ix1,m2);
+ ix1 = mod(ia1*ix1+ic1,m1);
+ ix3 = mod(ix1,m3);
+ for (j=0;j<97;j++) {
+ ix1 = mod(ia1*ix1+ic1,m1);
+ ix2 = mod(ia2*ix2+ic2,m2);
+ R[j] = (ix1+ix2*rm2)*rm1;
+ }
+}
+
+realtype rand() {
+int j;
+realtype rnd;
+ if (!RndInit) randomize();
+ ix1 = mod(ia1*ix1+ic1,m1);
+ ix2 = mod(ia2*ix2+ic2,m2);
+ ix3 = mod(ia3*ix3+ic3,m3);
+ j = 1 + (97*ix3)/m3;
+ j = IMax(j,1);
+ j = IMin(j,97);
+ rnd = R[j-1];
+ R[j] = (ix1+ix2*rm2)*rm1;
+ return rnd;
+}
+*/
+
+// ===========================================================
+
+// End of Random_N
diff --git a/mmdb2/mmdb_math_rand.h b/mmdb2/mmdb_math_rand.h
new file mode 100644
index 0000000..8fde4f1
--- /dev/null
+++ b/mmdb2/mmdb_math_rand.h
@@ -0,0 +1,80 @@
+// $Id: mmdb_math_rand.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : Rand <interface>
+// ~~~~~~~~~
+// **** Classes : RandomNumber ( random number generator )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 1997-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_MATH_Rand__
+#define __MMDB_MATH_Rand__
+
+#include "mmdb_io_file.h"
+
+namespace mmdb {
+
+ namespace math {
+
+ // -------------------------------------------------------------
+
+ enum RN_MAX_SEED {
+ _RN_MAX_IJ = 31328,
+ _RN_MAX_KL = 30081
+ };
+
+ DefineClass(RandomNumber);
+
+ class RandomNumber {
+ public :
+ RandomNumber ( long IJ=0, long KL=0 );
+ void Init ( long IJ=0, long KL=0 );
+ realtype gauss_rnd(); //!< Gaussian random numbers
+ realtype random (); //!< Uniform [0..1] random number generator
+ realtype srandom (); //!< Uniform [-1..1] random number generator
+
+ void read ( io::RFile f );
+ void write ( io::RFile f );
+
+ protected :
+ long I97,J97;
+ realtype U[97],C,CD,CM;
+ realtype gset;
+ long iset;
+
+ };
+
+ } // namespace math
+
+} // namespace mmdb
+
+#endif
diff --git a/mmdb2/mmdb_mattype.cpp b/mmdb2/mmdb_mattype.cpp
new file mode 100644
index 0000000..83e4a59
--- /dev/null
+++ b/mmdb2/mmdb_mattype.cpp
@@ -0,0 +1,2087 @@
+// $Id: mmdb_mattype.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 10.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MatType_ <implementation>
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits>
+#include <stdio.h>
+
+#include "mmdb_mattype.h"
+
+
+namespace mmdb {
+
+ // -------------------------------------------------------
+
+ realtype MachEps;
+ realtype floatMachEps;
+ realtype LnMaxReal;
+ realtype LnMinReal;
+ static realtype LnMaxRealExp;
+ static realtype LnMinRealExp;
+
+ // Initialization. Some C++ enviroments do not do the
+ // following statements automatically, therefore it is
+ // always advisable to call InitMatType() explicitely
+ // from the top of main(). See body of InitMatType()
+ // in the very end of this file. It is completely
+ // harmless and cheap to call InitMatType() multiple
+ // times.
+
+ static bool MatTypeInit = InitMatType();
+
+
+ // -------------------------------------------------------
+
+
+#ifdef _WIN32
+ pstr strcasestr ( pstr s1, cpstr s2 ) {
+ pstr l1,l2,l;
+ l1 = NULL;
+ l2 = NULL;
+ CreateCopy ( l1,s1 );
+ CreateCopy ( l2,s2 );
+ LowerCase ( l1 );
+ LowerCase ( l2 );
+ l = strstr ( l1,l2 );
+ if (l)
+ l = s1 + (l-l1);
+ delete[] l1;
+ delete[] l2;
+ return l;
+ }
+#endif
+
+
+ // -------------------------------------------------------
+ bool GetVectorMemory ( rvector & V, word N, word Shift ) {
+ V = new realtype[N];
+ if (V!=NULL) V = V - Shift; // shift for abovementioned enumeration
+ return (V!=NULL);
+ }
+
+ bool GetVectorMemory ( ivector & I, word N, word Shift ) {
+ I = new int[N];
+ if (I!=NULL) I = I - Shift; // shift for abovementioned enumeration
+ return (I!=NULL);
+ }
+
+ bool GetVectorMemory ( wvector & W, word N, word Shift ) {
+ W = new word[N];
+ if (W!=NULL) W = W - Shift; // shift for abovementioned enumeration
+ return (W!=NULL);
+ }
+
+ bool GetVectorMemory ( bvector & B, word N, word Shift ) {
+ B = new byte[N];
+ if (B!=NULL) B = B - Shift; // shift for abovementioned enumeration
+ return (B!=NULL);
+ }
+
+ bool GetVectorMemory ( ovector & O, word N, word Shift ) {
+ O = new bool[N];
+ if (O!=NULL) O = O - Shift; // shift for abovementioned enumeration
+ return (O!=NULL);
+ }
+
+ bool GetVectorMemory ( lvector & L, word N, word Shift ) {
+ L = new long[N];
+ if (L!=NULL) L = L - Shift; // shift for abovementioned enumeration
+ return (L!=NULL);
+ }
+
+ bool GetVectorMemory ( lwvector & L, word N, word Shift ) {
+ L = new lword[N];
+ if (L!=NULL) L = L - Shift; // shift for abovementioned enumeration
+ return (L!=NULL);
+ }
+
+ bool GetVectorMemory ( psvector & P, word N, word Shift ) {
+ P = new pstr[N];
+ if (P!=NULL) P = P - Shift; // shift for abovementioned enumeration
+ return (P!=NULL);
+ }
+
+ void FreeVectorMemory ( rvector & V, word Shift ) {
+ if (V!=NULL) {
+ V = V + Shift; // back shift for the work of heap system
+ delete[] V;
+ V = NULL;
+ }
+ }
+
+ void FreeVectorMemory ( ivector & I, word Shift ) {
+ if (I!=NULL) {
+ I = I + Shift; // back shift for the work of heap system
+ delete[] I;
+ I = NULL;
+ }
+ }
+
+ void FreeVectorMemory ( wvector & W, word Shift ) {
+ if (W!=NULL) {
+ W = W + Shift; // back shift for the work of heap system
+ delete[] W;
+ W = NULL;
+ }
+ }
+
+ void FreeVectorMemory ( bvector & B, word Shift ) {
+ if (B!=NULL) {
+ B = B + Shift; // back shift for the work of heap system
+ delete[] B;
+ B = NULL;
+ }
+ }
+
+ void FreeVectorMemory ( ovector & O, word Shift ) {
+ if (O!=NULL) {
+ O = O + Shift; // back shift for the work of heap system
+ delete[] O;
+ O = NULL;
+ }
+ }
+
+ void FreeVectorMemory ( lvector & L, word Shift ) {
+ if (L!=NULL) {
+ L = L + Shift; // back shift for the work of heap system
+ delete[] L;
+ L = NULL;
+ }
+ }
+
+ void FreeVectorMemory ( lwvector & L, word Shift ) {
+ if (L!=NULL) {
+ L = L + Shift; // back shift for the work of heap system
+ delete[] L;
+ L = NULL;
+ }
+ }
+
+ void FreeVectorMemory ( psvector & P, word Shift ) {
+ if (P!=NULL) {
+ P = P + Shift; // back shift for the work of heap system
+ delete[] P;
+ P = NULL;
+ }
+ }
+
+ bool GetMatrixMemory ( rmatrix & A, word N, word M,
+ word ShiftN, word ShiftM ) {
+ A = new rvector[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetVectorMemory ( A[i],M,ShiftM );
+ if (A[N-1]==NULL)
+ FreeMatrixMemory ( A,N,0,ShiftM );
+ else A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ bool GetMatrixMemory ( imatrix & A, word N, word M,
+ word ShiftN, word ShiftM ) {
+ A = new ivector[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetVectorMemory ( A[i],M,ShiftM );
+ if (A[N-1]==NULL)
+ FreeMatrixMemory ( A,N,0,ShiftM );
+ else A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ bool GetMatrixMemory ( wmatrix & W, word N, word M,
+ word ShiftN, word ShiftM ) {
+ W = new wvector[N];
+ if (W!=NULL) {
+ for (word i=0;i<N;i++)
+ GetVectorMemory ( W[i],M,ShiftM );
+ if (W[N-1]==NULL)
+ FreeMatrixMemory ( W,N,0,ShiftM );
+ else W = W - ShiftN; // shift for the enumeration with 1
+ }
+ return (W!=NULL);
+ }
+
+ bool GetMatrixMemory ( bmatrix & B, word N, word M,
+ word ShiftN, word ShiftM ) {
+ B = new bvector[N];
+ if (B!=NULL) {
+ for (word i=0;i<N;i++)
+ GetVectorMemory ( B[i],M,ShiftM );
+ if (B[N-1]==NULL)
+ FreeMatrixMemory ( B,N,0,ShiftM );
+ else B = B - ShiftN; // shift for the enumeration with 1
+ }
+ return (B!=NULL);
+ }
+
+ bool GetMatrixMemory ( omatrix & O, word N, word M,
+ word ShiftN, word ShiftM ) {
+ O = new ovector[N];
+ if (O!=NULL) {
+ for (word i=0;i<N;i++)
+ GetVectorMemory ( O[i],M,ShiftM );
+ if (O[N-1]==NULL)
+ FreeMatrixMemory ( O,N,0,ShiftM );
+ else O = O - ShiftN; // shift for the enumeration with 1
+ }
+ return (O!=NULL);
+ }
+
+ bool GetMatrixMemory ( lmatrix & L, word N, word M,
+ word ShiftN, word ShiftM ) {
+ L = new lvector[N];
+ if (L!=NULL) {
+ for (word i=0;i<N;i++)
+ GetVectorMemory ( L[i],M,ShiftM );
+ if (L[N-1]==NULL)
+ FreeMatrixMemory ( L,N,0,ShiftM );
+ else L = L - ShiftN; // shift for the enumeration with 1
+ }
+ return (L!=NULL);
+ }
+
+ bool GetMatrixMemory ( lwmatrix & L, word N, word M,
+ word ShiftN, word ShiftM ) {
+ L = new lwvector[N];
+ if (L!=NULL) {
+ for (word i=0;i<N;i++)
+ GetVectorMemory ( L[i],M,ShiftM );
+ if (L[N-1]==NULL)
+ FreeMatrixMemory ( L,N,0,ShiftM );
+ else L = L - ShiftN; // shift for the enumeration with 1
+ }
+ return (L!=NULL);
+ }
+
+ bool GetMatrixMemory ( psmatrix & P, word N, word M,
+ word ShiftN, word ShiftM ) {
+ P = new psvector[N];
+ if (P!=NULL) {
+ for (word i=0;i<N;i++)
+ GetVectorMemory ( P[i],M,ShiftM );
+ if (P[N-1]==NULL)
+ FreeMatrixMemory ( P,N,0,ShiftM );
+ else P = P - ShiftN; // shift for the enumeration with 1
+ }
+ return (P!=NULL);
+ }
+
+ void FreeMatrixMemory ( rmatrix & A, word N,
+ word ShiftN, word ShiftM ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeVectorMemory ( A[i],ShiftM );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ void FreeMatrixMemory ( imatrix & A, word N,
+ word ShiftN, word ShiftM ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeVectorMemory ( A[i],ShiftM );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ void FreeMatrixMemory ( wmatrix & W, word N,
+ word ShiftN, word ShiftM ) {
+ if (W!=NULL) {
+ W = W + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeVectorMemory ( W[i],ShiftM );
+ delete[] W;
+ W = NULL;
+ }
+ }
+
+ void FreeMatrixMemory ( bmatrix & B, word N,
+ word ShiftN, word ShiftM ) {
+ if (B!=NULL) {
+ B = B + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeVectorMemory ( B[i],ShiftM );
+ delete[] B;
+ B = NULL;
+ }
+ }
+
+ void FreeMatrixMemory ( omatrix & O, word N,
+ word ShiftN, word ShiftM ) {
+ if (O!=NULL) {
+ O = O + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeVectorMemory ( O[i],ShiftM );
+ delete[] O;
+ O = NULL;
+ }
+ }
+
+ void FreeMatrixMemory ( lmatrix & L, word N,
+ word ShiftN, word ShiftM ) {
+ if (L!=NULL) {
+ L = L + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeVectorMemory ( L[i],ShiftM );
+ delete[] L;
+ L = NULL;
+ }
+ }
+
+ void FreeMatrixMemory ( lwmatrix & L, word N,
+ word ShiftN, word ShiftM ) {
+ if (L!=NULL) {
+ L = L + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeVectorMemory ( L[i],ShiftM );
+ delete[] L;
+ L = NULL;
+ }
+ }
+
+ void FreeMatrixMemory ( psmatrix & P, word N,
+ word ShiftN, word ShiftM ) {
+ if (P!=NULL) {
+ P = P + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeVectorMemory ( P[i],ShiftM );
+ delete[] P;
+ P = NULL;
+ }
+ }
+
+ bool GetMatrix3Memory ( rmatrix3 & A, word N, word M, word K,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ A = new rmatrix[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+ if (A[N-1]==NULL)
+ FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+ else
+ A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ bool GetMatrix3Memory ( imatrix3 & A, word N, word M, word K,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ A = new imatrix[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+ if (A[N-1]==NULL)
+ FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+ else
+ A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ bool GetMatrix3Memory ( wmatrix3 & A, word N, word M, word K,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ A = new wmatrix[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+ if (A[N-1]==NULL)
+ FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+ else
+ A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ bool GetMatrix3Memory ( bmatrix3 &A, word N, word M, word K,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ A = new bmatrix[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+ if (A[N-1]==NULL)
+ FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+ else
+ A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ bool GetMatrix3Memory ( omatrix3 &A, word N, word M, word K,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ A = new omatrix[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+ if (A[N-1]==NULL)
+ FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+ else
+ A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ bool GetMatrix3Memory ( lmatrix3 & A, word N, word M, word K,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ A = new lmatrix[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+ if (A[N-1]==NULL)
+ FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+ else
+ A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ bool GetMatrix3Memory ( lwmatrix3 & A, word N, word M, word K,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ A = new lwmatrix[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+ if (A[N-1]==NULL)
+ FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+ else
+ A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ bool GetMatrix3Memory ( psmatrix3 & A, word N, word M, word K,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ A = new psmatrix[N];
+ if (A!=NULL) {
+ for (word i=0;i<N;i++)
+ GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+ if (A[N-1]==NULL)
+ FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+ else
+ A = A - ShiftN; // shift for the enumeration with 1
+ }
+ return (A!=NULL);
+ }
+
+ void FreeMatrix3Memory ( rmatrix3 & A, word N, word M,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ void FreeMatrix3Memory ( imatrix3 & A, word N, word M,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ void FreeMatrix3Memory ( wmatrix3 & A, word N, word M,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ void FreeMatrix3Memory ( bmatrix3 & A, word N, word M,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ void FreeMatrix3Memory ( omatrix3 & A, word N, word M,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ void FreeMatrix3Memory ( lmatrix3 & A, word N, word M,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ void FreeMatrix3Memory ( lwmatrix3 & A, word N, word M,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ void FreeMatrix3Memory ( psmatrix3 & A, word N, word M,
+ word ShiftN, word ShiftM, word ShiftK ) {
+ if (A!=NULL) {
+ A = A + ShiftN; // back shift for the work of heap system
+ for (word i=0;i<N;i++)
+ FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+ delete[] A;
+ A = NULL;
+ }
+ }
+
+ realtype MachinEps () {
+ // A1.3.1 : Calculation of the machine's epsilon
+ /*
+ realtype rMachEps = 1.0;
+ do
+ rMachEps /= 2.0;
+ while ((1.0+rMachEps)!=1.0);
+ return 2.0*rMachEps;
+ */
+ return std::numeric_limits<realtype>::epsilon();
+ }
+
+ realtype floatMachinEps() {
+ // A1.3.1 : Calculation of the machine's epsilon
+ /*
+ float fMachEps = 1.0;
+ do
+ fMachEps /= 2.0;
+ while (float(1.0+fMachEps)!=1.0);
+ return 2.0*fMachEps;
+ */
+ return std::numeric_limits<float>::epsilon();
+ }
+
+ realtype frac ( realtype R ) {
+ realtype i;
+ return modf ( R,&i );
+ }
+
+ long mod ( long x, long y ) {
+ long k=x/y;
+ long f=x-k*y;
+ while (f<0) f += y;
+ return f;
+ }
+
+ realtype Pow ( realtype X, int y ) {
+ int m,l;
+ realtype B;
+ if (y==0) return 1.0;
+ else if (X!=0.0) {
+ B = X;
+ m = 1;
+ if (y>=0) l = y;
+ else l = -y;
+ while (m++<l) B = B*X;
+ if (y>=0) return B;
+ else return 1.0/B;
+ } else return 0.0;
+ }
+
+ realtype Pow1 ( realtype X, realtype Y ) {
+ int k = mround(Y);
+ if (fabs(k-Y)<=100.0*MachEps) return Pow(X,k);
+ if (X==0.0) return 0.0;
+ else return pow(X,Y);
+ }
+
+ realtype Exp ( realtype X ) {
+ //realtype X1 = X;
+ //realtype B = 1.0;
+ if (X>=LnMaxRealExp) return MaxReal;
+ else if (X<=LnMinRealExp) return 0.0;
+ else {
+ return exp(X);
+ /*
+ while (X1>LnMaxReal) {
+ X1 -= LnMaxReal;
+ B *= MaxExponent;
+ }
+ while (X1<-LnMaxReal) {
+ X1 += LnMaxReal;
+ B /= MaxExponent;
+ }
+ return B*exp(X1);
+ */
+ }
+ }
+
+ bool Odd ( int i ) {
+ return (i & 1);
+ }
+
+
+ // ----------------------------------------------------
+
+ long HexValL ( cpstr S ) {
+ char C;
+ int i;
+ long z=0;
+ for (i=0;S[i];i++) {
+ z <<= 4;
+ C = (char)toupper(S[i]);
+ if (isdigit(C)) z += S[i]-'0';
+ else z += C-'A'+10;
+ }
+ return z;
+ }
+
+
+ // ----------------------------------------------------
+
+ long OctValL ( cpstr S ) {
+ int i;
+ long z=0;
+ for (i=0;S[i];i++) {
+ z <<= 3;
+ z += S[i]-'0';
+ }
+ return z;
+ }
+
+
+ // ----------------------------------------------------
+
+ long BinValL ( cpstr S ) {
+ int i;
+ long z=0;
+ for (i=0;S[i];i++) {
+ z <<= 1;
+ z += S[i]-'0';
+ }
+ return z;
+ }
+
+ pstr BinValS ( long L, pstr S ) {
+ int i;
+ long z;
+ z = long(1) << (8*sizeof(long)-1);
+ for (i=0;i<8*(int)sizeof(long);i++) {
+ if (L & z) S[i] = '1';
+ else S[i] = '0';
+ z >>= 1;
+ }
+ S[8*sizeof(long)] = char(0);
+ return S;
+ }
+
+
+
+ // ----------------------------------------------------
+
+ pstr ParamStr ( pstr D, cpstr S, realtype V, int M, cpstr S1 ) {
+ char VS[30];
+ strcat ( D,S );
+ sprintf ( VS,"%-.*g",M,V );
+ strcat ( D,VS );
+ return strcat(D,S1);
+ }
+
+
+ pstr ParamStr ( pstr D, cpstr S, realtype V, int M,
+ cpstr S1, realtype V2, int M2, cpstr S2 ) {
+ char VS[30];
+ ParamStr ( D,S,V,M,S1 );
+ sprintf ( VS,"%-.*g",M2,V2 );
+ strcat ( D,VS );
+ return strcat(D,S2);
+ }
+
+
+ pstr CreateCopy ( pstr & Dest, cpstr Source ) {
+ if (Dest) delete[] Dest;
+ if (Source) {
+ Dest = new char[strlen(Source)+1];
+ strcpy ( Dest,Source );
+ } else
+ Dest = NULL;
+ return Dest;
+ }
+
+ pstr CreateCopy_n ( pstr & Dest, cpstr Source, int n ) {
+ int l;
+ if (Dest) delete[] Dest;
+ if (Source) {
+ l = IMin ( strlen(Source),n );
+ Dest = new char[l+1];
+ strncpy ( Dest,Source,l );
+ Dest[l] = char(0);
+ } else
+ Dest = NULL;
+ return Dest;
+ }
+
+ pstr CreateCopCat ( pstr & Dest,
+ cpstr Source1, cpstr Source2,
+ cpstr Source3, cpstr Source4,
+ cpstr Source5 ) {
+ if (Dest) {
+ delete[] Dest;
+ Dest = NULL;
+ }
+ return CreateConcat ( Dest,Source1,Source2,Source3,Source4,Source5 );
+ }
+
+ pstr CreateCopCat ( pstr & Dest,
+ cpstr Source1, cpstr Source2,
+ cpstr Source3, cpstr Source4 ) {
+ if (Dest) {
+ delete[] Dest;
+ Dest = NULL;
+ }
+ return CreateConcat ( Dest,Source1,Source2,Source3,Source4 );
+ }
+
+ pstr CreateCopCat ( pstr & Dest,
+ cpstr Source1, cpstr Source2,
+ cpstr Source3 ) {
+ if (Dest) {
+ delete[] Dest;
+ Dest = NULL;
+ }
+ return CreateConcat ( Dest,Source1,Source2,Source3 );
+ }
+
+ pstr CreateCopCat ( pstr & Dest,
+ cpstr Source1, cpstr Source2 ) {
+ if (Dest) {
+ delete[] Dest;
+ Dest = NULL;
+ }
+ return CreateConcat ( Dest,Source1,Source2 );
+ }
+
+
+ pstr CreateConcat ( pstr & Dest,
+ cpstr Source1, cpstr Source2,
+ cpstr Source3, cpstr Source4,
+ cpstr Source5 ) {
+ pstr S;
+ int ld,ls;
+ if (Dest) ld = strlen(Dest);
+ else ld = 0;
+ ls = 0;
+ if (Source1) ls += strlen(Source1);
+ if (Source2) ls += strlen(Source2);
+ if (Source3) ls += strlen(Source3);
+ if (Source4) ls += strlen(Source4);
+ if (Source5) ls += strlen(Source5);
+ if (ls>0) {
+ S = new char[ls+ld+1];
+ if (Dest) {
+ strcpy ( S,Dest );
+ delete[] Dest;
+ } else
+ S[0] = char(0);
+ if (Source1) strcat ( S,Source1 );
+ if (Source2) strcat ( S,Source2 );
+ if (Source3) strcat ( S,Source3 );
+ if (Source4) strcat ( S,Source4 );
+ if (Source5) strcat ( S,Source5 );
+ Dest = S;
+ }
+ return Dest;
+ }
+
+
+ pstr CreateConcat ( pstr & Dest,
+ cpstr Source1, cpstr Source2,
+ cpstr Source3, cpstr Source4 ) {
+ pstr S;
+ int ld,ls;
+ if (Dest) ld = strlen(Dest);
+ else ld = 0;
+ ls = 0;
+ if (Source1) ls += strlen(Source1);
+ if (Source2) ls += strlen(Source2);
+ if (Source3) ls += strlen(Source3);
+ if (Source4) ls += strlen(Source4);
+ if (ls>0) {
+ S = new char[ls+ld+1];
+ if (Dest) {
+ strcpy ( S,Dest );
+ delete[] Dest;
+ } else
+ S[0] = char(0);
+ if (Source1) strcat ( S,Source1 );
+ if (Source2) strcat ( S,Source2 );
+ if (Source3) strcat ( S,Source3 );
+ if (Source4) strcat ( S,Source4 );
+ Dest = S;
+ }
+ return Dest;
+ }
+
+
+ pstr CreateConcat ( pstr & Dest,
+ cpstr Source1, cpstr Source2,
+ cpstr Source3 ) {
+ pstr S;
+ int ld,ls;
+ if (Dest) ld = strlen(Dest);
+ else ld = 0;
+ ls = 0;
+ if (Source1) ls += strlen(Source1);
+ if (Source2) ls += strlen(Source2);
+ if (Source3) ls += strlen(Source3);
+ if (ls>0) {
+ S = new char[ls+ld+1];
+ if (Dest) {
+ strcpy ( S,Dest );
+ delete[] Dest;
+ } else
+ S[0] = char(0);
+ if (Source1) strcat ( S,Source1 );
+ if (Source2) strcat ( S,Source2 );
+ if (Source3) strcat ( S,Source3 );
+ Dest = S;
+ }
+ return Dest;
+ }
+
+ pstr CreateConcat ( pstr & Dest,
+ cpstr Source1, cpstr Source2 ) {
+ pstr S;
+ int ld,ls;
+ if (Dest) ld = strlen(Dest);
+ else ld = 0;
+ ls = 0;
+ if (Source1) ls += strlen(Source1);
+ if (Source2) ls += strlen(Source2);
+ if (ls>0) {
+ S = new char[ls+ld+1];
+ if (Dest) {
+ strcpy ( S,Dest );
+ delete[] Dest;
+ } else
+ S[0] = char(0);
+ if (Source1) strcat ( S,Source1 );
+ if (Source2) strcat ( S,Source2 );
+ Dest = S;
+ }
+ return Dest;
+ }
+
+ pstr CreateConcat ( pstr & Dest, cpstr Source ) {
+ pstr S;
+ int ld,ls;
+ if (Dest) ld = strlen(Dest);
+ else ld = 0;
+ if (Source) ls = strlen(Source);
+ else ls = 0;
+ if (ls>0) {
+ S = new char[ls+ld+1];
+ if (Dest) {
+ strcpy ( S,Dest );
+ delete[] Dest;
+ } else
+ S[0] = char(0);
+ strcat ( S,Source );
+ Dest = S;
+ }
+ return Dest;
+ }
+
+
+ pstr LastOccurence ( cpstr S, char c ) {
+ pstr P=(pstr)S;
+ pstr R=NULL;
+ while (*P) {
+ if (*P==c) R = P;
+ P++;
+ }
+ return R;
+ }
+
+
+ pstr FirstOccurence ( cpstr S, char c ) {
+ pstr P=(pstr)S;
+ while (*P) {
+ if (*P==c) return P;
+ P++;
+ }
+ return NULL;
+ }
+
+ int indexOf ( cpstr S, char c ) {
+ int i=0;
+ while (S[i]) {
+ if (S[i]==c) return i;
+ i++;
+ }
+ return -1;
+ }
+
+ pstr FirstOccurence ( cpstr S, int Slen, cpstr Q, int Qlen ) {
+ int i,j,k,l;
+ l = Slen-Qlen;
+ for (i=0;i<=l;i++) {
+ j = 0;
+ k = i;
+ while (j<Qlen)
+ if (S[k++]!=Q[j]) break;
+ else j++;
+ if (j>=Qlen) return pstr(&(S[i]));
+ }
+ return NULL;
+ }
+
+ int indexOf ( cpstr S, int Slen, cpstr Q, int Qlen ) {
+ int i,j,k,l;
+ l = Slen-Qlen;
+ for (i=0;i<=l;i++) {
+ j = 0;
+ k = i;
+ while (j<Qlen)
+ if (S[k++]!=Q[j]) break;
+ else j++;
+ if (j>=Qlen) return i;
+ }
+ return -1;
+ }
+
+
+ pstr LowerCase ( pstr s ) {
+ pstr p=s;
+ while (*p) {
+ *p = char(tolower(int(*p)));
+ p++;
+ }
+ return s;
+ }
+
+ pstr UpperCase ( pstr s ) {
+ pstr p=s;
+ while (*p) {
+ *p = char(toupper(int(*p)));
+ p++;
+ }
+ return s;
+ }
+
+
+ void GetString ( pstr L, cpstr S, int M ) {
+ // Copies first M characters of string S into string L,
+ // appending the terminating null. If S contains less
+ // then M characters, L will be padded with spaces.
+ int i,j;
+ i = 0;
+ j = 0;
+ while (S[i] && (i<M))
+ L[j++] = S[i++];
+ while (j<M)
+ L[j++] = ' ';
+ L[j] = char(0);
+ }
+
+
+ void GetStrTer ( pstr L, cpstr S, int n, int LMax, int SMax ) {
+ // Copies at least n (or LMax if LMax<n) first symbols of
+ // string S into string L, then continues copying until first
+ // space or terminating null is found. If the terminating null
+ // is met among the first n characters or if SMax<n, the string
+ // L will be padded with spaces till the length of minimum of
+ // n and LMax and then terminated with the null.
+ // SMax are buffer lengths of L and S, respectively. Even if
+ // no space is found, the last character in L will be the
+ // terminating null.
+ int i,k,lm1,msl,mnsl;
+ lm1 = LMax-1;
+ msl = IMin(lm1,SMax);
+ mnsl = IMin(n,msl);
+ k = 0;
+ for (i=0;i<mnsl;i++)
+ if (S[i]) L[k++] = S[i];
+ else break;
+ if ((k>=SMax) || (!S[k])) {
+ lm1 = IMin(n,lm1);
+ while (k<lm1)
+ L[k++] = ' ';
+ } else {
+ lm1 = k;
+ for (i=lm1;i<msl;i++)
+ if (S[i] && (S[i]!=' ')) L[k++] = S[i];
+ else break;
+ }
+ L[k] = char(0);
+ }
+
+
+ void GetStrTerWin32File ( pstr L, cpstr S, int n, int LMax,
+ int SMax ) {
+ //
+ // Version of GetStrTer(..) allowing for spaces in the string.
+ //
+ // Copies at least n (or LMax if LMax<n) first symbols of
+ // string S into string L, then continues copying until first
+ // terminating null is found. If the terminating null
+ // is met among the first n characters or if SMax<n, the string
+ // L will be padded with spaces till the length of minimum of
+ // n and LMax and then terminated with the null.
+ // SMax are buffer lengths of L and S, respectively. The last
+ // character in L will be the terminating null.
+ //
+ int i,k,lm1,msl,mnsl;
+ lm1 = LMax-1;
+ msl = IMin(lm1,SMax);
+ mnsl = IMin(n,msl);
+ k = 0;
+ for (i=0;i<mnsl;i++)
+ if (S[i]) L[k++] = S[i];
+ else break;
+ if ((!S[k]) || (k>=SMax)) {
+ lm1 = IMin(n,lm1);
+ while (k<lm1)
+ L[k++] = ' ';
+ } else {
+ lm1 = k;
+ for (i=lm1;i<msl;i++)
+ if (S[i]) L[k++] = S[i];
+ else break;
+ }
+ L[k] = char(0);
+ }
+
+ void strcpy_n ( pstr d, cpstr s, int n ) {
+ // Copies at most n symbols from string s to d, but
+ // no more than strlen(s) (s must contain a terminating
+ // null). The terminating null IS NEITHER appended NOR
+ // copied to d.
+ int i;
+ i = 0;
+ while ((i<n) && (s[i])) {
+ d[i] = s[i];
+ i++;
+ }
+ }
+
+
+ void strcpy_n1 ( pstr d, cpstr s, int n ) {
+ // Copies at most n last symbols from string s to d, but
+ // no more than strlen(s) (s must contain a terminating null).
+ // The string in d is aligned to the right and added with
+ // spaces at the left, if necessary. The terminating null
+ // IS NEITHER appended NOR copied to d.
+ int i,k;
+ i = n-1;
+ k = strlen(s)-1;
+ while ((i>=0) && (k>=0))
+ d[i--] = s[k--];
+ while (i>=0)
+ d[i--] = ' ';
+ }
+
+ void strcpy_nr ( pstr d, cpstr s, int n ) {
+ // Copies at most n symbols from string s to d, but
+ // no more than strlen(s) (s must contain a terminating null).
+ // The string in d is aligned to the right and added with
+ // spaces at the left, if necessary. The terminating null
+ // IS NEITHER appended NOR copied to d.
+ int i,k;
+ i = n-1;
+ k = IMin(i,strlen(s)-1);
+ while ((i>=0) && (k>=0))
+ d[i--] = s[k--];
+ while (i>=0)
+ d[i--] = ' ';
+ }
+
+
+ void strcpy_ns ( pstr d, cpstr s, int n ) {
+ // Copies at most n symbols from string s to d, but
+ // no more than strlen(s) (s must contain a terminating
+ // null). The terminating null IS NEITHER appended NOR
+ // copied to d; rather, d is padded with spaces if
+ // strlen(s)<n.
+ int i;
+ i = 0;
+ while ((i<n) && (s[i])) {
+ d[i] = s[i];
+ i++;
+ }
+ while (i<n)
+ d[i++] = ' ';
+ }
+
+
+ pstr strcpy_cs ( pstr d, cpstr s ) {
+ // Copies string s to string d cutting all spaces at
+ // at the end. Thus, " abcde " will be copied like
+ // " abcde" (terminating null appended).
+ // The function returns d.
+ int i;
+ i = 0;
+ while (s[i]) {
+ d[i] = s[i];
+ i++;
+ }
+ i--;
+ while ((i>0) && (d[i]==' ')) i--;
+ if (d[i]==' ') d[i] = char(0);
+ else d[i+1] = char(0);
+ return d;
+ }
+
+
+ pstr strcpy_ncs ( pstr d, cpstr s, int n ) {
+ // Copies at most n characters from string s to string d
+ // cutting all spaces at at the end. Thus, " abcde " will
+ // be copied like " abc" at n=4 and like " abcde" at n>5
+ // (terminating null appended).
+ // The function returns d.
+ int i;
+ i = 0;
+ while (s[i] && (i<n)) {
+ d[i] = s[i];
+ i++;
+ }
+ i--;
+ while ((i>0) && (d[i]==' ')) i--;
+ if (d[i]==' ') d[i] = char(0);
+ else d[i+1] = char(0);
+ return d;
+ }
+
+ pstr strcpy_css ( pstr d, cpstr s ) {
+ // Copies string s to string d cutting all spaces at
+ // at the begining and at the end. Thus, " ab c de "
+ // will be copied like "ab c de" (terminating null
+ // appended).
+ // The function returns d.
+ int i,k;
+ i = 0;
+ while (s[i]==' ') i++;
+ k = 0;
+ while (s[i])
+ d[k++] = s[i++];
+ if (k>0) {
+ k--;
+ while ((k>0) && (d[k]==' ')) k--;
+ if (d[k]==' ') d[k] = char(0);
+ else d[k+1] = char(0);
+ } else
+ d[k] = char(0);
+ return d;
+ }
+
+ pstr strcpy_ncss ( pstr d, cpstr s, int n ) {
+ // Copies at most n characters from string s to string d cutting
+ // all spaces at the begining and at the end. Thus, " ab c de "
+ // will be copied like "ab" at n=3 (terminating null appended).
+ // The function returns d.
+ int i,k;
+ i = 0;
+ while ((s[i]==' ') && (i<n)) i++;
+ k = 0;
+ while (s[i] && (i<n))
+ d[k++] = s[i++];
+ if (k>0) {
+ k--;
+ while ((k>0) && (d[k]==' ')) k--;
+ if (d[k]==' ') d[k] = char(0);
+ else d[k+1] = char(0);
+ } else
+ d[k] = char(0);
+ return d;
+ }
+
+
+ pstr strcpy_n0 ( pstr d, cpstr s, int n ) {
+ // Copies at most n symbols from string s to d, but
+ // no more than strlen(s) (s must contain a terminating
+ // null). The terminating null IS appended to d.
+ // The function returns d.
+ int i;
+ i = 0;
+ while ((i<n) && (s[i])) {
+ d[i] = s[i];
+ i++;
+ }
+ d[i] = char(0);
+ return d;
+ }
+
+
+ int strlen_des ( cpstr s ) {
+ // strlen_des returns the length of a string as if all extra
+ // spaces from the latter have been deleted. Extra spaces
+ // include all leading and tracing spaces and any sequential
+ // spaces when more than one. The string does not change.
+ int i,l;
+ l = 0;
+ i = 0;
+ while (s[i]==' ') i++;
+ while (s[i]) {
+ if ((s[i]!=' ') || ((s[i+1]!=' ') && s[i+1]))
+ l++;
+ i++;
+ }
+ return l;
+ }
+
+ pstr strcpy_des ( pstr d, cpstr s ) {
+ // strcpy_des copies string s into string d removing all extra
+ // spaces from the latter. Extra spaces include all leading and
+ // tracing spaces and any sequential spaces when more than one.
+ int i,j;
+ j = 0;
+ i = 0;
+ while (s[i]==' ') i++;
+ while (s[i]) {
+ if ((s[i]!=' ') || ((s[i+1]!=' ') && s[i+1]))
+ d[j++] = s[i];
+ i++;
+ }
+ d[j] = char(0);
+ return d;
+ }
+
+ pstr strcat_des ( pstr d, cpstr s ) {
+ // strcpy_des appends string s to string d removing all extra
+ // spaces from the latter. Extra spaces include all leading and
+ // tracing spaces and any sequential spaces when more than one.
+ int i,j;
+ j = strlen(d);
+ i = 0;
+ while (s[i]==' ') i++;
+ while (s[i]) {
+ if ((s[i]!=' ') || ((s[i+1]!=' ') && s[i+1]))
+ d[j++] = s[i];
+ i++;
+ }
+ d[j] = char(0);
+ return d;
+ }
+
+
+ void PadSpaces ( pstr S, int len ) {
+ // Pads string S with spaces making its length equal to len.
+ // The terminating zero is added, so that S should reserve
+ // space of a minimum len+1 characters.
+ int i=strlen(S);
+ while (i<len) S[i++] = ' ';
+ S[i] = char(0);
+ }
+
+
+ pstr CutSpaces ( pstr S, int CutKey ) {
+ // Cuts spaces at the begining or end of string S
+ // according to the value of CutKey. THe function
+ // returns S;
+ int i,k;
+ i = 0;
+ k = 0;
+ if (CutKey & SCUTKEY_BEGIN)
+ while (S[i]==' ') i++;
+ if (k<i)
+ while (S[i])
+ S[k++] = S[i++];
+ else
+ k = strlen(S);
+ if ((CutKey & SCUTKEY_END) && (k>0)) {
+ k--;
+ while ((k>0) && (S[k]==' ')) k--;
+ if (S[k]!=' ') k++;
+ }
+ S[k] = char(0);
+ return S;
+ }
+
+
+ pstr DelSpaces ( pstr S, char c ) {
+ // Removes all spaces (or other symbols as specified by 'c')
+ // from the string. The string is then shrinked by the number
+ // of removed characters. Thus, " as ttt " becomes "asttt".
+ int i,j;
+ j = 0;
+ for (i=0;S[i];i++)
+ if (S[i]!=c) {
+ if (j<i) S[j] = S[i];
+ j++;
+ }
+ S[j] = char(0);
+ return S;
+ }
+
+ pstr EnforceSpaces ( pstr S ) {
+ int i,k;
+ i = 0;
+ while (S[i]) {
+ k = int(S[i]);
+ if ((k<32) && (k!=9) && (k!=10) && (k!=13)) S[i] = ' ';
+ i++;
+ }
+ return S;
+ }
+
+
+ // ----------------------------------------------------
+
+ #define _fbase 256
+ #define _rfbase 256.0
+ #define _fsign 0x80
+ #define _fsign1 0x7F
+
+ #ifdef UseDoubleFloat
+ # define _nfPowers 255
+ # define _nfPower0 127
+ # define _nfPower8 135
+ //# define _nfPower4 131
+ # define _nfPower4 130
+ #else
+ # define _nfPowers 31
+ # define _nfPower0 15
+ # define _nfPower8 19
+ # define _nfPower4 19
+ #endif
+
+ static realtype _fpower[_nfPowers+1];
+ static realtype _fpower8;
+ static realtype _fpower4;
+ static bool _old_float_unibin;
+
+ bool InitFPowers() {
+ int i;
+ _fpower[_nfPower0] = 1.0;
+ for (i=1;i<=_nfPower0;i++) {
+ _fpower[_nfPower0+i] = _fpower[_nfPower0+i-1]*_rfbase;
+ _fpower[_nfPower0-i] = _fpower[_nfPower0-i+1]/_rfbase;
+ }
+ _fpower[_nfPowers] = fMaxReal;
+ _fpower8 = _fpower[_nfPower8];
+ _fpower4 = _fpower[_nfPower4];
+ _old_float_unibin = false;
+ return true;
+ }
+
+ void __modify4() {
+ _fpower4 = _fpower[_nfPower4-1];
+ }
+
+ void set_new_float_unibin() {
+ _old_float_unibin = false;
+ }
+
+ bool is_new_float_unibin() {
+ return !_old_float_unibin;
+ }
+
+ void set_old_float_unibin() {
+ _old_float_unibin = true;
+ }
+
+ void int2UniBin ( int I, intUniBin iUB ) {
+ int n;
+ word j;
+ n = I;
+ for (j=0;j<sizeof(intUniBin);j++) {
+ iUB[j] = byte(n & 0xFF);
+ n >>= 8;
+ }
+ }
+
+ void short2UniBin ( short S, shortUniBin sUB ) {
+ int j,sh;
+ short n;
+ sh = 8*(sizeof(shortUniBin)-1);
+ for (j=sizeof(shortUniBin)-1;j>=0;j--) {
+ n = (S >> sh) & 0xFF;
+ sUB[j] = byte(n);
+ sh -= 8;
+ }
+ }
+
+ void long2UniBin ( long L, longUniBin lUB ) {
+ int j,sh;
+ long n;
+ sh = 8*(sizeof(longUniBin)-1);
+ for (j=sizeof(longUniBin)-1;j>=0;j--) {
+ n = (L >> sh) & 0xFF;
+ lUB[j] = byte(n);
+ sh -= 8;
+ }
+ }
+
+ void word2UniBin ( word W, wordUniBin wUB ) {
+ int j,sh;
+ word n;
+ sh = 8*(sizeof(wordUniBin)-1);
+ for (j=sizeof(wordUniBin)-1;j>=0;j--) {
+ n = (W >> sh) & 0xFF;
+ wUB[j] = byte(n);
+ sh -= 8;
+ }
+ }
+
+
+ void real2UniBin ( realtype R, realUniBin rUB ) {
+ int k1,k2,k;
+ realtype Q,L;
+ if (R>=0) Q = R;
+ else Q = -R;
+ k1 = 0;
+ k2 = _nfPowers;
+ do {
+ k = (k1+k2)/2;
+ if (Q>=_fpower[k]) k1 = k;
+ else k2 = k;
+ } while (k2>k1+1);
+ if (Q<=_fpower[0]) k2 = 0;
+ Q = (Q/_fpower[k2])*_fpower8;
+ rUB[0] = byte(k2);
+ for (k=sizeof(realUniBin)-1;k>0;k--) {
+ L = floor(Q/_rfbase);
+ rUB[k] = byte(int(Q-L*_rfbase));
+ Q = L;
+ }
+ if (R<0) rUB[1] |= _fsign;
+
+ }
+
+ void shortreal2UniBin ( shortreal R, shortrealUniBin srUB ) {
+ int k1,k2,k;
+ realtype Q,L;
+
+ if (R>=0) Q = R;
+ else Q = -R;
+ k1 = 0;
+ k2 = _nfPowers;
+ do {
+ k = (k1+k2)/2;
+ if (Q>=_fpower[k]) k1 = k;
+ else k2 = k;
+ } while (k2>k1+1);
+ if (Q<=_fpower[0]) k2 = 0;
+ Q = (Q/_fpower[k2])*_fpower4;
+ srUB[0] = byte(k2);
+ for (k=sizeof(shortrealUniBin)-1;k>0;k--) {
+ L = floor(Q/_rfbase);
+ srUB[k] = byte(int(Q-L*_rfbase));
+ Q = L;
+ }
+ if (R<0) srUB[1] |= _fsign;
+
+ }
+
+ /*
+ #undef _new_float_unibin
+
+ #ifdef _new_float_unibin
+
+ void float2UniBin ( realtype R, floatUniBin fUB ) {
+ int k1,k2,k;
+ realtype Q,L;
+
+ if (R>=0) Q = R;
+ else Q = -R;
+ k1 = 0;
+ k2 = _nfPowers;
+ do {
+ k = (k1+k2)/2;
+ if (Q>=_fpower[k]) k1 = k;
+ else k2 = k;
+ } while (k2>k1+1);
+ if (Q<=_fpower[0]) k2 = 0;
+ Q = (Q/_fpower[k2])*_fpower4;
+ fUB[0] = byte(k2);
+ for (k=sizeof(floatUniBin)-1;k>0;k--) {
+ L = floor(Q/_rfbase);
+ fUB[k] = byte(int(Q-L*_rfbase));
+ Q = L;
+ }
+ if (R<0) fUB[1] |= _fsign;
+
+ }
+
+ #else
+
+ void float2UniBin ( realtype R, floatUniBin fUB ) {
+ int k1,k2,k;
+ realtype Q,L;
+ if (R>=0) Q = R;
+ else Q = -R;
+ k1 = 0;
+ k2 = _nfPowers;
+ do {
+ k = (k1+k2)/2;
+ if (Q>=_fpower[k]) k1 = k;
+ else k2 = k;
+ } while (k2>k1+1);
+ if (Q<=_fpower[0]) k2 = 0;
+ Q = (Q/_fpower[k2])*_fpower8;
+ fUB[0] = byte(k2);
+ for (k=sizeof(realUniBin)-1;k>0;k--) {
+ L = floor(Q/_rfbase);
+ if (k<=sizeof(floatUniBin))
+ fUB[k] = byte(int(Q-L*_rfbase));
+ Q = L;
+ }
+ if (R<0) fUB[1] |= _fsign;
+
+ }
+
+ #endif
+ */
+
+ void float2UniBin ( realtype R, floatUniBin fUB ) {
+ int k1,k2,k;
+ realtype Q,L;
+
+ if (R>=0) Q = R;
+ else Q = -R;
+ k1 = 0;
+ k2 = _nfPowers;
+ do {
+ k = (k1+k2)/2;
+ if (Q>=_fpower[k]) k1 = k;
+ else k2 = k;
+ } while (k2>k1+1);
+ if (Q<=_fpower[0]) k2 = 0;
+ fUB[0] = byte(k2);
+
+ if (_old_float_unibin) {
+ // this is wrong but compatible with already existing files :(
+ // in the result, it gives errors in 6th digit at back conversion
+ Q = (Q/_fpower[k2])*_fpower8;
+ for (k=sizeof(realUniBin)-1;k>0;k--) {
+ L = floor(Q/_rfbase);
+ if (k<=(int)sizeof(floatUniBin))
+ fUB[k] = byte(int(Q-L*_rfbase));
+ Q = L;
+ }
+ } else {
+ // this is correct
+ Q = (Q/_fpower[k2])*_fpower4;
+ for (k=sizeof(floatUniBin)-1;k>0;k--) {
+ L = floor(Q/_rfbase);
+ fUB[k] = byte(int(Q-L*_rfbase));
+ Q = L;
+ }
+ }
+
+ //if (fUB[1] & _fsign) printf ( " error!\n" );
+
+ if (R<0) fUB[1] |= _fsign;
+
+ }
+
+
+ void UniBin2float ( floatUniBin fUB, realtype & R ) {
+ int j,s;
+
+ if (fUB[1] & _fsign) {
+ s = 1;
+ fUB[1] &= _fsign1;
+ } else
+ s = 0;
+
+ R = int(fUB[1]);
+
+ if (_old_float_unibin) {
+ // this is wrong and gives a conversion error in 6th digit :(
+ // we have to keep this for compatibility with already existing
+ // files
+ for (j=2;j<(int)sizeof(floatUniBin);j++)
+ R = R*_rfbase + int(fUB[j]);
+ for (j=sizeof(floatUniBin);j<(int)sizeof(realUniBin);j++)
+ R *= _rfbase;
+ R = (R/_fpower8)*_fpower[int(fUB[0])];
+ } else {
+ // this is correct
+ for (j=2;j<(int)sizeof(floatUniBin);j++)
+ R = R*_rfbase + int(fUB[j]);
+ R = (R/_fpower4)*_fpower[int(fUB[0])];
+ }
+ if (s) R = -R;
+ }
+
+
+ /* -------------------------------------------------------
+ This piece of code shows that float2Unibin - Unbin2float
+ pair does same-quality job as the native float - double
+ conversion:
+
+ InitMatType();
+ set_new_float_unibin();
+
+ floatUniBin fUB;
+ realUniBin rUB;
+ realtype maxsh = MaxShortReal/2.0; // max manageable /2!
+ float maxshf = maxsh;
+ realtype maxshr = maxshf;
+ realtype maxsh1;
+
+ float2UniBin ( maxsh,fUB );
+ UniBin2float ( fUB,maxsh1 );
+
+ printf ( " float\n %10.3f\n %10.3f\n %10.3f\n %10.3f\n",
+ maxsh,maxsh1,maxshf,maxshr );
+
+ maxsh = MaxShortReal;
+ real2UniBin ( maxsh,rUB );
+ UniBin2real ( rUB,maxsh1 );
+
+ printf ( " real\n %10.3f\n %10.3f\n",maxsh,maxsh1 );
+
+ ---- RESULTS:
+
+ float
+ 170099999999999990938343446679146987520.000
+ 170099999948540854500627141228603899904.000
+ 170100000027769017014891478822147850240.000
+ 170100000027769017014891478822147850240.000
+ real
+ 340199999999999981876686893358293975040.000
+ 340199999999999981876686893358293975040.000
+
+ -------------------------------------------------------------- */
+
+ /*
+ void shortreal2UniBin ( shortreal R, shortrealUniBin srUB ) {
+ int k1,k2,k;
+ realtype Q,L;
+
+ if (R>=0) Q = R;
+ else Q = -R;
+ k1 = 0;
+ k2 = _nfPowers;
+ do {
+ k = (k1+k2)/2;
+ if (Q>=_fpower[k]) k1 = k;
+ else k2 = k;
+ } while (k2>k1+1);
+ if (Q<=_fpower[0]) k2 = 0;
+ Q = (Q/_fpower[k2])*_fpower8;
+ srUB[0] = byte(k2);
+ for (k=sizeof(realUniBin)-1;k>0;k--) {
+ L = floor(Q/_rfbase);
+ if (k<=(int)sizeof(shortrealUniBin))
+ srUB[k] = byte(int(Q-L*_rfbase));
+ Q = L;
+ }
+ if (R<0) srUB[1] |= _fsign;
+
+ }
+
+ void float2UniBin ( realtype R, floatUniBin fUB ) {
+ int k1,k2,k;
+ realtype Q,L;
+
+ if (R>=0) Q = R;
+ else Q = -R;
+ k1 = 0;
+ k2 = _nfPowers;
+ do {
+ k = (k1+k2)/2;
+ if (Q>=_fpower[k]) k1 = k;
+ else k2 = k;
+ } while (k2>k1+1);
+ if (Q<=_fpower[0]) k2 = 0;
+ Q = (Q/_fpower[k2])*_fpower8;
+ fUB[0] = byte(k2);
+ for (k=sizeof(realUniBin)-1;k>0;k--) {
+ L = floor(Q/_rfbase);
+ if (k<=(int)sizeof(floatUniBin))
+ fUB[k] = byte(int(Q-L*_rfbase));
+ Q = L;
+ }
+ if (R<0) fUB[1] |= _fsign;
+
+ }
+ */
+
+ /*
+ void UniBin2int ( intUniBin iUB, int & I ) {
+ int j,n,sh;
+ sh = 8*sizeof(intUniBin);
+ I = 0x00;
+ for (j=sizeof(intUniBin)-1;j>=0;j--) {
+ sh -= 8;
+ n = byte(iUB[j]);
+ I = I | (n << sh);
+ }
+ }
+ */
+
+ void UniBin2int ( intUniBin iUB, int & I ) {
+ int j;
+ I = 0x00;
+ for (j=sizeof(intUniBin)-1;j>=0;j--) {
+ I <<= 8;
+ I |= int(iUB[j]);
+ }
+ }
+
+ void UniBin2short ( shortUniBin sUB, short & S ) {
+ int j,sh;
+ short n;
+ sh = 8*sizeof(shortUniBin);
+ S = 0x00;
+ for (j=sizeof(shortUniBin)-1;j>=0;j--) {
+ sh -= 8;
+ n = byte(sUB[j]);
+ S = S | (n << sh);
+ }
+ }
+
+ void UniBin2long ( longUniBin lUB, long & L ) {
+ int j,sh;
+ long n;
+ sh = 8*sizeof(longUniBin);
+ L = 0x00;
+ for (j=sizeof(longUniBin)-1;j>=0;j--) {
+ sh -= 8;
+ n = byte(lUB[j]);
+ L = L | (n << sh);
+ }
+ }
+
+ void UniBin2word ( wordUniBin wUB, word & W ) {
+ int j,sh;
+ word n;
+ sh = 8*sizeof(wordUniBin);
+ W = 0x00;
+ for (j=sizeof(wordUniBin)-1;j>=0;j--) {
+ sh -= 8;
+ n = byte(wUB[j]);
+ W = W | (n << sh);
+ }
+ }
+
+ void UniBin2real ( realUniBin rUB, realtype & R ) {
+ int j,s;
+ if (rUB[1] & _fsign) {
+ s = 1;
+ rUB[1] &= _fsign1;
+ } else
+ s = 0;
+ R = int(rUB[1]);
+ for (j=2;j<(int)sizeof(realUniBin);j++)
+ R = R*_rfbase + int(rUB[j]);
+ R = (R/_fpower8)*_fpower[int(rUB[0])];
+ if (s) R = -R;
+ }
+
+ void UniBin2shortreal ( shortrealUniBin srUB, shortreal & R ) {
+ int j,s;
+ if (srUB[1] & _fsign) {
+ s = 1;
+ srUB[1] &= _fsign1;
+ } else
+ s = 0;
+ R = int(srUB[1]);
+ for (j=2;j<(int)sizeof(shortrealUniBin);j++)
+ R = R*_rfbase + int(srUB[j]);
+ R = (R/_fpower4)*_fpower[int(srUB[0])];
+ if (s) R = -R;
+ }
+
+ /*
+ #ifdef _new_float_unibin
+
+ void UniBin2float ( floatUniBin fUB, realtype & R ) {
+ int j,s;
+ if (fUB[1] & _fsign) {
+ s = 1;
+ fUB[1] &= _fsign1;
+ } else
+ s = 0;
+ R = int(fUB[1]);
+ for (j=2;j<(int)sizeof(floatUniBin);j++)
+ R = R*_rfbase + int(fUB[j]);
+ R = (R/_fpower4)*_fpower[int(fUB[0])];
+ if (s) R = -R;
+ }
+
+ #else
+
+ void UniBin2float ( floatUniBin fUB, realtype & R ) {
+ int j,s;
+ if (fUB[1] & _fsign) {
+ s = 1;
+ fUB[1] &= _fsign1;
+ } else
+ s = 0;
+ R = int(fUB[1]);
+ for (j=2;j<sizeof(floatUniBin);j++)
+ R = R*_rfbase + int(fUB[j]);
+ for (j=sizeof(floatUniBin);j<sizeof(realUniBin);j++)
+ R *= _rfbase;
+ R = (R/_fpower8)*_fpower[int(fUB[0])];
+ if (s) R = -R;
+ }
+
+ #endif
+ */
+
+
+
+
+
+ /*
+ void UniBin2shortreal ( shortrealUniBin srUB, shortreal & R ) {
+ int j,s;
+ if (srUB[1] & _fsign) {
+ s = 1;
+ srUB[1] &= _fsign1;
+ } else
+ s = 0;
+ R = int(srUB[1]);
+ for (j=2;j<(int)sizeof(shortrealUniBin);j++)
+ R = R*_rfbase + int(srUB[j]);
+ for (j=sizeof(shortrealUniBin);j<(int)sizeof(realUniBin);j++)
+ R *= _rfbase;
+ R = (R/_fpower8)*_fpower[int(srUB[0])];
+ if (s) R = -R;
+ }
+
+ void UniBin2float ( floatUniBin fUB, realtype & R ) {
+ int j,s;
+ if (fUB[1] & _fsign) {
+ s = 1;
+ fUB[1] &= _fsign1;
+ } else
+ s = 0;
+ R = int(fUB[1]);
+ for (j=2;j<(int)sizeof(floatUniBin);j++)
+ R = R*_rfbase + int(fUB[j]);
+ for (j=sizeof(floatUniBin);j<(int)sizeof(realUniBin);j++)
+ R *= _rfbase;
+ R = (R/_fpower8)*_fpower[int(fUB[0])];
+ if (s) R = -R;
+ }
+ */
+
+
+ void mem_write ( int I, pstr S, int & l ) {
+ intUniBin iUB;
+ int2UniBin ( I,iUB );
+ memcpy ( &(S[l]),iUB,sizeof(intUniBin) );
+ l += sizeof(intUniBin);
+ S[l] = char(0);
+ }
+
+ void mem_write ( short I, pstr S, int & l ) {
+ shortUniBin sUB;
+ short2UniBin ( I,sUB );
+ memcpy ( &(S[l]),sUB,sizeof(shortUniBin) );
+ l += sizeof(shortUniBin);
+ S[l] = char(0);
+ }
+
+ void mem_write ( long I, pstr S, int & l ) {
+ longUniBin lUB;
+ long2UniBin ( I,lUB );
+ memcpy ( &(S[l]),lUB,sizeof(longUniBin) );
+ l += sizeof(longUniBin);
+ S[l] = char(0);
+ }
+
+ void mem_write ( word W, pstr S, int & l ) {
+ wordUniBin wUB;
+ word2UniBin ( W,wUB );
+ memcpy ( &(S[l]),wUB,sizeof(wordUniBin) );
+ l += sizeof(wordUniBin);
+ S[l] = char(0);
+ }
+
+ void mem_write ( realtype R, pstr S, int & l ) {
+ realUniBin rUB;
+ real2UniBin ( R,rUB );
+ memcpy ( &(S[l]),rUB,sizeof(realUniBin) );
+ l += sizeof(realUniBin);
+ S[l] = char(0);
+ }
+
+ void mem_write ( shortreal R, pstr S, int & l ) {
+ shortrealUniBin srUB;
+ shortreal2UniBin ( R,srUB );
+ memcpy ( &(S[l]),srUB,sizeof(shortrealUniBin) );
+ l += sizeof(shortrealUniBin);
+ S[l] = char(0);
+ }
+
+ void mem_write ( pstr L, int len, pstr S, int & l ) {
+ memcpy ( &(S[l]),L,len );
+ l += len;
+ S[l] = char(0);
+ }
+
+ void mem_write ( pstr L, pstr S, int & l ) {
+ int len;
+ if (L) len = strlen(L);
+ else len = 0;
+ mem_write ( len,S,l );
+ if (len>0) {
+ memcpy ( &(S[l]),L,len );
+ l += len;
+ S[l] = char(0);
+ }
+ }
+
+ void mem_write ( bool B, pstr S, int & l ) {
+ if (B) S[l++] = 'Y';
+ else S[l++] = 'N';
+ S[l] = char(0);
+ }
+
+ void mem_write_byte ( byte B, pstr S, int & l ) {
+ S[l++] = char(B);
+ S[l] = char(0);
+ }
+
+
+ void mem_read ( int & I, cpstr S, int & l ) {
+ intUniBin iUB;
+ memcpy ( iUB,&(S[l]),sizeof(intUniBin) );
+ l += sizeof(intUniBin);
+ UniBin2int ( iUB,I );
+ }
+
+ void mem_read ( short & I, cpstr S, int & l ) {
+ shortUniBin sUB;
+ memcpy ( sUB,&(S[l]),sizeof(shortUniBin) );
+ l += sizeof(shortUniBin);
+ UniBin2short ( sUB,I );
+ }
+
+ void mem_read ( long & I, cpstr S, int & l ) {
+ longUniBin lUB;
+ memcpy ( lUB,&(S[l]),sizeof(longUniBin) );
+ l += sizeof(longUniBin);
+ UniBin2long ( lUB,I );
+ }
+
+ void mem_read ( word & W, cpstr S, int & l ) {
+ wordUniBin wUB;
+ memcpy ( wUB,&(S[l]),sizeof(wordUniBin) );
+ l += sizeof(wordUniBin);
+ UniBin2word ( wUB,W );
+ }
+
+ void mem_read ( realtype & R, cpstr S, int & l ) {
+ realUniBin rUB;
+ memcpy ( rUB,&(S[l]),sizeof(realUniBin) );
+ l += sizeof(realUniBin);
+ UniBin2real ( rUB,R );
+ }
+
+ void mem_read ( shortreal & R, cpstr S, int & l ) {
+ shortrealUniBin srUB;
+ memcpy ( srUB,&(S[l]),sizeof(shortrealUniBin) );
+ l += sizeof(shortrealUniBin);
+ UniBin2shortreal ( srUB,R );
+ }
+
+ void mem_read ( pstr L, int len, cpstr S, int & l ) {
+ memcpy ( L,&(S[l]),len );
+ l += len;
+ }
+
+ void mem_read ( pstr & L, cpstr S, int & l ) {
+ int len;
+ if (L) {
+ delete[] L;
+ L = NULL;
+ }
+ mem_read ( len,S,l );
+ if (len>0) {
+ L = new char[len+1];
+ memcpy ( L,&(S[l]),len );
+ L[len] = char(0);
+ l += len;
+ }
+ }
+
+ void mem_read ( bool & B, cpstr S, int & l ) {
+ B = (S[l++]=='Y');
+ }
+
+ void mem_read_byte ( byte & B, cpstr S, int & l ) {
+ B = byte(S[l++]);
+ }
+
+ // -------------------------------------------------------
+
+ bool InitMatType() {
+ MachEps = MachinEps();
+ floatMachEps = floatMachinEps();
+ LnMaxReal = log(fMaxReal);
+ LnMinReal = log(fMinReal);
+ LnMaxRealExp = LnMaxReal;
+ LnMinRealExp = LnMinReal;
+ InitFPowers();
+ return true;
+ }
+
+}
+
+/* =================================================== */
+
+// *** end of <MatType>
diff --git a/mmdb2/mmdb_mattype.h b/mmdb2/mmdb_mattype.h
new file mode 100644
index 0000000..08cf55c
--- /dev/null
+++ b/mmdb2/mmdb_mattype.h
@@ -0,0 +1,652 @@
+// $Id: mmdb_mattype.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 10.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MatType_ <interface>
+// ~~~~~~~~~
+// **** Functions :
+// ~~~~~~~~~~~
+// GetString ( reads substring from a string )
+// GetStrTer ( reads substring and put term-ing null )
+// strcpy_n ( copies not more than n characters )
+// strcpy_ns ( like strcpy_ns and pads with spaces )
+// strcpy_n0 ( like strcpy_n and adds terminating 0 )
+// PadSpaces ( pads a string with spaces )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+
+#ifndef __MMDB_MatType__
+#define __MMDB_MatType__
+
+#include <math.h>
+
+#define UseDoubleFloat
+
+#ifndef __ClassMacros
+
+# define __ClassMacros
+
+ // A Class definition macros
+# define DefineClass(ClassName) \
+ class ClassName; \
+ typedef ClassName * P##ClassName; \
+ typedef ClassName & R##ClassName; \
+ typedef P##ClassName * PP##ClassName; \
+ typedef P##ClassName & RP##ClassName;
+
+ // A Structure definition macros
+# define DefineStructure(StructureName) \
+ struct StructureName; \
+ typedef StructureName * P##StructureName; \
+ typedef StructureName & R##StructureName; \
+ typedef P##StructureName * PP##StructureName; \
+ typedef P##StructureName & RP##StructureName;
+
+#endif
+
+#define UNUSED_ARGUMENT(x) (void)x
+
+// -----------------------------------------------------
+
+namespace mmdb {
+
+#ifdef UseDoubleFloat
+
+ typedef double realtype;
+ const realtype MinReal = 2.2250e-307;
+ const realtype MaxReal = 1.7976e+308;
+ const realtype fMinReal = 2.2250e-307;
+ const realtype fMaxReal = 1.7976e+308;
+
+#else
+
+ typedef float realtype;
+ const realtype MinReal = 1.1755e-38;
+ const realtype MaxReal = 3.4020e+38;
+ const realtype fMinReal = 1.1755e-38;
+ const realtype fMaxReal = 3.4020e+38;
+
+#endif
+
+ typedef float shortreal;
+ const shortreal MinShortReal = 1.1755e-38;
+ const shortreal MaxShortReal = 3.4020e+38;
+
+#define strrchr LastOccurence
+#define fstrrchr LastOccurence
+#define strchr FirstOccurence
+#define fstrchr FirstOccurence
+
+ typedef char * pstr;
+ typedef const char * cpstr;
+ typedef unsigned int word;
+ typedef unsigned char byte;
+ typedef signed char short_int;
+// typedef byte Boolean;
+ typedef unsigned int word2;
+ typedef byte * byteptr;
+ typedef unsigned long lword;
+
+ typedef byte intUniBin [4];
+ typedef byte shortUniBin [2];
+ typedef byte longUniBin [4];
+ typedef byte wordUniBin [4];
+ typedef byte realUniBin [10];
+ typedef byte floatUniBin [5];
+ typedef byte shortrealUniBin[5];
+
+#ifdef _WIN32
+ pstr strcasestr ( pstr s1, cpstr s2 );
+#endif
+
+#ifdef _MSC_VER
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp
+#endif
+
+ const int MaxInt = 32767;
+ const int MinInt = -32768;
+ const word MaxWord = 65535L;
+ const long int MaxInt4 = 2147483647L;
+
+ // MinInt4 would have to be defined as -2147483648,
+ // however some compilers do not like that. To be on safe,
+ // we define it as -2147483647:
+ const long int MinInt4 = -2147483647;
+ const lword MaxWord4 = 4294967295UL;
+
+ const realtype Pi = 3.141592653589793238462643;
+ const realtype Eu = 2.718281828459045235360287;
+ const realtype ln10 = 2.3025850929940456840179915;
+
+ // *** vectors X[1..N] :
+ typedef realtype * rvector;
+ typedef int * ivector;
+ typedef word * wvector;
+ typedef byte * bvector;
+ typedef bool * ovector;
+ typedef long * lvector;
+ typedef lword * lwvector;
+ typedef pstr * psvector;
+
+ // *** matrices X[1..N][1..M] :
+ typedef rvector * rmatrix;
+ typedef ivector * imatrix;
+ typedef wvector * wmatrix;
+ typedef bvector * bmatrix;
+ typedef ovector * omatrix;
+ typedef lvector * lmatrix;
+ typedef lwvector * lwmatrix;
+ typedef psvector * psmatrix;
+
+ // *** matrices X[1..N][1..M][1..K] :
+ typedef rmatrix * rmatrix3;
+ typedef imatrix * imatrix3;
+ typedef wmatrix * wmatrix3;
+ typedef bmatrix * bmatrix3;
+ typedef omatrix * omatrix3;
+ typedef lmatrix * lmatrix3;
+ typedef lwmatrix * lwmatrix3;
+ typedef psmatrix * psmatrix3;
+
+
+ // ------------------------------------------------------------
+
+ // Initialization. Some C++ enviroments do not do call
+ // InitMatType() automatically, therefore it is always
+ // advisable to call InitMatType() explicitely from the top of
+ // main(). It is completely harmless and cheap (although
+ // unnecessary) to call InitMatType() multiple times.
+ extern bool InitMatType();
+
+ // ------------------------------------------------------------
+
+ inline int mround ( realtype X ) { return (int)floor(X+0.5); }
+ inline int ifloor ( realtype X ) { return (int)floor(X); }
+ inline int Abs ( int x ) { return ( x >= 0 ? x : -x ); }
+
+ inline void ISwap ( int & x, int & y )
+ { int b = x; x = y; y = b; }
+
+ inline void WSwap ( word & x, word & y )
+ { word b = x; x = y; y = b; }
+
+ inline void BSwap ( byte & x, byte & y )
+ { byte b = x; x = y; y = b; }
+
+ inline void OSwap ( bool & x, bool & y )
+ { bool b = x; x = y; y = b; }
+
+ inline void LSwap ( long & x, long & y )
+ { long b = x; x = y; y = b; }
+
+ inline void RSwap ( realtype & x, realtype & y )
+ { realtype b = x; x = y; y = b; }
+
+ inline realtype RMax ( const realtype x1, const realtype x2 )
+ { return ( x1 > x2 ? x1 : x2 ); }
+
+ inline long LMax ( const long x1, const long x2 )
+ { return ( x1 > x2 ? x1 : x2 ); }
+
+ inline word WMax ( const word x1, const word x2 )
+ { return ( x1 > x2 ? x1 : x2 ); }
+
+ inline int IMax ( const int x1, const int x2 )
+ { return ( x1 > x2 ? x1 : x2 ); }
+
+ inline realtype RMin ( const realtype x1, const realtype x2 )
+ { return ( x1 < x2 ? x1 : x2 ); }
+
+ inline long LMin ( const long x1, const long x2 )
+ { return ( x1 < x2 ? x1 : x2 ); }
+
+ inline word WMin ( const word x1, const word x2 )
+ { return ( x1 < x2 ? x1 : x2 ); }
+
+ inline int IMin ( const int x1, const int x2 )
+ { return ( x1 < x2 ? x1 : x2 ); }
+
+ inline realtype fsign ( const realtype x1, const realtype x2 ) {
+ realtype ax;
+ if (x1>=0.0) ax = x1;
+ else ax = -x1;
+ return ( x2 >= 0.0 ? ax : -ax );
+ }
+
+
+ // ------------------------------------------------------------
+
+ // Allocated vectors are enumerated as [Shift..Shift+N-1]
+ // rather than [0..N-1] !
+ // Get-functions return <true> if memory was allocated;
+ // if allocation attemt fails, vector is assigned with NULL
+
+ extern bool GetVectorMemory ( rvector & V, word N, word Shift=1 );
+ extern bool GetVectorMemory ( ivector & I, word N, word Shift=1 );
+ extern bool GetVectorMemory ( wvector & W, word N, word Shift=1 );
+ extern bool GetVectorMemory ( bvector & B, word N, word Shift=1 );
+ extern bool GetVectorMemory ( ovector & O, word N, word Shift=1 );
+ extern bool GetVectorMemory ( lvector & L, word N, word Shift=1 );
+ extern bool GetVectorMemory ( lwvector & L, word N, word Shift=1 );
+ extern bool GetVectorMemory ( psvector & P, word N, word Shift=1 );
+
+ // Shift at deallocation MUST be the same as that at allocation !
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // Free-functions do nothing if vector has value NULL (e.g.
+ // after unsuccessful allocation).
+
+ extern void FreeVectorMemory ( rvector & V, word Shift=1 );
+ extern void FreeVectorMemory ( ivector & I, word Shift=1 );
+ extern void FreeVectorMemory ( wvector & W, word Shift=1 );
+ extern void FreeVectorMemory ( bvector & B, word Shift=1 );
+ extern void FreeVectorMemory ( ovector & O, word Shift=1 );
+ extern void FreeVectorMemory ( lvector & L, word Shift=1 );
+ extern void FreeVectorMemory ( lwvector & L, word Shift=1 );
+ extern void FreeVectorMemory ( psvector & P, word Shift=1 );
+
+ // -------------------------------------------------------------
+
+ // Allocated matrices are enumerated as
+ // [ShiftN..ShiftN+N-1, ShiftM..ShiftM+M-1]
+ // rather than [0..N-1,0..M-1] !
+ // Get-functions return <true> if memory was allocated;
+ // if allocation attemt fails, matrix is assigned with NULL
+ // Free-functions do nothing if matrix has value NULL (e.g.
+ // after unsuccessful allocation).
+
+ extern bool GetMatrixMemory
+ ( rmatrix & A, word N, word M, word ShiftN=1, word ShiftM=1 );
+ extern bool GetMatrixMemory
+ ( imatrix & A, word N, word M, word ShiftN=1, word ShiftM=1 );
+ extern bool GetMatrixMemory
+ ( wmatrix & W, word N, word M, word ShiftN=1, word ShiftM=1 );
+ extern bool GetMatrixMemory
+ ( bmatrix & B, word N, word M, word ShiftN=1, word ShiftM=1 );
+ extern bool GetMatrixMemory
+ ( omatrix & O, word N, word M, word ShiftN=1, word ShiftM=1 );
+ extern bool GetMatrixMemory
+ ( lmatrix & L, word N, word M, word ShiftN=1, word ShiftM=1 );
+ extern bool GetMatrixMemory
+ ( lwmatrix & L, word N, word M, word ShiftN=1, word ShiftM=1 );
+ extern bool GetMatrixMemory
+ ( psmatrix & P, word N, word M, word ShiftN=1, word ShiftM=1 );
+
+ // ShiftN and ShiftM at deallocation MUST be the same as those at
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // allocation !
+ // ~~~~~~~~~~~~~
+
+ extern void FreeMatrixMemory ( rmatrix & A, word N,
+ word ShiftN=1, word ShiftM=1 );
+ extern void FreeMatrixMemory ( imatrix & A, word N,
+ word ShiftN=1, word ShiftM=1 );
+ extern void FreeMatrixMemory ( wmatrix & W, word N,
+ word ShiftN=1, word ShiftM=1 );
+ extern void FreeMatrixMemory ( bmatrix & B, word N,
+ word ShiftN=1, word ShiftM=1 );
+ extern void FreeMatrixMemory ( omatrix & O, word N,
+ word ShiftN=1, word ShiftM=1 );
+ extern void FreeMatrixMemory ( lmatrix & L, word N,
+ word ShiftN=1, word ShiftM=1 );
+ extern void FreeMatrixMemory ( lwmatrix & L, word N,
+ word ShiftN=1, word ShiftM=1 );
+ extern void FreeMatrixMemory ( psmatrix & P, word N,
+ word ShiftN=1, word ShiftM=1 );
+
+
+ // -------------------------------------------------------------
+ // 3D matrices
+
+ extern bool GetMatrix3Memory
+ ( rmatrix3 & A, word N, word M, word K,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern bool GetMatrix3Memory
+ ( imatrix3 & A, word N, word M, word K,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern bool GetMatrix3Memory
+ ( wmatrix3 & A, word N, word M, word K,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern bool GetMatrix3Memory
+ ( bmatrix3 & A, word N, word M, word K,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern bool GetMatrix3Memory
+ ( omatrix3 & A, word N, word M, word K,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern bool GetMatrix3Memory
+ ( lmatrix3 & A, word N, word M, word K,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern bool GetMatrix3Memory
+ ( lwmatrix3 & A, word N, word M, word K,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern bool GetMatrix3Memory
+ ( psmatrix3 & A, word N, word M, word K,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+
+ //
+ // ShiftN, ShiftM and ShiftK at deallocation MUST be
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // the same as those at allocation !
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ extern void FreeMatrix3Memory
+ ( rmatrix3 & A, word N, word M,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern void FreeMatrix3Memory
+ ( imatrix3 & A, word N, word M,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern void FreeMatrix3Memory
+ ( wmatrix3 & A, word N, word M,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern void FreeMatrix3Memory
+ ( bmatrix3 & A, word N, word M,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern void FreeMatrix3Memory
+ ( omatrix3 & A, word N, word M,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern void FreeMatrix3Memory
+ ( lmatrix3 & A, word N, word M,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern void FreeMatrix3Memory
+ ( lwmatrix3 & A, word N, word M,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+ extern void FreeMatrix3Memory
+ ( psmatrix3 & A, word N, word M,
+ word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+
+ // -------------------------------------------------------------
+
+ extern realtype MachEps;
+ extern realtype floatMachEps;
+ extern realtype LnMaxReal;
+ extern realtype LnMinReal;
+
+ extern realtype MachinEps ();
+ extern realtype floatMachinEps();
+ extern realtype frac ( realtype R );
+ extern long mod ( long x, long y );
+ extern realtype Pow ( realtype X, int y );
+ extern realtype Pow1 ( realtype X, realtype Y );
+ extern realtype Exp ( realtype X ); // use to avoid catastrophies
+ extern bool Odd ( int i );
+ extern long HexValL ( cpstr S );
+ extern long OctValL ( cpstr S );
+ extern long BinValL ( cpstr S );
+ extern pstr BinValS ( long L, pstr S ); // S[sizeof(long)+1] at least
+
+ extern pstr ParamStr ( pstr D, cpstr S, realtype V, int M=5,
+ cpstr S1=(pstr)"" );
+ extern pstr ParamStr ( pstr D, cpstr S, realtype V, int M,
+ cpstr S1, realtype V2, int M2=5,
+ cpstr S2=(pstr)"" );
+
+
+ // ---------- Strings
+
+ // CreateCopy(..) allocates Dest string and copies the contents of
+ // Source into it. If Dest is not NULL prior calling the function,
+ // it is attempted to deallocate first.
+
+ extern pstr CreateCopy ( pstr & Dest, cpstr Source );
+ extern pstr CreateCopy_n ( pstr & Dest, cpstr Source, int n );
+
+ extern pstr CreateConcat ( pstr & Dest, cpstr Source );
+ extern pstr CreateConcat ( pstr & Dest, cpstr Source1,
+ cpstr Source2 );
+ extern pstr CreateConcat ( pstr & Dest, cpstr Source1,
+ cpstr Source2,
+ cpstr Source3 );
+ extern pstr CreateConcat ( pstr & Dest, cpstr Source1,
+ cpstr Source2,
+ cpstr Source3,
+ cpstr Source4 );
+ extern pstr CreateConcat ( pstr & Dest, cpstr Source1,
+ cpstr Source2,
+ cpstr Source3,
+ cpstr Source4,
+ cpstr Source5 );
+
+ extern pstr CreateCopCat ( pstr & Dest, cpstr Source1,
+ cpstr Source2,
+ cpstr Source3,
+ cpstr Source4,
+ cpstr Source5 );
+ extern pstr CreateCopCat ( pstr & Dest, cpstr Source1,
+ cpstr Source2,
+ cpstr Source3,
+ cpstr Source4 );
+ extern pstr CreateCopCat ( pstr & Dest, cpstr Source1,
+ cpstr Source2,
+ cpstr Source3 );
+ extern pstr CreateCopCat ( pstr & Dest, cpstr Source1,
+ cpstr Source2 );
+
+ extern pstr LastOccurence ( cpstr S , char c );
+ extern pstr FirstOccurence ( cpstr S , char c );
+ extern int indexOf ( cpstr S , char c );
+ extern pstr FirstOccurence ( cpstr S, int Slen,
+ cpstr Q, int Qlen );
+ extern int indexOf ( cpstr S, int Slen,
+ cpstr Q, int Qlen );
+
+ extern pstr LowerCase ( pstr s );
+ extern pstr UpperCase ( pstr s );
+
+ // GetString(..) copies first M characters of string S into string
+ // L, appending the terminating null. If S contains less then M
+ // characters, L will be padded with spaces.
+ extern void GetString ( pstr L, cpstr S, int M );
+
+ // GetStrTer(..) copies at least n (or LMax if LMax<n) first symbols
+ // of string S into string L, then continues copying until first space
+ // or terminating null is found. If the terminating null is met among
+ // the first n characters or if SMax<n, the string L will be padded
+ // with spaces till the length of minimum of n and LMax and then
+ // terminated with the null.
+ // LMax and SMax are the buffer lengths of L and S,
+ // respectively. Even if no space is found, the last character
+ // in L will be the terminating null.
+ extern void GetStrTer ( pstr L, cpstr S, int n, int LMax,
+ int SMax );
+
+
+ // Version of GetStrTer(..) allowing for spaces in the string.
+ //
+ // Copies at least n (or LMax if LMax<n) first symbols of
+ // string S into string L, then continues copying until first
+ // terminating null is found. If the terminating null
+ // is met among the first n characters or if SMax<n, the string
+ // L will be padded with spaces till the length of minimum of
+ // n and LMax and then terminated with the null.
+ // SMax are buffer lengths of L and S, respectively. The last
+ // character in L will be the terminating null.
+ extern void GetStrTerWin32File ( pstr L, cpstr S, int n,
+ int LMax, int SMax );
+
+
+ // strcpy_n(..) copies at most n symbols from string s to d,
+ // but no more than strlen(s) (s must contain a terminating
+ // null). The terminating null IS NEITHER appended OR copied
+ // to d.
+ extern void strcpy_n ( pstr d, cpstr s, int n );
+
+ // strcpy_n1(..) copies at most n last symbols from string s
+ // to d, but no more than strlen(s) (s must contain a terminating
+ // null). The string in d is aligned to the right and added with
+ // spaces at the left, if necessary. The terminating null
+ // IS NEITHER appended OR copied to d.
+ extern void strcpy_n1 ( pstr d, cpstr s, int n );
+
+ // Copies at most n symbols from string s to d, but no
+ // more than strlen(s) (s must contain a terminating null).
+ // The string in d is aligned to the right and added with
+ // spaces at the left, if necessary. The terminating null
+ // IS NEITHER appended NOR copied to d.
+ extern void strcpy_nr ( pstr d, cpstr s, int n );
+
+ // strcpy_ns(..) copies at most n symbols from string s to d,
+ // but no more than strlen(s) (s must contain a terminating
+ // null). The terminating null IS NEITHER appended NOR copied
+ // to d; rather, d is padded with spaces up to the length of n
+ // if strlen(s)<n.
+ extern void strcpy_ns ( pstr d, cpstr s, int n );
+
+ // strcpy_cs(..) copies string s to string d cutting all
+ // spaces at the end. Thus, " abcde " will be copied
+ // like " abcde" (terminating null appended).
+ // The function returns d.
+ extern pstr strcpy_cs ( pstr d, cpstr s );
+
+ // strcpy_ncs(..) copies at most n characters from string s
+ // to string d cutting all spaces at at the end. Thus, " abcde "
+ // will be copied like " abc" at n=4 and like " abcde" at n>5
+ // (terminating null appended).
+ // The function returns d.
+ extern pstr strcpy_ncs ( pstr d, cpstr s, int n );
+
+ // strcpy_css(..) copies string s to string d cutting all
+ // spaces at the begining and at the end. Thus, " ab c de "
+ // will be copied like "ab c de" (terminating null appended).
+ // The function returns d.
+ extern pstr strcpy_css ( pstr d, cpstr s );
+
+ // strcpy_ncss(..) copies at most n characters from string s
+ // to string d cutting all spaces at the begining and at the end.
+ // Thus, " ab c de " will be copied like "ab" at n=3 (terminating
+ // null appended).
+ // The function returns d.
+ extern pstr strcpy_ncss ( pstr d, cpstr s, int n );
+
+ // strcpy_n0(..) copies at most n symbols from string s to d,
+ // but no more than strlen(s) (s must contain a terminating
+ // null). The terminating null IS appended to d.
+ // The function returns d.
+ extern pstr strcpy_n0 ( pstr d, cpstr s, int n );
+
+ // strlen_des returns the length of a string as if all extra
+ // spaces from the latter have been deleted. Extra spaces
+ // include all leading and tracing spaces and any sequential
+ // spaces when more than one. The string does not change.
+ extern int strlen_des ( cpstr s );
+
+ // strcpy_des copies string s into string d removing all extra
+ // spaces from the latter. Extra spaces include all leading and
+ // tracing spaces and any sequential spaces when more than one.
+ extern pstr strcpy_des ( pstr d, cpstr s );
+
+ // strcat_des appends string s to string d removing all extra
+ // spaces from the latter. Extra spaces include all leading and
+ // tracing spaces and any sequential spaces when more than one.
+ extern pstr strcat_des ( pstr d, cpstr s );
+
+ // PadSpaces(..) pads string S with spaces making its length
+ // equal to len. The terminating zero is added, so that S should
+ // reserve space of a minimum len+1 characters.
+ extern void PadSpaces ( pstr S, int len );
+
+ enum SCUTKEY {
+ SCUTKEY_BEGIN = 0x00000001,
+ SCUTKEY_END = 0x00000002,
+ SCUTKEY_BEGEND = 0x00000003
+ };
+
+ // CutSpaces(..) cuts spaces at the begining or end of
+ // string S according to the value of CutKey. The function
+ // returns S.
+ extern pstr CutSpaces ( pstr S, int CutKey );
+
+ // DelSpaces(..) removes all spaces (or other symbols as
+ // specified by 'c') from the string. The string is then
+ // shrinked by the number of removed characters. Thus,
+ // " as ttt " becomes "asttt".
+ extern pstr DelSpaces ( pstr S, char c=' ' );
+
+ // EnforceSpaces(..) replaces all unprintable characters,
+ // except <CR>, <LF>, <TAB> and some others, for spaces
+ extern pstr EnforceSpaces ( pstr S );
+
+ // -------------------------------------------------------------
+
+ /// This call will produce correct floats in universal binaries but
+ /// make them incompatible with old files. Without this call, float
+ /// read/write will result in error after 6th digit.
+ /// UniBin read/write of other types (realtype, shortreal, int etc)
+ /// is not affected by this call, and to the best of knowledge is
+ /// correct (no loss of precision).
+ extern void set_new_float_unibin();
+ extern bool is_new_float_unibin();
+ extern void set_old_float_unibin();
+
+ extern void __modify4();
+
+ extern void int2UniBin ( int I, intUniBin iUB );
+ extern void short2UniBin ( short S, shortUniBin sUB );
+ extern void long2UniBin ( long L, longUniBin lUB );
+ extern void word2UniBin ( word W, wordUniBin wUB );
+ extern void real2UniBin ( realtype R, realUniBin rUB );
+ extern void float2UniBin ( realtype R, floatUniBin fUB );
+ extern void shortreal2UniBin ( shortreal R, shortrealUniBin srUB );
+ extern void UniBin2int ( intUniBin iUB, int & I );
+ extern void UniBin2short ( shortUniBin sUB, short & S );
+ extern void UniBin2long ( longUniBin lUB, long & L );
+ extern void UniBin2word ( wordUniBin wUB, word & W );
+ extern void UniBin2real ( realUniBin rUB, realtype & R );
+ extern void UniBin2shortreal ( shortrealUniBin srUB, shortreal & R );
+ extern void UniBin2float ( floatUniBin fUB, realtype & R );
+
+ extern void mem_write ( int I, pstr S, int & l );
+ extern void mem_write ( short I, pstr S, int & l );
+ extern void mem_write ( long I, pstr S, int & l );
+ extern void mem_write ( word W, pstr S, int & l );
+ extern void mem_write ( realtype R, pstr S, int & l );
+ extern void mem_write ( shortreal R, pstr S, int & l );
+ extern void mem_write ( pstr L, int len, pstr S, int & l );
+ extern void mem_write ( pstr L, pstr S, int & l );
+ extern void mem_write ( bool B, pstr S, int & l );
+ extern void mem_write_byte ( byte B, pstr S, int & l );
+
+ extern void mem_read ( int & I, cpstr S, int & l );
+ extern void mem_read ( short & I, cpstr S, int & l );
+ extern void mem_read ( long & I, cpstr S, int & l );
+ extern void mem_read ( word & W, cpstr S, int & l );
+ extern void mem_read ( realtype & R, cpstr S, int & l );
+ extern void mem_read ( shortreal & R, cpstr S, int & l );
+ extern void mem_read ( pstr L, int len, cpstr S, int & l );
+ extern void mem_read ( pstr & L, cpstr S, int & l );
+ extern void mem_read ( bool & B, cpstr S, int & l );
+ extern void mem_read_byte ( byte & B, cpstr S, int & l );
+
+}
+
+#endif
+
+/* =================================================== */
+
diff --git a/mmdb2/mmdb_mmcif_.cpp b/mmdb2/mmdb_mmcif_.cpp
new file mode 100644
index 0000000..e5b962e
--- /dev/null
+++ b/mmdb2/mmdb_mmcif_.cpp
@@ -0,0 +1,3666 @@
+// $Id: mmdb_mmcif_.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_MMCIF <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::mmcif::Category ( mmCIF category )
+// ~~~~~~~~~ mmdb::mmcif::Struct ( mmCIF structure )
+// mmdb::mmcif::Loop ( mmCIF loop )
+// mmdb::mmcif::Data ( mmCIF data block )
+// mmdb::mmcif::File ( mmCIF file )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "mmdb_mmcif_.h"
+
+namespace mmdb {
+
+ namespace mmcif {
+
+ // ====================== SortTags ===============================
+
+ void SortTags ( psvector tag, int len, ivector index ) {
+ int i,k,l,l1,l2;
+ if (len==1) {
+ index[0] = 0;
+ return;
+ }
+ if (strcasecmp(tag[0],tag[1])<0) {
+ index[0] = 0;
+ index[1] = 1;
+ } else {
+ index[0] = 1;
+ index[1] = 0;
+ }
+ for (k=2;k<len;k++) {
+ l2 = k-1;
+ if (strcasecmp(tag[k],tag[index[0]])<0) l2 = 0;
+ else if (strcasecmp(tag[k],tag[index[l2]])>0) l2 = k;
+ else {
+ l1 = 0;
+ while (l1<l2-1) {
+ l = (l1+l2)/2;
+ if (strcasecmp(tag[k],tag[index[l]])<0) l2 = l;
+ else l1 = l;
+ }
+ }
+ for (i=k;i>l2;i--)
+ index[i] = index[i-1];
+ index[l2] = k;
+ }
+ }
+
+
+ // ====================== Category ==========================
+
+ const int CIF_NODATA_DOT = 0;
+ const int CIF_NODATA_QUESTION = 1;
+ cpstr CIF_NODATA_DOT_FIELD = pstr("\x02" ".");
+ cpstr CIF_NODATA_QUESTION_FIELD = pstr("\x02" "?");
+
+ Category::Category() : io::Stream() {
+ InitCategory();
+ }
+
+ Category::Category ( cpstr N ) : io::Stream() {
+ InitCategory();
+ SetCategoryName ( N );
+ }
+
+ Category::Category ( io::RPStream Object ) : io::Stream(Object) {
+ InitCategory();
+ }
+
+ Category::~Category() {
+ FreeMemory();
+ }
+
+ void Category::InitCategory() {
+ name = NULL;
+ nTags = 0;
+ tag = NULL;
+ index = NULL;
+ nAllocTags = 0;
+ }
+
+ void Category::FreeMemory() {
+ int i;
+ if (name) delete[] name;
+ name = NULL;
+ for (i=0;i<nAllocTags;i++)
+ if (tag[i]) delete[] tag[i];
+ FreeVectorMemory ( tag ,0 );
+ FreeVectorMemory ( index,0 );
+ nTags = 0;
+ nAllocTags = 0;
+ }
+
+ void Category::SetCategoryName ( cpstr N ) {
+ if (N[0]) CreateCopy ( name,N );
+ else {
+ CreateCopy ( name,pstr(" ") );
+ name[0] = char(1); // no category name
+ }
+ }
+
+ void Category::ExpandTags ( int nTagsNew ) {
+ int i,nAT;
+ psvector tag1;
+ ivector index1;
+ if (nTagsNew>nAllocTags) {
+ nAT = nTagsNew + IMin(nAllocTags/2+1,20);
+ GetVectorMemory ( tag1 ,nAT,0 );
+ GetVectorMemory ( index1,nAT,0 );
+ for (i=0;i<nAllocTags;i++) {
+ tag1 [i] = tag [i];
+ index1[i] = index[i];
+ }
+ for (i=nAllocTags;i<nAT;i++) {
+ tag1 [i] = NULL;
+ index1[i] = i;
+ }
+ FreeVectorMemory ( tag ,0 );
+ FreeVectorMemory ( index,0 );
+ tag = tag1;
+ index = index1;
+ nAllocTags = nAT;
+ }
+ }
+
+ pstr Category::GetTag ( int tagNo ) {
+ if ((tagNo>=0) && (tagNo<nTags)) return tag[tagNo];
+ return NULL;
+ }
+
+ void Category::Sort() {
+ // Sorts tags for easing the search
+ int i,k;
+ if (nAllocTags>0) {
+ k = 0;
+ if (!index)
+ GetVectorMemory ( index,nAllocTags,0 );
+ for (i=0;i<nTags;i++)
+ if (tag[i]) {
+ if (k<i) {
+ tag[k] = tag[i];
+ tag[i] = NULL;
+ }
+ k++;
+ }
+ nTags = k;
+ SortTags ( tag,nTags,index );
+ }
+ }
+
+ void Category::Optimize() {
+ int i,k;
+ psvector tag1;
+ k = 0;
+ for (i=0;i<nTags;i++)
+ if (tag[i]) k++;
+ if (k<=0) FreeMemory();
+ else if (k!=nAllocTags) {
+ GetVectorMemory ( tag1,k,0 );
+ FreeVectorMemory ( index,0 );
+ k = 0;
+ for (i=0;i<nTags;i++)
+ if (tag[i])
+ tag1[k++] = tag[i];
+ FreeVectorMemory ( tag,0 );
+ tag = tag1;
+ nTags = k;
+ nAllocTags = nTags;
+ Sort();
+ }
+ }
+
+ int Category::GetTagNo ( cpstr ttag ) {
+ // Binary search for index of tag ttag in tag[].
+ // Return:
+ // >=0 : position of the tag found
+ // <0 : the tag was not found, it could be inserted before
+ // (-RC-1)th element, where RC is the return value
+ int l1,l2,l,k;
+
+ if (!tag) return -1;
+
+ if (!index) Sort();
+
+ l = 0;
+ l1 = 0;
+ l2 = nTags-1;
+ k = 1;
+ while (l1<l2-1) {
+ l = (l1+l2)/2;
+ k = strcasecmp ( ttag,tag[index[l]] );
+ if (k<0) l2 = l;
+ else if (k>0) l1 = l;
+ else {
+ l1 = l;
+ break;
+ }
+ }
+
+ if (k==0) return index[l]; // is at RCth position
+ k = strcasecmp ( ttag,tag[index[l1]] );
+ if (k==0) return index[l1]; // is at RCth position
+ if (k<0) return -1; // would be at (-RC-1)th position
+ if (l2!=l1) {
+ k = strcasecmp ( ttag,tag[index[l2]] );
+ if (k==0) return index[l2]; // is at RCth position
+ if (k>0) return -2-l2; // would be at l2+1=(-RC-1)th position
+ }
+
+ return -2-l1; // would be at l1+1=(-RC-1)th position
+
+ }
+
+ int Category::AddTag ( cpstr ttag ) {
+ // return -1: the tag has been added on the top of array;
+ // index is added and sorted automatically
+ // >=0: the tag is already in the array -- its position
+ // is returned
+ int i1,i;
+ if (!tag) {
+ ExpandTags ( 3 ); // get space for first 3 tags
+ CreateCopy ( tag[0],ttag );
+ nTags = 1;
+ return -nTags; // the tag has been added on the top of array
+ }
+ i1 = GetTagNo ( ttag );
+ if (i1>=0) return i1; // non-negative returns mean that
+ // the tag is already in the array
+ i1 = -i1-1; // otherwise the tag has to be added and indexed at here
+ // put new tag on the top of array and update index
+ ExpandTags ( nTags+1 );
+ CreateCopy ( tag[nTags],ttag );
+ for (i=nTags;i>i1;i--)
+ index[i] = index[i-1];
+ index[i1] = nTags;
+ nTags++;
+ return -nTags; // the tag has been added on the top of array
+ }
+
+ void Category::PrintTags() {
+ int i;
+ Sort();
+ printf ( " Unsorted tags:\n" );
+ for (i=0;i<nTags;i++)
+ if (tag[i])
+ printf ( " %s.%s\n",name,tag[i] );
+ if (index) {
+ printf ( " Sorted tags:\n" );
+ for (i=0;i<nTags;i++)
+ if (tag[index[i]])
+ printf ( " %s.%s\n",name,tag[index[i]] );
+ }
+ }
+
+ bool Category::CheckTags ( cpstr * tagList ) {
+ int i;
+ i = 0;
+ while (tagList[i][0]) {
+ if (GetTagNo(tagList[i])<0) return false;
+ i++;
+ }
+ return true;
+ }
+
+ void Category::PutCategoryName ( cpstr newName ) {
+ CreateCopy ( name,newName );
+ }
+
+ void Category::Copy ( PCategory Category ) {
+ int i;
+ FreeMemory();
+ if (Category) {
+ CreateCopy ( name,Category->name );
+ nTags = Category->nTags;
+ nAllocTags = nTags;
+ if (nTags>0) {
+ GetVectorMemory ( tag ,nAllocTags,0 );
+ GetVectorMemory ( index,nAllocTags,0 );
+ for (i=0;i<nTags;i++) {
+ tag[i] = NULL;
+ CreateCopy ( tag[i],Category->tag[i] );
+ index[i] = Category->index[i];
+ }
+ }
+ }
+ }
+
+
+ void Category::write ( io::RFile f ) {
+ int i;
+ if (!index) Sort();
+ f.CreateWrite ( name );
+ f.WriteInt ( &nTags );
+ for (i=0;i<nTags;i++)
+ f.CreateWrite ( tag[i] );
+ f.WriteVector ( index,nTags,0 );
+ }
+
+ void Category::read ( io::RFile f ) {
+ int i;
+ FreeMemory ();
+ f.CreateRead ( name );
+ f.ReadInt ( &nTags );
+ nAllocTags = nTags;
+ if (nTags>0) {
+ GetVectorMemory ( tag,nTags,0 );
+ for (i=0;i<nTags;i++) {
+ tag[i] = NULL;
+ f.CreateRead ( tag[i] );
+ }
+ }
+ f.CreateReadVector ( index,0 );
+ }
+
+ MakeStreamFunctions(Category)
+
+
+
+ // ====================== Struct ===========================
+
+
+ Struct::Struct() : Category() {
+ InitStruct();
+ }
+
+ Struct::Struct ( cpstr N ) : Category(N) {
+ InitStruct();
+ }
+
+ Struct::Struct ( io::RPStream Object ) : Category(Object) {
+ InitStruct();
+ }
+
+ Struct::~Struct() {
+ FreeMemory();
+ }
+
+ void Struct::FreeMemory() {
+ int i;
+ for (i=0;i<nAllocTags;i++)
+ if (field[i]) delete[] field[i];
+ FreeVectorMemory ( field,0 );
+ Category::FreeMemory();
+ }
+
+ void Struct::InitStruct() {
+ field = NULL;
+ }
+
+ void Struct::Optimize() {
+ int i,k;
+ psvector f1;
+ k = 0;
+ for (i=0;i<nTags;i++)
+ if (!tag[i]) {
+ if (field[i]) delete[] field[i];
+ field[i] = NULL;
+ } else if (!field[i]) {
+ delete[] tag[i];
+ tag[i] = NULL;
+ } else
+ k++;
+ if (k<=0) FreeMemory();
+ else if (k!=nAllocTags) {
+ f1 = new pstr[k];
+ k = 0;
+ for (i=0;i<nTags;i++)
+ if (tag[i])
+ f1[k++] = field[i];
+ FreeVectorMemory ( field,0 );
+ field = f1;
+ Category::Optimize();
+ }
+ }
+
+ void Struct::AddField ( cpstr F, cpstr T, bool Concatenate ) {
+ psvector field1;
+ int i,nAT;
+ pstr nf;
+
+ nAT = nAllocTags;
+ i = AddTag ( T );
+
+ if (i<0) {
+ // The tag was not in the list, but has been added on the top
+ // of list. Now expand the field list and put new field on
+ // the top of it.
+ if (nAllocTags>nAT) {
+ GetVectorMemory ( field1,nAllocTags,0 );
+ for (i=0;i<nTags-1;i++)
+ field1[i] = field[i];
+ for (i=nTags-1;i<nAllocTags;i++)
+ field1[i] = NULL;
+ FreeVectorMemory ( field,0 );
+ field = field1;
+ }
+ i = nTags-1;
+ field[i] = NULL;
+ }
+
+ if (!F) {
+ if ((!Concatenate) || (!field[i])) {
+ CreateCopy ( field[i],pstr(" ?") );
+ field[i][0] = char(2);
+ }
+ } else if ((!Concatenate) || (!field[i]))
+ CreateCopy ( field[i],F );
+ else {
+ nf = new char[strlen(field[i])+strlen(F)+1];
+ strcpy ( nf,field[i] );
+ strcat ( nf,F );
+ delete[] field[i];
+ field[i] = nf;
+ }
+
+ }
+
+ pstr Struct::GetField ( int tagNo ) {
+ if ((tagNo>=0) && (tagNo<nTags)) return field[tagNo];
+ return NULL;
+ }
+
+ int Struct::GetString ( pstr & S, cpstr TName,
+ bool Remove ) {
+ int k = GetTagNo ( TName );
+ if (S) delete[] S;
+ S = NULL;
+ if (!field) return CIFRC_NoField;
+ if (k<0) return CIFRC_NoTag;
+ if (!field[k]) return CIFRC_NoField;
+ if (field[k][0]==char(2)) {
+ if (Remove) {
+ delete[] field[k];
+ field[k] = NULL;
+ }
+ } else if (Remove) {
+ S = field[k];
+ field[k] = NULL;
+ } else
+ CreateCopy ( S,field[k] );
+ return 0;
+ }
+
+ pstr Struct::GetString ( cpstr TName, int & RC ) {
+ int k = GetTagNo ( TName );
+ if (k<0) {
+ RC = CIFRC_NoTag;
+ return NULL;
+ }
+ if (!field) {
+ RC = CIFRC_NoField;
+ return NULL;
+ }
+ if (!field[k]) {
+ RC = CIFRC_NoField;
+ return NULL;
+ }
+ RC = 0;
+ if (field[k][0]==char(2)) return NULL;
+ return field[k];
+ }
+
+ int Struct::DeleteField ( cpstr TName ) {
+ int k = GetTagNo ( TName );
+ if ((k>=0) && (field)) {
+ if (field[k]) delete[] field[k];
+ field[k] = NULL;
+ }
+ return k;
+ }
+
+ int Struct::GetReal ( realtype & R, cpstr TName,
+ bool Remove ) {
+ pstr endptr;
+ int RC;
+ int k = GetTagNo ( TName );
+ R = 0.0;
+ if (!field) return CIFRC_NoField;
+ if (k<0) return CIFRC_NoTag;
+ if (!field[k]) return CIFRC_NoField;
+ if (field[k][0]==char(2)) return CIFRC_NoData;
+ R = strtod ( field[k],&endptr );
+ if (endptr==field[k]) RC = CIFRC_WrongFormat;
+ else {
+ RC = 0;
+ if (Remove) {
+ delete[] field[k];
+ field[k] = NULL;
+ }
+ }
+ return RC;
+ }
+
+ int Struct::GetInteger ( int & I, cpstr TName,
+ bool Remove ) {
+ pstr endptr;
+ int RC;
+ int k = GetTagNo ( TName );
+ I = 0;
+ if (!field) return CIFRC_NoField;
+ if (k<0) return CIFRC_NoTag;
+ if (!field[k]) return CIFRC_NoField;
+ if (field[k][0]==char(2)) {
+ if (field[k][1]=='.') I = MinInt4;
+ return CIFRC_NoData;
+ }
+ I = mround ( strtod(field[k],&endptr) );
+ if (endptr==field[k]) RC = CIFRC_WrongFormat;
+ else {
+ RC = 0;
+ if (Remove) {
+ delete[] field[k];
+ field[k] = NULL;
+ }
+ }
+ return RC;
+ }
+
+
+ void Struct::PutString ( cpstr S, cpstr T,
+ bool NonBlankOnly ) {
+ pstr p;
+ if (!S) PutNoData ( CIF_NODATA_QUESTION,T );
+ else {
+ p = pstr(S);
+ if (NonBlankOnly)
+ while (*p==' ') p++;
+ if (!(*p)) PutNoData ( CIF_NODATA_DOT,T );
+ else AddField ( S,T,false );
+ }
+ }
+
+ void Struct::PutDate ( cpstr T ) {
+ time_t t;
+ tm * tstruct;
+ char S[100];
+ t = time ( NULL );
+ tstruct = localtime(&t);
+ if (tstruct)
+ sprintf ( S,"%4i-%02i-%02i",
+ tstruct->tm_year+1900,tstruct->tm_mon+1,tstruct->tm_mday );
+ else strcpy ( S,"YYYY-MM-DD" );
+ AddField ( S,T,false );
+ }
+
+
+ void Struct::PutNoData ( int NoDataType, cpstr T ) {
+ char S[10];
+ S[0] = char(2);
+ if (NoDataType==CIF_NODATA_DOT) S[1] = '.';
+ else S[1] = '?';
+ S[2] = char(0);
+ AddField ( S,T,false );
+ }
+
+
+ void Struct::PutReal ( realtype R, cpstr T, int prec ) {
+ char rS[100];
+ sprintf ( rS,"%.*g",prec,R );
+ AddField ( rS,T,false );
+ }
+
+ void Struct::PutReal ( realtype R, cpstr T, cpstr format ) {
+ char rS[100];
+ sprintf ( rS,format,R );
+ AddField ( DelSpaces(rS,' '),T,false );
+ }
+
+ void Struct::PutInteger ( int I, cpstr T ) {
+ char iS[100];
+ if (I>MinInt4) {
+ sprintf ( iS,"%i",I );
+ AddField ( iS,T,false );
+ } else
+ PutNoData ( CIF_NODATA_DOT,T );
+ }
+
+
+
+ #define NODATA_Q pstr("?")
+ #define NODATA_P pstr(".")
+
+ bool Struct::WriteMMCIFStruct ( cpstr FName,
+ io::GZ_MODE gzipMode ) {
+ io::File f;
+ f.assign ( FName,true,false,gzipMode );
+ if (f.rewrite()) {
+ WriteMMCIF ( f );
+ f.shut();
+ return true;
+ } else
+ return false;
+ }
+
+ #define _max_output_line_width 256
+
+ void Struct::WriteMMCIF ( io::RFile f ) {
+ int i,j,k,l,m,n;
+ pstr F;
+
+ // calculate maximal length of tags
+ l = 0;
+ for (i=0;i<nTags;i++)
+ l = IMax(l,strlen(tag[i]));
+ l += 1; // add one space separator
+
+ // calculate maximal space left for data
+ m = _max_output_line_width - l;
+ // subtract category name width
+ if (name[0]!=char(1)) m -= strlen(name);
+
+ // start outout
+ f.LF();
+ for (i=0;i<nTags;i++) { // for each tag
+
+ // print category name, if not hidden, and dot
+ if (name[0]!=char(1)) {
+ f.Write ( name );
+ f.Write ( pstr(".") );
+ }
+
+ // print tag, checking for duplicate tag flag
+ F = strchr ( tag[i],'\1' );
+ if (F) {
+ *F = char(0);
+ f.Write ( tag[i] );
+ *F = '\1';
+ } else
+ f.Write ( tag[i] );
+
+ // print field
+ if (field[i]) { // field is defined
+ F = field[i];
+ if (strchr(F,'\n') || strstr(F,"\" ")) {
+ f.Write ( pstr("\n;") );
+ f.Write ( F );
+ f.Write ( pstr("\n;\n") );
+ } else {
+ n = strlen(F);
+ if (n>m) // wrap around if field is too long
+ f.Write ( pstr("\n ") );
+ else {
+ k = l-strlen(tag[i]);
+ for (j=0;j<k;j++)
+ f.Write ( pstr(" ") );
+ }
+ if ((((F[0]=='.') || (F[0]=='?')) && (!F[1])) ||
+ strchr(F,' ')) {
+ f.Write ( pstr("\"") );
+ f.Write ( field[i] );
+ f.Write ( pstr("\"\n") );
+ } else if (field[i][0]==char(2)) {
+ f.WriteLine ( &(field[i][1]) );
+ } else if (!field[i][0]) {
+ f.WriteLine ( NODATA_P );
+ } else
+ f.WriteLine ( field[i] );
+ }
+
+ } else { // field if not defined, put question mark
+
+ k = l-strlen(tag[i]);
+ for (j=0;j<k;j++)
+ f.Write ( pstr(" ") );
+ f.WriteLine ( NODATA_Q );
+
+ }
+
+ }
+
+ }
+
+ void Struct::Copy ( PCategory Struct ) {
+ int i;
+ Category::Copy ( Struct );
+ if (nTags>0) {
+ GetVectorMemory ( field,nTags,0 );
+ for (i=0;i<nTags;i++) {
+ field[i] = NULL;
+ CreateCopy ( field[i],PStruct(Struct)->field[i] );
+ }
+ }
+ }
+
+ void Struct::write ( io::RFile f ) {
+ int i;
+ Category::write ( f );
+ for (i=0;i<nTags;i++)
+ f.CreateWrite ( field[i] );
+ }
+
+ void Struct::read ( io::RFile f ) {
+ int i;
+ Category::read ( f );
+ if (nTags>0) {
+ GetVectorMemory ( field,nTags,0 );
+ for (i=0;i<nTags;i++) {
+ field[i] = NULL;
+ f.CreateRead ( field[i] );
+ }
+ }
+ }
+
+
+ MakeStreamFunctions(Struct)
+
+
+
+ // ====================== Loop ==============================
+
+
+ Loop::Loop() : Category() {
+ InitLoop();
+ }
+
+ Loop::Loop ( cpstr N ) : Category(N) {
+ InitLoop();
+ }
+
+ Loop::Loop ( io::RPStream Object ) : Category(Object) {
+ InitLoop();
+ }
+
+ Loop::~Loop() {
+ FreeMemory();
+ }
+
+ void Loop::InitLoop() {
+ nRows = 0;
+ field = NULL;
+ iColumn = 0;
+ nAllocRows = 0;
+ }
+
+ void Loop::FreeMemory() {
+ DeleteFields();
+ Category::FreeMemory();
+ }
+
+ void Loop::Optimize() {
+ int i,j,nT,nR,k,m;
+ bool empty;
+ psmatrix f1;
+
+ if (!field) {
+ Category::Optimize(); // optimize tags
+ return;
+ }
+
+ // first check for empty columns
+ nT = 0;
+ for (i=0;i<nTags;i++)
+ if (!tag[i]) {
+ for (j=0;j<nRows;j++) // delete ith column of field
+ if (field[j]) {
+ if (field[j][i])
+ delete[] field[j][i];
+ field[j][i] = NULL;
+ }
+ } else {
+ empty = true;
+ j = 0;
+ while ((j<nRows) && empty) { // check if ith column is empty
+ if (field[j])
+ empty = !field[j][i];
+ j++;
+ }
+ if (empty) { // if ith column is empty, delete its tag
+ delete[] tag[i];
+ tag[i] = NULL;
+ } else // otherwise count ith tag
+ nT++;
+ }
+
+ // now check for empty rows
+ nR = 0;
+ for (j=0;j<nRows;j++)
+ if (field[j]) {
+ i = 0;
+ while ((i<nTags) && (!field[j][i])) i++;
+ if (i>=nTags) {
+ delete[] field[j]; // delete empty row
+ field[j] = NULL;
+ } else
+ nR++; // count non-empty row
+ }
+ if ((nT<=0) || (nR<=0))
+ FreeMemory(); // the loop is completely empty
+ else if ((nT!=nTags) || (nR!=nAllocRows)) {
+ f1 = new psvector[nR];
+ m = 0;
+ for (j=0;j<nRows;j++)
+ if (field[j]) {
+ f1[m] = new pstr[nT];
+ k = 0;
+ for (i=0;i<nTags;i++)
+ if (tag[i])
+ f1[m][k++] = field[j][i];
+ m++;
+ delete[] field[j];
+ }
+ if (field) delete[] field;
+ field = f1;
+ nRows = nR;
+ nAllocRows = nRows;
+ Category::Optimize(); // optimize tags
+ }
+
+ }
+
+ void Loop::DeleteFields() {
+ int i,j;
+ if (field) {
+ for (i=0;i<nAllocRows;i++)
+ if (field[i]) {
+ for (j=0;j<nTags;j++)
+ if (field[i][j]) delete[] field[i][j];
+ delete[] field[i];
+ }
+ delete[] field;
+ field = NULL;
+ nRows = 0;
+ nAllocRows = 0;
+ }
+ }
+
+ void Loop::AddLoopTag ( cpstr T, bool Remove ) {
+ psmatrix f1;
+ int i,j,nT1;
+ if (Remove) {
+ DeleteFields();
+ AddTag ( T );
+ } else {
+ f1 = field;
+ field = NULL;
+ i = AddTag ( T );
+ if ((f1) && (i<0)) {
+ // The tag was added on the top of tag array. Create
+ // and fill new fields.
+ field = new psvector[nAllocRows];
+ nT1 = nTags-1;
+ for (i=0;i<nAllocRows;i++)
+ if (f1[i]) {
+ field[i] = new pstr[nTags];
+ for (j=0;j<nT1;j++)
+ field[i][j] = f1[i][j];
+ field[i][nT1] = NULL;
+ f1[i] = NULL;
+ } else
+ field[i] = NULL;
+ delete[] f1;
+ } else
+ // The tag was already in the category. Just restore fields.
+ field = f1;
+ }
+ }
+
+
+ void Loop::ExpandRows ( int nRowsNew ) {
+ int nAR,i;
+ psmatrix field1;
+ if (nRowsNew>nAllocRows) {
+ nAR = nRowsNew + IMin(nAllocRows/2+10,2000);
+ field1 = new psvector[nAR];
+ for (i=0;i<nAllocRows;i++)
+ field1[i] = field[i];
+ for (i=nAllocRows;i<nAR;i++)
+ field1[i] = NULL;
+ if (field) delete[] field;
+ field = field1;
+ nAllocRows = nAR;
+ }
+ }
+
+ void Loop::AddString ( cpstr S, bool NonBlankOnly ) {
+ int i;
+ pstr p;
+ if (!S) AddNoData ( CIF_NODATA_QUESTION );
+ else {
+ p = pstr(S);
+ if (NonBlankOnly)
+ while (*p==' ') p++;
+ if (!(*p)) AddNoData ( CIF_NODATA_DOT );
+ else {
+ if (iColumn==0) { // start a new row
+ ExpandRows ( nRows+1 );
+ field[nRows] = new pstr[nTags];
+ for (i=0;i<nTags;i++)
+ field[nRows][i] = NULL;
+ nRows++;
+ }
+ CreateCopy ( field[nRows-1][iColumn],S );
+ iColumn++;
+ if (iColumn>=nTags) iColumn = 0;
+ }
+ }
+ }
+
+ void Loop::AddNoData ( int NoDataType ) {
+ char S[10];
+ S[0] = char(2);
+ if (NoDataType==CIF_NODATA_DOT) S[1] = '.';
+ else S[1] = '?';
+ S[2] = char(0);
+ AddString ( S );
+ }
+
+ void Loop::AddReal ( realtype R, int prec ) {
+ char rS[100];
+ sprintf ( rS,"%.*g",prec,R );
+ AddString ( rS );
+ }
+
+ void Loop::AddReal ( realtype R, cpstr format ) {
+ char rS[100];
+ sprintf ( rS,format,R );
+ AddString ( DelSpaces(rS,' ') );
+ }
+
+ void Loop::AddInteger ( int I ) {
+ char iS[100];
+ if (I>MinInt4) {
+ sprintf ( iS,"%i",I );
+ AddString ( iS );
+ } else
+ AddNoData ( CIF_NODATA_DOT );
+ }
+
+
+ pstr Loop::GetField ( int rowNo, int tagNo ) {
+ if ((tagNo>=0) && (tagNo<nTags) &&
+ (rowNo>=0) && (rowNo<nRows)) {
+ if (field[rowNo]) return field[rowNo][tagNo];
+ }
+ return NULL;
+ }
+
+ int Loop::GetString ( pstr & S, cpstr TName, int nrow,
+ bool Remove) {
+ int k = GetTagNo ( TName );
+ if (S) delete[] S;
+ S = NULL;
+ if (k<0) return CIFRC_NoTag;
+ if ((nrow<0) || (nrow>=nRows)) return CIFRC_WrongIndex;
+ if (!field[nrow]) return CIFRC_NoField;
+ if (!field[nrow][k]) return CIFRC_NoField;
+ if (field[nrow][k][0]==char(2)) {
+ if (Remove) {
+ delete[] field[nrow][k];
+ field[nrow][k] = NULL;
+ }
+ } else if (Remove) {
+ S = field[nrow][k];
+ field[nrow][k] = NULL;
+ } else
+ CreateCopy ( S,field[nrow][k] );
+ return 0;
+ }
+
+ pstr Loop::GetString ( cpstr TName, int nrow, int & RC ) {
+ int k = GetTagNo ( TName );
+ if (k<0) {
+ RC = CIFRC_NoTag;
+ return NULL;
+ }
+ if ((nrow<0) || (nrow>=nRows)) {
+ RC = CIFRC_WrongIndex;
+ return NULL;
+ }
+ if (!field[nrow]) {
+ RC = CIFRC_NoField;
+ return NULL;
+ }
+ if (!field[nrow][k]) {
+ RC = CIFRC_NoField;
+ return NULL;
+ }
+ RC = 0;
+ // char(2) means the field was either '.' or '?'
+ if (field[nrow][k][0]==char(2)) return NULL;
+ return field[nrow][k];
+ }
+
+ // CopyString() does nothing if RC is not 0
+ void Loop::CopyString ( pstr buf, int maxlength,
+ cpstr TName, int nrow, int & RC ) {
+ pstr p;
+ int k;
+
+ if (RC) return;
+
+ k = GetTagNo ( TName );
+ if (k<0) {
+ RC = CIFRC_NoTag;
+ buf[0] = char(0);
+ return;
+ }
+ if ((nrow<0) || (nrow>=nRows)) {
+ RC = CIFRC_WrongIndex;
+ buf[0] = char(0);
+ return;
+ }
+ if (!field[nrow]) {
+ RC = CIFRC_NoField;
+ buf[0] = char(0);
+ return;
+ }
+ p = field[nrow][k];
+ if (!p) {
+ RC = CIFRC_NoField;
+ buf[0] = char(0);
+ return;
+ }
+
+ // char(2) means the field was either '.' or '?'
+ if (p[0]==char(2)) {
+ buf[0] = p[0];
+ buf[1] = char(0);
+ } else
+ strncpy ( buf,p,IMin(maxlength,strlen(p)+1) );
+
+ }
+
+
+
+ int Loop::DeleteField ( cpstr TName, int nrow ) {
+ int k = GetTagNo ( TName );
+ if (k<0) return CIFRC_NoTag;
+ if ((nrow<0) || (nrow>=nRows))
+ return CIFRC_WrongIndex;
+ if (field[nrow]) {
+ if (field[nrow][k]) delete[] field[nrow][k];
+ field[nrow][k] = NULL;
+ }
+ return k;
+ }
+
+ int Loop::DeleteRow ( int nrow ) {
+ int i;
+ if ((nrow<0) || (nrow>=nRows))
+ return CIFRC_WrongIndex;
+ if (field[nrow]) {
+ for (i=0;i<nTags;i++)
+ if (field[nrow][i]) {
+ delete[] field[nrow][i];
+ field[nrow][i] = NULL;
+ }
+ delete[] field[nrow];
+ field[nrow] = NULL;
+ }
+ return 0;
+ }
+
+ int Loop::GetReal ( realtype & R, cpstr TName, int nrow,
+ bool Remove ) {
+ pstr endptr;
+ int k = GetTagNo ( TName );
+ if (k<0) return CIFRC_NoTag;
+ if ((nrow<0) || (nrow>=nRows))
+ return CIFRC_WrongIndex;
+ R = 0.0;
+ if (!field[nrow]) return CIFRC_NoField;
+ if (!field[nrow][k]) return CIFRC_NoField;
+ if (field[nrow][k][0]==char(2)) return CIFRC_NoField;
+ R = strtod ( field[nrow][k],&endptr );
+ if (endptr==field[nrow][k]) return CIFRC_WrongFormat;
+ if (Remove) {
+ delete[] field[nrow][k];
+ field[nrow][k] = NULL;
+ }
+ return 0;
+ }
+
+ void Loop::CopyReal ( realtype & R, cpstr TName, int nrow,
+ int & RC ) {
+ pstr endptr;
+ int k;
+
+ if (RC) return;
+
+ // R = 0.0;
+ k = GetTagNo ( TName );
+
+ if (k<0) RC = CIFRC_NoTag;
+ else if ((nrow<0) || (nrow>=nRows)) RC = CIFRC_WrongIndex;
+ else if (!field[nrow]) RC = CIFRC_NoField;
+ else if (!field[nrow][k]) RC = CIFRC_NoField;
+ else if (field[nrow][k][0]==char(2)) RC = CIFRC_NoField;
+ else {
+ R = strtod ( field[nrow][k],&endptr );
+ if (endptr==field[nrow][k]) RC = CIFRC_WrongFormat;
+ }
+
+ }
+
+ void Loop::CopyInteger ( int & I, cpstr TName, int nrow,
+ int & RC ) {
+ pstr endptr;
+ int k;
+
+ if (RC) return;
+
+ I = 0;
+ k = GetTagNo ( TName );
+
+ if (k<0) RC = CIFRC_NoTag;
+ else if ((nrow<0) || (nrow>=nRows)) RC = CIFRC_WrongIndex;
+ else if (!field[nrow]) RC = CIFRC_NoField;
+ else if (!field[nrow][k]) RC = CIFRC_NoField;
+ else if (field[nrow][k][0]==char(2)) RC = CIFRC_NoField;
+ else {
+ I = mround ( strtod ( field[nrow][k],&endptr ) );
+ if (endptr==field[nrow][k]) RC = CIFRC_WrongFormat;
+ }
+
+ }
+
+ int Loop::GetInteger ( int & I, cpstr TName, int nrow,
+ bool Remove ) {
+ pstr endptr;
+ int k = GetTagNo ( TName );
+ if (k<0) return CIFRC_NoTag;
+ if ((nrow<0) || (nrow>=nRows))
+ return CIFRC_WrongIndex;
+ I = 0;
+ if (!field[nrow]) return CIFRC_NoField;
+ if (!field[nrow][k]) return CIFRC_NoField;
+ if (field[nrow][k][0]==char(2)) {
+ if (field[nrow][k][1]=='.') I = MinInt4;
+ return CIFRC_NoField;
+ }
+ I = mround ( strtod(field[nrow][k],&endptr) );
+ if (endptr==field[nrow][k]) return CIFRC_WrongFormat;
+ if (Remove) {
+ delete[] field[nrow][k];
+ field[nrow][k] = NULL;
+ }
+ return 0;
+ }
+
+
+ int Loop::GetSVector ( psvector & S, cpstr TName,
+ int i1, int i2, bool Remove ) {
+ int j,k,r1,r2;
+ r1 = IMin(i1,i2);
+ r2 = IMin(IMax(i1,i2),nRows-1);
+ if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex;
+ k = GetTagNo ( TName );
+ if (k<0) return CIFRC_NoTag;
+ if (!S)
+ GetVectorMemory ( S,r2-r1+1,r1 );
+ if (Remove) {
+ for (j=r1;j<=r2;j++)
+ if (field[j]) {
+ S[j] = field[j][k];
+ field[j][k] = NULL;
+ if (S[j]) {
+ if (S[j][0]==char(2)) {
+ delete[] S[j];
+ S[j] = NULL;
+ }
+ }
+ } else
+ S[j] = NULL;
+ } else {
+ for (j=r1;j<=r2;j++) {
+ S[j] = NULL;
+ if (field[j]) {
+ if (field[j][k]) {
+ if (field[j][k][0]!=char(2))
+ CreateCopy ( S[j],field[j][k] );
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+ int Loop::GetRVector ( rvector & R, cpstr TName,
+ int i1, int i2, bool Remove ) {
+ int j,k,r1,r2,RC;
+ pstr endptr;
+ r1 = IMin(i1,i2);
+ r2 = IMin(IMax(i1,i2),nRows-1);
+ if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex;
+ k = GetTagNo ( TName );
+ if (k<0) return CIFRC_NoTag;
+ if (!R)
+ GetVectorMemory ( R,r2-r1+1,r1 );
+ RC = 0;
+ for (j=r1;j<=r2;j++) {
+ R[j] = 0.0;
+ if (field[j]) {
+ if (field[j][k]) {
+ R[j] = strtod ( field[j][k],&endptr );
+ if (endptr==field[j][k]) RC = CIFRC_WrongFormat;
+ if (Remove) {
+ delete[] field[j][k];
+ field[j][k] = NULL;
+ }
+ }
+ }
+ }
+ return RC;
+ }
+
+ int Loop::GetIVector ( ivector & I, cpstr TName,
+ int i1, int i2, bool Remove ) {
+ int j,k,r1,r2,RC;
+ pstr endptr;
+ r1 = IMin(i1,i2);
+ r2 = IMin(IMax(i1,i2),nRows-1);
+ if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex;
+ k = GetTagNo ( TName );
+ if (k<0) return CIFRC_NoTag;
+ if (!I)
+ GetVectorMemory ( I,r2-r1+1,r1 );
+ RC = 0;
+ for (j=r1;j<=r2;j++) {
+ I[j] = 0;
+ if (field[j]) {
+ if (field[j][k]) {
+ I[j] = mround ( strtod(field[j][k],&endptr) );
+ if (endptr==field[j][k]) RC = CIFRC_WrongFormat;
+ if (Remove) {
+ delete[] field[j][k];
+ field[j][k] = NULL;
+ }
+ }
+ }
+ }
+ return RC;
+ }
+
+
+ void Loop::PutString ( cpstr S, cpstr T, int nrow ) {
+ psmatrix field1;
+ int nT,nR,iT,i,j;
+ nT = nTags;
+ nR = nRows;
+ iT = AddTag ( T );
+ if (iT<0) iT = nTags-1;
+ if (nTags>nT) {
+ // a new tag has been added; all field must be reallocated.
+ nRows = IMax(nR,nrow+1); // nrow is indexed like 0,1,...
+ nAllocRows = IMax(nR,nrow+IMin(nR/2+1,2000));
+ field1 = new psvector[nAllocRows];
+ for (i=0;i<nR;i++)
+ if (field[i]) {
+ field1[i] = new pstr[nTags];
+ for (j=0;j<nT;j++)
+ field1[i][j] = field[i][j];
+ for (j=nT;j<nTags;j++)
+ field1[i][j] = NULL;
+ delete[] field[i];
+ } else
+ field1[i] = NULL;
+ for (i=nR;i<nRows;i++)
+ field1[i] = NULL;
+ if (field) delete[] field;
+ field = field1;
+ } else if (nrow>=nR) {
+ // only new rows are to be added
+ ExpandRows ( nrow+1 );
+ nRows++;
+ }
+ if (!field[nrow]) {
+ field[nrow] = new pstr[nTags];
+ for (j=0;j<nTags;j++)
+ field[nrow][j] = NULL;
+ }
+ CreateCopy ( field[nrow][iT],S );
+ iColumn = iT+1;
+ if (iColumn>=nTags) iColumn = 0;
+ }
+
+
+ void Loop::PutNoData ( int NoDataType, cpstr T, int nrow ) {
+ char S[10];
+ S[0] = char(2);
+ if (NoDataType==CIF_NODATA_DOT) S[1] = '.';
+ else S[1] = '?';
+ S[2] = char(0);
+ PutString ( S,T,nrow );
+ }
+
+
+ void Loop::PutReal ( realtype R, cpstr T, int nrow, int prec ) {
+ char rS[100];
+ sprintf ( rS,"%.*g",prec,R );
+ PutString ( rS,T,nrow );
+ }
+
+ void Loop::PutReal ( realtype R, cpstr T, int nrow,
+ cpstr format ) {
+ char rS[100];
+ sprintf ( rS,format,R );
+ PutString ( DelSpaces(rS,' '),T,nrow );
+ }
+
+ void Loop::PutInteger ( int I, cpstr T, int nrow ) {
+ char iS[100];
+ if (I>MinInt4) {
+ sprintf ( iS,"%i",I );
+ PutString ( iS,T,nrow );
+ } else
+ PutNoData ( CIF_NODATA_DOT,T,nrow );
+ }
+
+ void Loop::PutSVector ( psvector S, cpstr T, int i1, int i2 ) {
+ int i,j,k;
+ PutString ( S[i2],T,i2 );
+ if (iColumn==0) k = nTags-1;
+ else k = iColumn-1;
+ for (i=i2-1;i>=i1;i--) {
+ if (!field[i]) {
+ field[i] = new pstr[nTags];
+ for (j=0;j<nTags;j++)
+ field[i][j] = NULL;
+ }
+ CreateCopy ( field[i][k],S[i] );
+ }
+ }
+
+ void Loop::PutRVector ( rvector R, cpstr T,
+ int i1, int i2, int prec ) {
+ int i,j,k;
+ char rS[100];
+ PutReal ( R[i2],T,i2,prec );
+ if (iColumn==0) k = nTags-1;
+ else k = iColumn-1;
+ for (i=i2-1;i>=i1;i--) {
+ if (!field[i]) {
+ field[i] = new pstr[nTags];
+ for (j=0;j<nTags;j++)
+ field[i][j] = NULL;
+ }
+ sprintf ( rS,"%.*g",prec,R[i] );
+ CreateCopy ( field[i][k],rS );
+ }
+ }
+
+ void Loop::PutIVector ( ivector I, cpstr T,
+ int i1, int i2 ) {
+ int l,j,k;
+ char iS[100];
+ PutInteger ( I[i2],T,i2 );
+ if (iColumn==0) k = nTags-1;
+ else k = iColumn-1;
+ for (l=i2-1;l>=i1;l--) {
+ if (!field[l]) {
+ field[l] = new pstr[nTags];
+ for (j=0;j<nTags;j++)
+ field[l][j] = NULL;
+ }
+ sprintf ( iS,"%i",I[l] );
+ CreateCopy ( field[l][k],iS );
+ }
+ }
+
+ bool Loop::WriteMMCIFLoop ( cpstr FName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ f.assign ( FName,true,false,gzipMode );
+ if (f.rewrite()) {
+ WriteMMCIF ( f );
+ f.shut();
+ return true;
+ } else
+ return false;
+ }
+
+ void Loop::WriteMMCIF ( io::RFile f ) {
+ int i,j,k,m,n;
+ ivector l;
+ pstr F;
+
+ // write loop keyword
+ f.Write ( pstr("\nloop_\n") );
+
+ GetVectorMemory ( l,nTags,0 );
+ k = 0;
+ for (i=0;i<nTags;i++) {
+ if (name[0]!=char(1)) {
+ f.Write ( name );
+ f.Write ( pstr(".") );
+ }
+ F = strchr ( tag[i],'\1' );
+ if (F) {
+ *F = char(0);
+ f.WriteLine ( tag[i] );
+ *F = '\1';
+ } else
+ f.WriteLine ( tag[i] );
+ l[i] = 0;
+ for (j=0;j<nRows;j++)
+ if (field[j]) {
+ if (field[j][i]) {
+ F = field[j][i];
+ if (strchr(F,'\n') || strstr(F,"\" "))
+ l[i] = 10001;
+ else if (F[0]==char(2)) l[i] = IMax(l[i],1);
+ else if (((F[0]=='.') || (F[0]=='?')) &&
+ (!F[1])) l[i] = IMax(l[i],3);
+ else {
+ if (strchr(F,' ')) m = 2;
+ else m = 0;
+ l[i] = IMax(l[i],strlen(F)+m);
+ }
+ }
+ }
+ l[i] = IMax(l[i],1);
+ k += l[i]+1;
+ if (k>_max_output_line_width) {
+ l[i] = -l[i];
+ k = 0;
+ }
+ }
+ for (i=0;i<nRows;i++) {
+ m = 0; // counts symbols in the string
+ k = 0; // rest of left-aligned fields to fill with spaces
+ for (j=0;j<nTags;j++) {
+ n = k;
+ k = l[j]; // length of the field
+ if (k<0) k = -k;
+ m += k+1;
+ if (m>_max_output_line_width) {
+ f.LF();
+ m = k+1;
+ } else
+ while (n>0) {
+ f.Write ( pstr(" ") );
+ n--;
+ }
+ if (field[i]) {
+ if (field[i][j]) {
+ F = field[i][j];
+ if (k>10000) {
+ if (F[0]==char(2)) {
+ f.Write ( pstr(" ") );
+ f.WriteLine ( &(F[1]) );
+ } else if (!F[0]) {
+ f.Write ( pstr(" ") );
+ f.WriteLine ( NODATA_P );
+ } else {
+ f.Write ( pstr(";") );
+ f.WriteLine ( F );
+ f.WriteLine ( pstr(";") );
+ }
+ m = 0;
+ k = 0;
+ } else if ((((F[0]=='.') || (F[0]=='?')) && (!F[1])) ||
+ strchr(F,' ')) {
+ f.Write ( pstr(" \"") );
+ f.Write ( F );
+ f.Write ( pstr("\"") );
+ k -= strlen(F)+2;
+ } else if (F[0]==char(2)) {
+ f.Write ( pstr(" ") );
+ f.Write ( &(F[1]) );
+ k--;
+ } else if (!F[0]) {
+ f.Write ( pstr(" ") );
+ f.Write ( NODATA_P );
+ k--;
+ } else {
+ f.Write ( pstr(" ") );
+ f.Write ( F );
+ k -= strlen(F);
+ }
+ } else {
+ f.Write ( pstr(" ") );
+ f.Write ( NODATA_Q );
+ k--;
+ }
+ } else {
+ f.Write ( pstr(" ") );
+ f.Write ( NODATA_Q );
+ k--;
+ }
+ }
+ if (m) f.LF();
+ }
+
+ }
+
+
+ void Loop::Copy ( PCategory Loop ) {
+ int i,j;
+ Category::Copy ( Loop );
+ nRows = PLoop(Loop)->nRows;
+ nAllocRows = nRows;
+ if ((nTags>0) && (nRows>0)) {
+ field = new psvector[nRows];
+ for (i=0;i<nRows;i++) {
+ if (PLoop(Loop)->field[i]) {
+ field[i] = new pstr[nTags];
+ for (j=0;j<nTags;j++) {
+ field[i][j] = NULL;
+ CreateCopy ( field[i][j],PLoop(Loop)->field[i][j] );
+ }
+ } else
+ field[i] = NULL;
+ }
+ }
+ iColumn = PLoop(Loop)->iColumn;
+ }
+
+
+ void Loop::write ( io::RFile f ) {
+ int i,j;
+ Category::write ( f );
+ f.WriteInt ( &nRows );
+ if ((nTags>0) && (nRows>0))
+ for (i=0;i<nRows;i++)
+ if (field[i]) {
+ j = 1;
+ f.WriteInt ( &j );
+ for (j=0;j<nTags;j++)
+ f.CreateWrite ( field[i][j] );
+ } else {
+ j = 0;
+ f.WriteInt ( &j );
+ }
+ f.WriteInt ( &iColumn );
+ }
+
+ void Loop::read ( io::RFile f ) {
+ int i,j;
+ Category::read ( f );
+ f.ReadInt ( &nRows );
+ nAllocRows = nRows;
+ if ((nTags>0) && (nRows>0)) {
+ field = new psvector[nRows];
+ for (i=0;i<nRows;i++) {
+ f.ReadInt ( &j );
+ if (j) {
+ field[i] = new pstr[nTags];
+ for (j=0;j<nTags;j++) {
+ field[i][j] = NULL;
+ f.CreateRead ( field[i][j] );
+ }
+ } else
+ field[i] = NULL;
+ }
+ }
+ f.ReadInt ( &iColumn );
+ }
+
+
+ MakeStreamFunctions(Loop)
+
+
+
+ // ====================== Data =============================
+
+
+ Data::Data() : io::Stream() {
+ InitData();
+ }
+
+ Data::Data ( cpstr N ) : io::Stream() {
+ InitData();
+ CreateCopy ( name,N );
+ }
+
+ Data::Data ( io::RPStream Object ) : io::Stream(Object) {
+ InitData();
+ }
+
+ Data::~Data() {
+ FreeMemory(0);
+ }
+
+ void Data::InitData() {
+ name = NULL;
+ nCategories = 0;
+ Category = NULL;
+ index = NULL;
+ flags = 0;
+ Warning = 0;
+ loopNo = 0;
+ tagNo = 0;
+ WrongCat = NULL;
+ WrongTag = NULL;
+ nWrongFields = 0;
+ }
+
+ void Data::FreeMemory ( int key ) {
+ int i;
+ if (name) delete[] name;
+ name = NULL;
+ if (Category) {
+ for (i=0;i<nCategories;i++)
+ if (Category[i]) delete Category[i];
+ delete[] Category;
+ Category = NULL;
+ }
+ nCategories = 0;
+ FreeVectorMemory ( index,0 );
+ if (key==0) FreeWrongFields();
+ }
+
+ void Data::FreeWrongFields() {
+ int i;
+ if (WrongCat) {
+ for (i=0;i<nWrongFields;i++)
+ if (WrongCat[i]) delete[] WrongCat[i];
+ delete[] WrongCat;
+ }
+ if (WrongTag) {
+ for (i=0;i<nWrongFields;i++)
+ if (WrongTag[i]) delete[] WrongTag[i];
+ delete[] WrongTag;
+ }
+ WrongCat = NULL;
+ WrongTag = NULL;
+ nWrongFields = 0;
+ }
+
+
+ void Data::SetPrintWarnings ( bool SPW ) {
+ if (SPW) SetFlag ( CIFFL_PrintWarnings );
+ else RemoveFlag ( CIFFL_PrintWarnings );
+ }
+
+ void Data::SetStopOnWarning ( bool SOW ) {
+ if (SOW) SetFlag ( CIFFL_StopOnWarnings );
+ else RemoveFlag ( CIFFL_StopOnWarnings );
+ }
+
+ void Data::SetFlag ( CIF_FLAG F ) {
+ flags |= F;
+ }
+
+ void Data::RemoveFlag ( CIF_FLAG F ) {
+ flags &= ~F;
+ }
+
+ void Data::SetWrongFields ( cpstr *cats, cpstr *tags ) {
+ int i,lc,lt;
+ FreeWrongFields();
+ if ((!cats) || (!tags)) return;
+ lc = 0;
+ while (cats[lc]) lc++;
+ lt = 0;
+ while (tags[lt]) lt++;
+ nWrongFields = IMax(lc,lt);
+ if (nWrongFields>0) {
+ WrongCat = new pstr[nWrongFields];
+ WrongTag = new pstr[nWrongFields];
+ for (i=0;i<nWrongFields;i++) {
+ WrongCat[i] = NULL;
+ WrongTag[i] = NULL;
+ if (cats[i]) {
+ if (cats[i][0]) CreateCopy ( WrongCat[i],cats[i] );
+ }
+ if (!WrongCat[i]) {
+ CreateCopy ( WrongCat[i],pstr(" ") );
+ WrongCat[i][0] = char(1);
+ }
+ if (tags[i]) CreateCopy ( WrongTag[i],tags[i] );
+ else CreateCopy ( WrongTag[i],pstr("") );
+ }
+ }
+ }
+
+ bool Data::CheckWrongField ( cpstr C, cpstr T ) {
+ int i;
+ for (i=0;i<nWrongFields;i++)
+ if ((!strcasecmp(C,WrongCat[i])) &&
+ (!strcasecmp(T,WrongTag[i]))) return true;
+ return false;
+ }
+
+ #define _max_buf_len 500
+
+ static char _err_string[_max_buf_len+1];
+ static int _err_line;
+
+
+ int Data::ReadMMCIFData ( cpstr FName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ char S[_max_buf_len+1];
+ int RC,lcount;
+ f.assign ( FName,true,false,gzipMode );
+ if (f.reset(true)) {
+ S[0] = char(0);
+ lcount = 0;
+ RC = ReadMMCIFData ( f,S,lcount );
+ f.shut();
+ return RC;
+ } else {
+ _err_string[0] = char(0);
+ _err_line = 0;
+ Warning = CIFRC_CantOpenFile;
+ return CIFRC_CantOpenFile;
+ }
+ }
+
+
+ // --------------- General I/O functions
+
+ int Data::ReadMMCIFData ( io::RFile f, pstr S, int & lcount ) {
+ pstr p;
+ int i,llen;
+ pstr L;
+
+ FreeMemory(1);
+ Warning = 0;
+ loopNo = 0;
+ tagNo = 0;
+
+ // 1. Look for 'data_' tag
+ do {
+ p = &(S[0]);
+ while ((*p==' ') || (*p==char(9))) p++;
+ if (strncmp(p,"data_",5)) {
+ f.ReadLine ( S,_max_buf_len );
+ lcount++;
+ p = NULL;
+ }
+ } while ((!p) && (!f.FileEnd()));
+
+ if (!p) {
+ strcpy ( _err_string,S );
+ _err_line = lcount;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ ERROR "
+ "<<line %i: no 'data_XXXX' tag found>>\n",lcount );
+ return CIFRC_NoDataLine;
+ }
+
+ llen = _max_buf_len;
+ L = new char[llen];
+ i = 0;
+ p += 5;
+ while ((*p) && (*p!=' ') && (*p!=char(9))) {
+ L[i++] = *p;
+ p++;
+ }
+ L[i] = char(0);
+ CreateCopy ( name,L );
+
+
+ // 2. Loop over tags until next 'data_' or end of file
+
+ while (p) {
+
+ // skip spaces
+ while ((*p==' ') || (*p==char(9))) p++;
+
+ if ((*p) && (*p!='#')) { // this is not a comment, continue
+ if (*p=='_')
+ GetDataItem ( f,S,L,p,lcount,llen );
+ else if (!strncmp(p,"loop_",5))
+ GetLoop ( f,S,L,p,lcount,llen );
+ else if (!strncmp(p,"data_",5)) {
+ p = NULL;
+ break;
+ } else {
+ // if got to here, the file is corrupted
+ strcpy ( _err_string,S );
+ _err_line = lcount;
+ Warning |= CIFW_UnrecognizedItems;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ WARNING "
+ "<<line %i: unrecognized string>>\n%s\n",
+ lcount,S );
+ while ((*p) && (*p!=' ') && (*p!=char(9)))
+ if (*p=='#') *p = char(0);
+ else p++;
+ }
+ } else
+ *p = char(0);
+
+ if (Warning && (flags & CIFFL_StopOnWarnings)) {
+ if (L) delete[] L;
+ return Warning;
+ }
+
+ if (!(*p)) {
+ if (!f.FileEnd()) {
+ f.ReadLine ( S,_max_buf_len );
+ lcount++;
+ p = &(S[0]);
+ } else
+ p = NULL;
+ }
+
+ }
+
+ if (L) delete[] L;
+
+ Optimize(); // get rid of over-allocated fields.
+
+ return Warning;
+
+ }
+
+
+ void Data::GetDataItem ( io::RFile f, pstr S, pstr & L,
+ pstr & p, int & lcount, int & llen ) {
+ PStruct cifStruct;
+ char T[100];
+ int RC,i;
+
+ i = 0;
+ while ((*p) && (*p!=' ') && (*p!=char(9)) && (*p!='.')) {
+ if (i<(int)sizeof(T)-1) T[i++] = *p;
+ p++;
+ }
+ T[i] = char(0);
+
+ if (*p!='.') { // category name missing
+ strcpy ( L,T ); // item name
+ T[0] = char(1); // special
+ T[1] = char(0); // category name
+ }
+
+ // look for category
+ i = AddCategory ( T );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifStruct = new Struct ( T );
+ Category[nCategories-1] = cifStruct;
+ } else {
+ cifStruct = PStruct(Category[i]);
+ if (cifStruct->GetCategoryID()!=MMCIF_Struct) {
+ strcpy ( _err_string,S );
+ _err_line = lcount;
+ Warning |= CIFW_NotAStructure;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ WARNING "
+ "<<line %i: %s was a loop -- replaced>>\n%s\n",
+ lcount,T,S );
+ delete Category[i];
+ cifStruct = new Struct ( T );
+ Category[i] = cifStruct;
+ }
+ }
+
+ if (*p=='.') { // get item name
+ i = 0;
+ p++; // skip period
+ while ((*p) && (*p!=' ') && (*p!=char(9))) {
+ T[i++] = *p;
+ p++;
+ }
+ T[i] = char(0);
+ } else
+ strcpy ( T,L );
+
+ if (nWrongFields>0) {
+ if (CheckWrongField(cifStruct->name,T)) {
+ GetField ( f,S,L,p,lcount,llen );
+ cifStruct->DeleteField ( T );
+ return;
+ }
+ }
+
+ RC = GetField ( f,S,L,p,lcount,llen );
+
+ if (RC) {
+ strcpy ( _err_string,S );
+ _err_line = lcount;
+ Warning |= CIFW_MissingField;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ WARNING "
+ "<<line %i: expected data field missing>>\n%s\n",
+ lcount,S );
+ }
+
+ while ((*p==' ') || (*p==char(9))) p++;
+ if (*p=='#') *p = char(0);
+
+ i = cifStruct->GetTagNo ( T );
+ if (i>=0) {
+ if (flags & CIFFL_SuggestTags) {
+ tagNo++;
+ ParamStr ( T,pstr("\1"),tagNo );
+ } else {
+ strcpy ( _err_string,S );
+ _err_line = lcount;
+ Warning |= CIFW_DuplicateTag;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ WARNING "
+ "<<line %i: duplicated tag>>\n%s\n",lcount,S );
+ }
+ }
+ cifStruct->AddField ( L,T );
+
+ }
+
+ void Data::GetLoop ( io::RFile f, pstr S, pstr & L,
+ pstr & p, int & lcount, int & llen ) {
+ PLoop cifLoop;
+ pstr p1;
+ char T[100];
+ bool Repeat,WrongField;
+ int RC,i,nC;
+
+ RC = 0;
+
+ p += 5; // skip 'loop_' tag
+
+ loopNo++;
+ cifLoop = NULL;
+ nC = -1; // undefined category number
+ do {
+
+ while ((*p==' ') || (*p==char(9))) p++;
+ p1 = p;
+
+ if (*p=='_') {
+
+ // get category name
+ i = 0;
+ while ((*p) && (*p!=' ') && (*p!=char(9)) && (*p!='.')) {
+ if (i<(int)sizeof(T)-1) T[i++] = *p;
+ p++;
+ }
+ T[i] = char(0);
+
+ if (*p!='.') { // category name missing
+ strcpy ( L,T ); // item name
+ if (flags & CIFFL_SuggestCategories)
+ sprintf ( T,"X%i",loopNo );
+ else strcpy ( T,"X" );
+ T[0] = char(1); // special category name
+ }
+
+ if (cifLoop) {
+ if (strcmp(cifLoop->GetCategoryName(),T)) {
+ // loop ended, empty
+ p = p1; // play back to last category
+ cifLoop = NULL;
+ }
+ } else {
+ // look for category
+ i = AddCategory ( T );
+ if ((i!=nC) && (nC>=0)) { // empty loop; most probably
+ // a corrupted file
+ p = p1; // play back to last category
+ strcpy ( _err_string,S );
+ _err_line = lcount;
+ Warning |= CIFW_EmptyLoop;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ WARNING "
+ "<<line %i: empty loop>>\n%s\n",lcount,S );
+ // AddCategory(..) has added a NULL-Category on the top of
+ // category list; remove it now
+ DeleteCategory ( nCategories-1 );
+ cifLoop = NULL;
+ // return;
+ }
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifLoop = new Loop ( T );
+ Category[nCategories-1] = cifLoop;
+ nC = nCategories-1;
+ }
+ }
+ /*
+ else if (Loop) {
+ if (!strcmp(Loop->GetCategoryName(),
+ Category[i]->GetCategoryName())) {
+ if (Loop->GetCategoryID()!=MMCIF_Loop) {
+ Warning |= CIFW_NotALoop;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ WARNING "
+ "<<line %i: %s was a structure --"
+ " replaced>>\n%s\n",lcount,T,S );
+ delete Category[i];
+ Loop = new Loop ( T );
+ Category[i] = Loop;
+ }
+ } else
+ Loop = NULL;
+ }
+ */
+ if (cifLoop) {
+
+ if (*p=='.') { // get item name
+ i = 0;
+ p++; // skip period
+ while ((*p) && (*p!=' ') && (*p!=char(9))) {
+ T[i++] = *p;
+ p++;
+ }
+ T[i] = char(0);
+ } else
+ strcpy ( T,L );
+
+ if (nWrongFields>0)
+ WrongField = CheckWrongField ( cifLoop->name,T );
+ else WrongField = false;
+
+ if (!WrongField) {
+ if (cifLoop->AddTag(T)>=0) {
+ if (flags & CIFFL_SuggestTags) {
+ tagNo++;
+ ParamStr ( T,pstr("\1"),tagNo );
+ cifLoop->AddTag(T);
+ } else {
+ strcpy ( _err_string,S );
+ _err_line = lcount;
+ Warning |= CIFW_DuplicateTag;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ WARNING "
+ "<<line %i: duplicate tag>>\n%s\n",lcount,S );
+ }
+ }
+ }
+ Repeat = true;
+
+ } else {
+
+ p = p1;
+ Repeat = false;
+
+ }
+
+ } else if (!(*p) || (*p=='#')) {
+ Repeat = !f.FileEnd();
+ if (Repeat) {
+ f.ReadLine ( S,_max_buf_len );
+ lcount++;
+ p = &(S[0]);
+ } else {
+ strcpy ( _err_string,S );
+ _err_line = lcount;
+ Warning |= CIFW_UnexpectedEOF;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ WARNING "
+ "<<line %i: unexpected end of file>>\n%s\n",
+ lcount,S );
+ }
+ } else
+ Repeat = false;
+
+ } while (Repeat);
+
+ if (cifLoop) {
+ do {
+ while ((*p==' ') || (*p==char(9))) p++;
+ if (!(*p) || (*p=='#')) {
+ Repeat = !f.FileEnd();
+ if (Repeat) {
+ f.ReadLine ( S,_max_buf_len );
+ lcount++;
+ p = &(S[0]);
+ }
+ } else if (*p=='_') Repeat = false;
+ else if (!strncmp(p,"loop_",5)) Repeat = false;
+ else if (!strncmp(p,"data_",5)) Repeat = false;
+ else if (!strncmp(p,"stop_",5)) {
+ p += 5;
+ Repeat = false;
+ } else {
+ RC = GetField ( f,S,L,p,lcount,llen );
+ if (!RC) {
+ cifLoop->AddString ( L );
+ Repeat = true;
+ } else
+ Repeat = false;
+ }
+ } while (Repeat);
+ if ((cifLoop->iColumn!=0) || (RC)) {
+ strcpy ( _err_string,S );
+ _err_line = lcount;
+ Warning |= CIFW_LoopFieldMissing;
+ if (flags & CIFFL_PrintWarnings)
+ printf ( "\n **** mmCIF READ WARNING "
+ "<<line %i: expected loop field missing>>\n%s\n",
+ lcount,S );
+ }
+ }
+
+ }
+
+ int Data::GetField ( io::RFile f, pstr S, pstr & L,
+ pstr & p, int & lcount, int & llen ) {
+ bool Repeat;
+ pstr L1;
+ int i,flen;
+ char c;
+
+ flen = 0;
+ L[flen] = char(0);
+
+ do {
+
+ // skip all spaces before the field
+ while ((*p==' ') || (*p==char(9))) p++;
+
+ if ((*p=='#') || (!(*p))) {
+ // comment or end of line met; the field should be
+ // found on the next line
+ Repeat = !f.FileEnd();
+ if (Repeat) {
+ // take the next line
+ f.ReadLine ( S,_max_buf_len );
+ lcount++;
+ p = &(S[0]);
+ Repeat = (*p!=';');
+ } else {
+ // end of file and the field is not taken
+ L[0] = char(0);
+ return 1;
+ }
+ } else
+ // first symbol of a field is found
+ Repeat = false;
+
+ } while (Repeat);
+
+
+ if (*p==';') { // this is a multiline field
+ p++;
+ strcpy ( L,p ); // take first line of the field
+ flen = strlen(L);
+ while (!f.FileEnd()) {
+ f.ReadLine ( S,_max_buf_len );
+ lcount++;
+ p = &(S[0]);
+ if (*p==';') { // multiline field terminated
+ p++;
+ while ((*p==' ') || (*p==char(9))) p++;
+ return 0;
+ } else { // multiline field continues -- take next line
+ flen += strlen(S)+2;
+ if (flen>=llen) {
+ llen = flen + IMin(2000,llen);
+ L1 = new char[llen];
+ strcpy ( L1,L );
+ delete[] L;
+ L = L1;
+ }
+ strcat ( L,"\n" );
+ strcat ( L,S );
+ }
+ }
+
+ // end of file -- take the last line of the multiline field
+ p = &(S[strlen(S)]);
+
+ } else {
+
+ i = 0;
+ if (*p!='_') {
+ if ((*p=='\'') || (*p=='"')) {
+ c = *p;
+ // field in quotation marks
+ do {
+ p++;
+ // stop taking characters either on end of line
+ // or the quotation mark
+ while ((*p) && (*p!=c)) {
+ L[i++] = *p;
+ p++;
+ }
+ while (*p==c) {
+ // it was a quotation mark -- check that it is followed
+ // by end of line or space
+ p++;
+ if ((*p) && (*p!=' ') && (*p!=char(9))) {
+ // the quotation mark is not a field terminator and
+ // belongs to the field.
+ L[i++] = c; // take the quotation mark
+ if (*p!=c) // take the non-space character
+ L[i++] = *p; // but check for field terminator
+ }
+ }
+ // terminate the loop only on space or end of line
+ } while ((*p) && (*p!=' ') && (*p!=char(9)));
+ if (*p) p++;
+ L[i] = char(0);
+ } else {
+ // a simplest field without spaces
+ while ((*p) && (*p!=' ') && (*p!=char(9))) {
+ L[i++] = *p;
+ p++;
+ }
+ L[i] = char(0);
+ if (((L[0]=='.') || (L[0]=='?')) && (!L[1])) {
+ // "no data" tokens
+ L[1] = L[0];
+ L[0] = char(2);
+ L[2] = char(0);
+ }
+ }
+ }
+
+ }
+
+ return 0;
+
+ }
+
+ void Data::Sort() {
+ int i,k;
+ psvector cnames;
+
+ k = 0;
+ for (i=0;i<nCategories;i++)
+ if (Category[i]) {
+ if (k<i) Category[k] = Category[i];
+ k++;
+ }
+ for (i=k;i<nCategories;i++)
+ Category[i] = NULL;
+ nCategories = k;
+
+ FreeVectorMemory ( index ,0 );
+ GetVectorMemory ( cnames,nCategories,0 );
+ GetVectorMemory ( index ,nCategories,0 );
+
+ for (i=0;i<nCategories;i++) {
+ Category[i]->Sort();
+ cnames[i] = NULL;
+ CreateCopy ( cnames[i],Category[i]->name );
+ }
+
+ SortTags ( cnames,nCategories,index );
+
+ for (i=0;i<nCategories;i++)
+ if (cnames[i]) delete[] cnames[i];
+
+ if (cnames) delete[] cnames;
+
+ }
+
+ int Data::GetCategoryNo ( cpstr cname ) {
+ // Binary search for index of category cname in Category[].
+ // Return:
+ // >=0 : position of the category found
+ // <0 : the category was not found, it could be inserted before
+ // (-RC-1)th element, where RC is the return value
+ int l1,l2,l,k;
+
+ if ((!Category) || (nCategories<1)) return -1;
+
+ if (!index) Sort();
+
+ if (cname[0]) {
+ l = 0;
+ l1 = 0;
+ l2 = nCategories-1;
+ k = 1;
+ while (l1<l2-1) {
+ l = (l1+l2)/2;
+ k = strcasecmp ( cname,Category[index[l]]->name );
+ if (k<0) l2 = l;
+ else if (k>0) l1 = l;
+ else {
+ l1 = l;
+ break;
+ }
+ }
+ if (k==0) return index[l]; // is at RCth position
+ k = strcasecmp(cname,Category[index[l1]]->name);
+ if (k==0) return index[l1]; // is at RCth position
+ if (k<0) return -1; // would be at (-RC-1)th position
+ if (l2!=l1) {
+ k = strcasecmp(cname,Category[index[l2]]->name);
+ if (k==0) return index[l2]; // is at RCth position
+ if (k>0) return -2-l2; // would be at l2+1=(-RC-1)th position
+ }
+ return -2-l1; // would be at l1+1=(-RC-1)th position
+ } else
+ // 'root' category should be always on top
+ if (Category[index[0]]->name[0]==char(1)) return index[0];
+
+ return -1;
+
+ }
+
+ int Data::AddCategory ( cpstr cname ) {
+ // return -1: a place for category has been added on the top of array;
+ // index is added and sorted automatically
+ // >=0: the category is already in the array -- its position
+ // is returned
+ int l1,l;
+ PPCategory Category1;
+ ivector index1;
+
+
+ if (!Category) {
+ Category = new PCategory[1];
+ Category[0] = NULL;
+ GetVectorMemory ( index,1,0 );
+ index[0] = 0;
+ nCategories = 1;
+ return -nCategories; // the category has been added on the top of array
+ }
+ l1 = GetCategoryNo ( cname );
+ if (l1>=0) return l1; // non-negative returns mean that
+ // the category is already in the array
+ l1 = -l1-1; // otherwise the category has to be added and indexed at here
+ // put new NULL-category on the top of array and update the index
+ Category1 = new PCategory[nCategories+1];
+ GetVectorMemory ( index1,nCategories+1,0 );
+ for (l=0;l<nCategories;l++)
+ Category1[l] = Category[l];
+ Category1[nCategories] = NULL;
+ for (l=0;l<l1;l++)
+ index1[l] = index[l];
+ index1[l1] = nCategories;
+ for (l=l1+1;l<=nCategories;l++)
+ index1[l] = index[l-1];
+ delete[] Category;
+ FreeVectorMemory ( index,0 );
+ Category = Category1;
+ index = index1;
+ nCategories++;
+ return -nCategories; // the category has been added on
+ // the top of array
+ }
+
+ bool Data::WriteMMCIFData ( cpstr FName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ f.assign ( FName,true,false,gzipMode );
+ if (f.rewrite()) {
+ WriteMMCIF ( f );
+ f.shut();
+ return true;
+ } else
+ return false;
+ }
+
+ void Data::WriteMMCIF ( io::RFile f ) {
+ int i;
+
+ if (name) {
+ f.Write ( pstr("\ndata_") );
+ f.WriteLine ( name );
+ } else
+ f.WriteLine ( pstr("\ndata_") );
+
+ for (i=0;i<nCategories;i++)
+ if (Category[i])
+ Category[i]->WriteMMCIF ( f );
+
+ }
+
+
+ // --------------- Retrieving data
+
+ int Data::DeleteCategory ( cpstr CName ) {
+ int k;
+ k = GetCategoryNo ( CName );
+ if (k<0) return CIFRC_NoCategory;
+ return DeleteCategory ( k );
+ }
+
+ int Data::DeleteCategory ( int CatNo ) {
+ int i;
+ if (Category[CatNo]) delete Category[CatNo];
+ for (i=CatNo+1;i<nCategories;i++)
+ Category[i-1] = Category[i];
+ i = 0;
+ while ((i<nCategories) && (index[i]!=CatNo)) {
+ if (index[i]>CatNo) index[i]--;
+ i++;
+ }
+ i++;
+ while (i<nCategories) {
+ if (index[i]>CatNo) index[i]--;
+ index[i-1] = index[i];
+ i++;
+ }
+ nCategories--;
+ index [nCategories] = 0;
+ Category[nCategories] = NULL;
+ return 0;
+ }
+
+ int Data::DeleteStructure ( cpstr CName ) {
+ int k;
+ k = GetCategoryNo ( CName );
+ if (k<0) return CIFRC_NoCategory;
+ if (Category[k]->GetCategoryID()==MMCIF_Struct)
+ return DeleteCategory ( k );
+ else return CIFRC_NotAStructure;
+ }
+
+ int Data::DeleteLoop ( cpstr CName ) {
+ int k;
+ k = GetCategoryNo ( CName );
+ if (k<0) return CIFRC_NoCategory;
+ if (Category[k]->GetCategoryID()==MMCIF_Loop)
+ return DeleteCategory ( k );
+ else return CIFRC_NotALoop;
+ }
+
+ PCategory Data::GetCategory ( int categoryNo ) {
+ if ((categoryNo>=0) && (categoryNo<nCategories))
+ return Category[categoryNo];
+ return NULL;
+ }
+
+ PStruct Data::GetStructure ( cpstr CName ) {
+ int i;
+ i = GetCategoryNo ( CName );
+ if (i<0) return NULL;
+ if (Category[i]->GetCategoryID()==MMCIF_Struct)
+ return PStruct(Category[i]);
+ else return NULL;
+ }
+
+ PLoop Data::GetLoop ( cpstr CName ) {
+ int i;
+ i = GetCategoryNo ( CName );
+ if (i<0) return NULL;
+ if (Category[i]->GetCategoryID()==MMCIF_Loop)
+ return PLoop(Category[i]);
+ else return NULL;
+ }
+
+ PLoop Data::FindLoop ( cpstr * tagList ) {
+ int i;
+ for (i=0;i<nCategories;i++)
+ if (Category[i]) {
+ if (Category[i]->GetCategoryID()==MMCIF_Loop) {
+ if (Category[i]->CheckTags(tagList))
+ return PLoop(Category[i]);
+ }
+ }
+ return NULL;
+ }
+
+ void Data::GetDataName ( pstr & dname, bool Remove ) {
+ if (Remove) {
+ if (dname) delete[] dname;
+ dname = name;
+ name = NULL;
+ } else
+ CreateCopy ( dname,name );
+ }
+
+ int Data::CheckData ( cpstr CName, cpstr TName ) {
+ // CheckData(..) returns positive value if the field is in the
+ // file:
+ // CIFRC_Structure category CName is a structure
+ // CIFRC_Loop category CName is a loop
+ // Negative returns mean:
+ // CIFRC_StructureNoTag category CName is present,
+ // it is a structure, but it does not
+ // have tag TName
+ // CIFRC_LoopNoTag category CName is present,
+ // it is a loop, but it does not have
+ // tag TName
+ // CIFRC_NoCategory category CName is not present.
+ // If TName is set to NULL then only the CName is checked and
+ // possible returns are CIFRC_Structure, CIFRC_Loop and
+ // CIFRC_NoCategory.
+ int i,k;
+ i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()==MMCIF_Struct)
+ k = CIFRC_Structure;
+ else k = CIFRC_Loop;
+ if (TName) {
+ if (Category[i]->GetTagNo(TName)<0) {
+ if (k==CIFRC_Structure)
+ k = CIFRC_StructureNoTag;
+ else k = CIFRC_LoopNoTag;
+ }
+ }
+ return k;
+ }
+
+ void Data::Optimize() {
+ int i,k;
+ PPCategory C1;
+ k = 0;
+ for (i=0;i<nCategories;i++)
+ if (Category[i]) {
+ Category[i]->Optimize();
+ if (Category[i]->nTags<=0) {
+ delete Category[i];
+ Category[i] = NULL;
+ } else
+ k++;
+ }
+ if (k>0) {
+ if (k!=nCategories) {
+ C1 = new PCategory[k];
+ k = 0;
+ for (i=0;i<nCategories;i++)
+ if (Category[i])
+ C1[k++] = Category[i];
+ if (Category) delete[] Category;
+ Category = C1;
+ nCategories = k;
+ FreeVectorMemory ( index,0 );
+ Sort();
+ }
+ } else {
+ if (Category) delete[] Category;
+ Category = NULL;
+ nCategories = 0;
+ }
+ }
+
+ int Data::GetString ( pstr & Dest, cpstr CName,
+ cpstr TName, bool Remove ) {
+ // GetString(..), GetReal(..) and GetInteger(..) return 0 if the
+ // requested field was found and successfully converted. Negative
+ // returns mean:
+ // CIFRC_WrongFormat the field was found but failed to convert
+ // due to improper numeric format
+ // CIFRC_NoTag category CName was found, but it does not
+ // have tag TName
+ // CIFRC_NoCategory category CName was not found
+ // CIFRC_NotAStructure category CName was found, but it is a loop
+ // rather than a structure.
+ // GetString(..) will try to dispose Dest unless it is assugned
+ // NULL value before the call. The string will be then dynamically
+ // allocated and copied.
+ int i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()!=MMCIF_Struct)
+ return CIFRC_NotAStructure;
+ return PStruct(Category[i])->GetString ( Dest,TName,Remove );
+ }
+
+ pstr Data::GetString ( cpstr CName, cpstr TName, int & RC ) {
+ int i = GetCategoryNo ( CName );
+ if (i<0) {
+ RC = CIFRC_NoCategory;
+ return NULL;
+ }
+ if (Category[i]->GetCategoryID()!=MMCIF_Struct) {
+ RC = CIFRC_NotAStructure;
+ return NULL;
+ }
+ return PStruct(Category[i])->GetString ( TName,RC );
+ }
+
+ int Data::DeleteField ( cpstr CName, cpstr TName ) {
+ int i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()!=MMCIF_Struct)
+ return CIFRC_NotAStructure;
+ return PStruct(Category[i])->DeleteField ( TName );
+ }
+
+ int Data::GetReal ( realtype & R, cpstr CName,
+ cpstr TName, bool Remove ) {
+ int i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()!=MMCIF_Struct)
+ return CIFRC_NotAStructure;
+ return PStruct(Category[i])->GetReal ( R,TName,Remove );
+ }
+
+ int Data::GetInteger ( int & I, cpstr CName,
+ cpstr TName, bool Remove ) {
+ int j = GetCategoryNo ( CName );
+ if (j<0) return CIFRC_NoCategory;
+ if (Category[j]->GetCategoryID()!=MMCIF_Struct)
+ return CIFRC_NotAStructure;
+ return PStruct(Category[j])->GetInteger ( I,TName,Remove );
+ }
+
+ int Data::GetLoopLength ( cpstr CName ) {
+ // GetLoopLength(..) returns CIFRC_NotALoop if the category CName
+ // is not a loop, CIFRC_NoCategory if the category CName is not
+ // found. Non-negative returns give the length of the loop (may be
+ // 0 if the loop is empty).
+ int i;
+ i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+ return CIFRC_NotALoop;
+ return PLoop(Category[i])->nRows;
+ }
+
+ int Data::GetLoopString ( pstr & Dest, cpstr CName,
+ cpstr TName, int nrow,
+ bool Remove ) {
+ // GetLoopString(..), GetLoopReal(..) and GetLoopInteger(..) act
+ // like GetString(..), GetReal(..) and GetInteger(..) above for
+ // nrow-th element of the 'loop_' (indexed like 0..N-1 where N
+ // is obtained through GetLoopLength(..)). They will return
+ // CIFRC_WrongIndex if nrow is out of range.
+ int i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+ return CIFRC_NotALoop;
+ return PLoop(Category[i])->GetString ( Dest,TName,nrow,Remove );
+ }
+
+ pstr Data::GetLoopString ( cpstr CName, cpstr TName,
+ int nrow, int & RC ) {
+ int i = GetCategoryNo ( CName );
+ if (i<0) {
+ RC = CIFRC_NoCategory;
+ return NULL;
+ }
+ if (Category[i]->GetCategoryID()!=MMCIF_Loop) {
+ RC = CIFRC_NotALoop;
+ return NULL;
+ }
+ return PLoop(Category[i])->GetString ( TName,nrow,RC );
+ }
+
+ int Data::DeleteLoopField ( cpstr CName, cpstr TName,
+ int nrow ) {
+ int i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+ return CIFRC_NotALoop;
+ return PLoop(Category[i])->DeleteField ( TName,nrow );
+ }
+
+ int Data::GetLoopReal ( realtype & R, cpstr CName,
+ cpstr TName, int nrow,
+ bool Remove ) {
+ int i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+ return CIFRC_NotALoop;
+ return PLoop(Category[i])->GetReal ( R,TName,nrow,Remove );
+ }
+
+ int Data::GetLoopInteger ( int & I, cpstr CName,
+ cpstr TName, int nrow,
+ bool Remove ) {
+ int j = GetCategoryNo ( CName );
+ if (j<0) return CIFRC_NoCategory;
+ if (Category[j]->GetCategoryID()!=MMCIF_Loop)
+ return CIFRC_NotALoop;
+ return PLoop(Category[j])->GetInteger ( I,TName,nrow,Remove );
+ }
+
+
+ int Data::GetLoopSVector ( psvector & S, cpstr CName,
+ cpstr TName, int i1, int i2,
+ bool Remove ) {
+ // GetLoopSVector(..), GetLoopRVector(..) and GetLoopIVector(..)
+ // read CIF 'loop_' data into allocated vectors of strings, reals and
+ // integers, correspondingly. The vectors may be deallocated prior
+ // to call and assigned NULL, in which case they will be allocated
+ // with offsets of i1, which is also the lower index of the 'loop_'
+ // data transferred into it. The upper vector index is given by i2 or
+ // by the loop's length whichever is less. If vectors are not assigned
+ // NULL prior the call, it is assumed that they are properly (i1-offset,
+ // i2-i1+1 length) allocated.
+ // The return codes are same as those of GetLoopString(..),
+ // GetLoopReal(..) and GetLoopInteger(..).
+ int i;
+ i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+ return CIFRC_NotALoop;
+ return PLoop(Category[i])->GetSVector ( S,TName,i1,i2,Remove );
+ }
+
+ int Data::GetLoopRVector ( rvector & R, cpstr CName,
+ cpstr TName, int i1, int i2,
+ bool Remove ) {
+ int i;
+ i = GetCategoryNo ( CName );
+ if (i<0) return CIFRC_NoCategory;
+ if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+ return CIFRC_NotALoop;
+ return PLoop(Category[i])->GetRVector ( R,TName,i1,i2,Remove );
+ }
+
+ int Data::GetLoopIVector ( ivector & I, cpstr CName,
+ cpstr TName, int i1, int i2,
+ bool Remove ) {
+ int j;
+ j = GetCategoryNo ( CName );
+ if (j<0) return CIFRC_NoCategory;
+ if (Category[j]->GetCategoryID()!=MMCIF_Loop)
+ return CIFRC_NotALoop;
+ return PLoop(Category[j])->GetIVector ( I,TName,i1,i2,Remove );
+ }
+
+
+ // --------------- Storing data
+
+ void Data::PutDataName ( cpstr dname ) {
+ // stores name for 'data_' record
+ CreateCopy ( name,dname );
+ }
+
+ int Data::PutNoData ( int NoDataType, cpstr CName, cpstr TName ) {
+ PStruct cifStruct;
+ int i,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifStruct = new Struct ( CName );
+ Category[nCategories-1] = cifStruct;
+ } else {
+ cifStruct = PStruct(Category[i]);
+ if (cifStruct->GetCategoryID()!=MMCIF_Struct) {
+ RC = CIFRC_NotAStructure;
+ delete Category[i];
+ cifStruct = new Struct ( CName );
+ Category[i] = cifStruct;
+ }
+ }
+
+ cifStruct->PutNoData ( NoDataType,TName );
+
+ return RC;
+
+ }
+
+ int Data::PutString ( cpstr S, cpstr CName,
+ cpstr TName, bool Concatenate ) {
+ // PutString(..), PutReal(..) and PutInteger(..) will put the
+ // values given into the specified category (CName) under the
+ // specified tag (TName). The category, tag and field are created
+ // automatically; the field will be replaced silently if identical
+ // CName.TName is specified in two calls. Calls of these functions
+ // may follow in random order; however CIF file will have all tags
+ // grouped by categories and catgories will follow in the order
+ // of first appearance in PutString(..), PutReal(..) or
+ // PutInteger(..).
+ // Return code - one of CIFRC_Ok or CIFRC_NotAStruct
+ PStruct cifStruct;
+ int i,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifStruct = new Struct ( CName );
+ Category[nCategories-1] = cifStruct;
+ } else {
+ cifStruct = PStruct(Category[i]);
+ if (cifStruct->GetCategoryID()!=MMCIF_Struct) {
+ RC = CIFRC_NotAStructure;
+ delete Category[i];
+ cifStruct = new Struct ( CName );
+ Category[i] = cifStruct;
+ }
+ }
+
+ cifStruct->AddField ( S,TName,Concatenate );
+
+ return RC;
+
+ }
+
+ int Data::PutDate ( cpstr CName, cpstr TName ) {
+ PStruct cifStruct;
+ int i,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifStruct = new Struct ( CName );
+ Category[nCategories-1] = cifStruct;
+ } else {
+ cifStruct = PStruct(Category[i]);
+ if (cifStruct->GetCategoryID()!=MMCIF_Struct) {
+ RC = CIFRC_NotAStructure;
+ delete Category[i];
+ cifStruct = new Struct ( CName );
+ Category[i] = cifStruct;
+ }
+ }
+
+ cifStruct->PutDate ( TName );
+
+ return RC;
+
+ }
+
+ int Data::PutReal ( realtype R, cpstr CName,
+ cpstr TName, int prec ) {
+ char rS[100];
+ sprintf ( rS,"%.*g",prec,R );
+ return PutString ( rS,CName,TName,false );
+ }
+
+ int Data::PutInteger ( int I, cpstr CName,
+ cpstr TName ) {
+ char iS[100];
+ if (I>MinInt4) sprintf ( iS,"%i",I );
+ else {
+ iS[0] = char(2);
+ iS[1] = '.';
+ iS[2] = char(0);
+ }
+ return PutString ( iS,CName,TName,false );
+ }
+
+
+ int Data::AddLoop ( cpstr CName, PLoop & cifLoop ) {
+ int i,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifLoop = new Loop ( CName );
+ Category[nCategories-1] = cifLoop;
+ RC = CIFRC_Created;
+ } else {
+ cifLoop = PLoop(Category[i]);
+ if (cifLoop->GetCategoryID()!=MMCIF_Loop) {
+ RC = CIFRC_NotALoop;
+ delete Category[i];
+ cifLoop = new Loop ( CName );
+ Category[i] = cifLoop;
+ }
+ }
+
+ return RC;
+
+ }
+
+ int Data::AddStructure ( cpstr CName, PStruct & cifStruct ) {
+ int i,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifStruct = new Struct ( CName );
+ Category[nCategories-1] = cifStruct;
+ RC = CIFRC_Created;
+ } else {
+ cifStruct = PStruct(Category[i]);
+ if (cifStruct->GetCategoryID()!=MMCIF_Struct) {
+ RC = CIFRC_NotAStructure;
+ delete Category[i];
+ cifStruct = new Struct ( CName );
+ Category[i] = cifStruct;
+ }
+ }
+
+ return RC;
+
+ }
+
+
+ int Data::PutLoopNoData ( int NoDataType, cpstr CName,
+ cpstr TName, int nrow ) {
+ PLoop cifLoop;
+ int i,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifLoop = new Loop ( CName );
+ Category[nCategories-1] = cifLoop;
+ } else {
+ cifLoop = PLoop(Category[i]);
+ if (cifLoop->GetCategoryID()!=MMCIF_Loop) {
+ RC = CIFRC_NotALoop;
+ delete Category[i];
+ cifLoop = new Loop ( CName );
+ Category[i] = cifLoop;
+ }
+ }
+
+ cifLoop->PutNoData ( NoDataType,TName,nrow );
+
+ return RC;
+
+ }
+
+
+ int Data::PutLoopString ( cpstr S, cpstr CName,
+ cpstr TName, int nrow ) {
+ // PutLoopString(..), PutLoopReal(..) and PutLoopInteger(..) act
+ // like PutString(..), PutReal(..) and PutInteger(..) above for
+ // nrow-th element of the 'loop_' CName (indexed begining from 0).
+ // In consequitive calls, given values of nrow does not have to be
+ // ordered; the most efficient way is to start with HIGHEST value
+ // for nrow in the loop and move down to 0. The least efficient way
+ // is to start with nrow=0 and move up.
+ PLoop cifLoop;
+ int i,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifLoop = new Loop ( CName );
+ Category[nCategories-1] = cifLoop;
+ } else {
+ cifLoop = PLoop(Category[i]);
+ if (cifLoop->GetCategoryID()!=MMCIF_Loop) {
+ RC = CIFRC_NotALoop;
+ delete Category[i];
+ cifLoop = new Loop ( CName );
+ Category[i] = cifLoop;
+ }
+ }
+
+ cifLoop->PutString ( S,TName,nrow );
+
+ return RC;
+
+ }
+
+ int Data::PutLoopReal ( realtype R, cpstr CName,
+ cpstr TName, int nrow, int prec ) {
+ char rS[100];
+ sprintf ( rS,"%.*g",prec,R );
+ return PutLoopString ( rS,CName,TName,nrow );
+ }
+
+ int Data::PutLoopInteger ( int I, cpstr CName,
+ cpstr TName, int nrow ) {
+ char iS[100];
+ sprintf ( iS,"%i",I );
+ return PutLoopString ( iS,CName,TName,nrow );
+ }
+
+
+ int Data::PutLoopSVector ( psvector S, cpstr CName,
+ cpstr TName, int i1, int i2 ) {
+ // PutLoopSVector(..), PutLoopRVector(..) and PutLoopIVector(..)
+ // put vectors of values into specified loop fields. Parameters i1
+ // and i2 give the range of indices of values which are to be
+ // transfered. To transfer an entire vector allocated as [0..N-1]
+ // i1 shoudl be set to 0 and i2 - to N-1. Note that the loop is
+ // always indexed as starting form 0 on, therefore negative i1 and
+ // i2 are not allowed, and specifying i1>0 will leave first i1
+ // elements of the CIF loop for the corresponding tag undefined
+ // (will be output like '?').
+ PLoop cifLoop;
+ int i,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifLoop = new Loop ( CName );
+ Category[nCategories-1] = cifLoop;
+ } else {
+ cifLoop = PLoop(Category[i]);
+ if (cifLoop->GetCategoryID()!=MMCIF_Loop) {
+ RC = CIFRC_NotALoop;
+ delete Category[i];
+ cifLoop = new Loop ( CName );
+ Category[i] = cifLoop;
+ }
+ }
+
+ cifLoop->PutSVector ( S,TName,i1,i2 );
+
+ return RC;
+
+ }
+
+ int Data::PutLoopRVector ( rvector R, cpstr CName,
+ cpstr TName,
+ int i1, int i2, int prec ) {
+ PLoop cifLoop;
+ int i,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifLoop = new Loop ( CName );
+ Category[nCategories-1] = cifLoop;
+ } else {
+ cifLoop = PLoop(Category[i]);
+ if (cifLoop->GetCategoryID()!=MMCIF_Loop) {
+ RC = CIFRC_NotALoop;
+ delete Category[i];
+ cifLoop = new Loop ( CName );
+ Category[i] = cifLoop;
+ }
+ }
+
+ cifLoop->PutRVector ( R,TName,i1,i2,prec );
+
+ return RC;
+
+ }
+
+ int Data::PutLoopIVector ( ivector I, cpstr CName,
+ cpstr TName,
+ int i1, int i2 ) {
+ PLoop cifLoop;
+ int j,RC;
+
+ RC = CIFRC_Ok;
+
+ // look for category
+ j = AddCategory ( CName );
+ if (j<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ cifLoop = new Loop ( CName );
+ Category[nCategories-1] = cifLoop;
+ } else {
+ cifLoop = PLoop(Category[j]);
+ if (cifLoop->GetCategoryID()!=MMCIF_Loop) {
+ RC = CIFRC_NotALoop;
+ delete Category[j];
+ cifLoop = new Loop ( CName );
+ Category[j] = cifLoop;
+ }
+ }
+
+ cifLoop->PutIVector ( I,TName,i1,i2 );
+
+ return RC;
+
+ }
+
+
+ int Data::RenameCategory ( cpstr CName,
+ cpstr newCName ) {
+ int i,RC;
+ i = GetCategoryNo ( CName );
+ if (i>=0) {
+ Category[i]->PutCategoryName ( newCName );
+ Sort();
+ RC = CIFRC_Ok;
+ } else
+ RC = CIFRC_NoCategory;
+ return RC;
+ }
+
+
+ void Data::Copy ( PData Data ) {
+ int i;
+ FreeMemory(0);
+ CreateCopy ( name,Data->name );
+ nCategories = Data->nCategories;
+ if (nCategories>0) {
+ Category = new PCategory[nCategories];
+ GetVectorMemory ( index,nCategories,0 );
+ for (i=0;i<nCategories;i++) {
+ if (Data->Category[i]) {
+ if (Data->Category[i]->GetCategoryID()==MMCIF_Struct)
+ Category[i] = new Struct();
+ else Category[i] = new Loop();
+ Category[i]->Copy ( Data->Category[i] );
+ } else
+ Category[i] = NULL;
+ index[i] = Data->index[i];
+ }
+ }
+ flags = Data->flags;
+ Warning = Data->Warning;
+ }
+
+
+ int Data::CopyCategory ( PData Data, cpstr CName,
+ cpstr newCName ) {
+ PCategory Cat;
+ int i,di,dc,RC;
+
+ di = Data->GetCategoryNo ( CName );
+
+ if (di>=0) {
+
+ RC = CIFRC_Ok;
+ dc = Data->Category[di]->GetCategoryID();
+
+ // look for category
+ i = AddCategory ( CName );
+ if (i<0) {
+ // negative value means that the category was not in the list,
+ // but a place for it has been provided and index updated
+ if (dc==MMCIF_Loop) Cat = new Loop ( CName );
+ else Cat = new Struct ( CName );
+ Category[nCategories-1] = Cat;
+ } else {
+ Cat = Category[i];
+ if (Cat->GetCategoryID()!=dc) {
+ RC = CIFRC_NotAStructure;
+ delete Category[i];
+ if (dc==MMCIF_Loop) Cat = new Loop ( CName );
+ else Cat = new Struct ( CName );
+ Category[i] = Cat;
+ }
+ }
+
+ Cat->Copy ( Data->Category[di] );
+ if (newCName) {
+ Cat->PutCategoryName ( newCName );
+ Sort();
+ }
+
+ } else
+ RC = CIFRC_NoCategory;
+
+ return RC;
+
+ }
+
+ void Data::PrintCategories() {
+ // for debuging only
+ int i;
+ printf ( " Total %i categories:\n",nCategories );
+ for (i=0;i<nCategories;i++)
+ if (Category[i]) {
+ printf ( " %5i. ",i+1 );
+ if (Category[i]->GetCategoryID()==MMCIF_Loop)
+ printf ( "Loop %s\n",Category[i]->name );
+ else printf ( "Structure %s\n",Category[i]->name );
+ }
+ }
+
+
+ void Data::write ( io::RFile f ) {
+ int i,k;
+ if (!index) Sort();
+ f.CreateWrite ( name );
+ f.WriteInt ( &nCategories );
+ for (i=0;i<nCategories;i++) {
+ if (Category[i]) {
+ k = Category[i]->GetCategoryID();
+ f.WriteInt ( &k );
+ Category[i]->write ( f );
+ } else {
+ k = -1;
+ f.WriteInt ( &k );
+ }
+ f.WriteInt ( &(index[i]) );
+ }
+ f.WriteInt ( &flags );
+ f.WriteInt ( &Warning );
+ }
+
+
+ void Data::read ( io::RFile f ) {
+ int i,k;
+ FreeMemory(0);
+ f.CreateRead ( name );
+ f.ReadInt ( &nCategories );
+ if (nCategories>0) {
+ Category = new PCategory[nCategories];
+ GetVectorMemory ( index,nCategories,0 );
+ for (i=0;i<nCategories;i++) {
+ f.ReadInt ( &k );
+ if (k>=0) {
+ if (k==MMCIF_Struct) Category[i] = new Struct();
+ else Category[i] = new Loop();
+ Category[i]->read ( f );
+ } else
+ Category[i] = NULL;
+ f.ReadInt ( &(index[i]) );
+ }
+ }
+ f.ReadInt ( &flags );
+ f.ReadInt ( &Warning );
+ }
+
+
+ MakeStreamFunctions(Data)
+
+
+
+ // ====================== File =============================
+
+
+ File::File() : io::Stream() {
+ InitFile();
+ }
+
+ File::File ( cpstr FName, io::GZ_MODE gzipMode ) : io::Stream() {
+ InitFile ();
+ ReadMMCIFFile ( FName,gzipMode );
+ }
+
+ File::File ( io::RPStream Object ) : io::Stream(Object) {
+ InitFile();
+ }
+
+ File::~File() {
+ FreeMemory();
+ }
+
+ void File::InitFile() {
+ nData = 0;
+ nAllocData = 0;
+ data = NULL;
+ index = NULL;
+ PrintWarnings = false;
+ StopOnWarning = false;
+ }
+
+ void File::FreeMemory() {
+ int i;
+ for (i=0;i<nData;i++)
+ if (data[i]) delete data[i];
+ if (data) delete[] data;
+ data = NULL;
+ FreeVectorMemory ( index,0 );
+ nData = 0;
+ nAllocData = 0;
+ }
+
+
+ pstr GetMMCIFInputBuffer ( int & LineNo ) {
+ LineNo = _err_line;
+ _err_string[sizeof(_err_string)-1] = char(0);
+ return _err_string;
+ }
+
+ int File::ReadMMCIFFile ( cpstr FName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ PData CIF;
+ char S[500];
+ int RC,lcount;
+
+ FreeMemory();
+
+ CIF = NULL;
+ f.assign ( FName,true,false,gzipMode );
+ if (f.reset(true)) {
+ S[0] = char(0);
+ lcount = 0;
+ RC = 0;
+ while ((!RC) && (!f.FileEnd())) {
+ if (!CIF) CIF = new Data();
+ CIF->SetPrintWarnings ( PrintWarnings );
+ CIF->SetStopOnWarning ( StopOnWarning );
+ RC = CIF->ReadMMCIFData ( f,S,lcount );
+ if (!RC) {
+ ExpandData ( nData+1 );
+ data[nData] = CIF;
+ nData++;
+ CIF = NULL;
+ }
+ }
+ if (CIF) delete CIF;
+ f.shut();
+ if (RC==CIFRC_NoDataLine) {
+ if (nData>0) RC = 0;
+ }
+ Sort();
+ return RC;
+ } else
+ return CIFRC_CantOpenFile;
+
+ }
+
+ int File::WriteMMCIFFile ( cpstr FName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ f.assign ( FName,true,false,gzipMode );
+ if (f.rewrite()) {
+ WriteMMCIF ( f );
+ f.shut();
+ return 0;
+ } else
+ return CIFRC_CantOpenFile;
+ }
+
+ void File::WriteMMCIF ( io::RFile f ) {
+ int i;
+ for (i=0;i<nData;i++)
+ if (data[i])
+ data[i]->WriteMMCIF ( f );
+ }
+
+
+ void File::Sort() {
+ psvector tag;
+ int i;
+ if (nData>0) {
+ FreeVectorMemory ( index,0 );
+ GetVectorMemory ( index,nData,0 );
+ GetVectorMemory ( tag ,nData,0 );
+ for (i=0;i<nData;i++) {
+ tag[i] = NULL;
+ CreateCopy ( tag[i],data[i]->name );
+ }
+ SortTags ( tag,nData,index );
+ for (i=0;i<nData;i++)
+ if (tag[i]) {
+ delete[] tag[i];
+ tag[i] = NULL;
+ }
+ FreeVectorMemory ( tag,0 );
+ }
+ }
+
+ int File::GetCIFDataNo ( cpstr DName ) {
+ // Binary search for index of DName ttag in data[].
+ // Return:
+ // >=0 : position of the DName found
+ // <0 : the DName was not found, it could be inserted before
+ // (-RC-1)th element, where RC is the return value
+ int l1,l2,l,k;
+
+ if (!data) return -1;
+ if (!index) Sort();
+
+ l = 0;
+ l1 = 0;
+ l2 = nData-1;
+ k = 1;
+ while (l1<l2-1) {
+ l = (l1+l2)/2;
+ k = strcasecmp ( DName,data[index[l]]->name );
+ if (k<0) l2 = l;
+ else if (k>0) l1 = l;
+ else {
+ l1 = l;
+ break;
+ }
+ }
+
+ if (k==0) return index[l]; // is at RCth position
+ k = strcasecmp ( DName,data[index[l1]]->name );
+ if (k==0) return index[l1]; // is at RCth position
+ if (k<0) return -1; // would be at (-RC-1)th position
+ if (l2!=l1) {
+ k = strcasecmp ( DName,data[index[l2]]->name );
+ if (k==0) return index[l2]; // is at RCth position
+ if (k>0) return -2-l2; // would be at l2+1=(-RC-1)th position
+ }
+
+ return -2-l1; // would be at l1+1=(-RC-1)th position
+
+ }
+
+ PData File::GetCIFData ( int dataNo ) {
+ if ((dataNo>=0) && (dataNo<nData)) return data[dataNo];
+ else return NULL;
+ }
+
+ PData File::GetCIFData ( cpstr DName ) {
+ int l;
+ l = GetCIFDataNo ( DName );
+ if (l>=0) return data[l];
+ else return NULL;
+ }
+
+ void File::ExpandData ( int nDataNew ) {
+ int i,nAD;
+ PPData data1;
+ ivector index1;
+ if (nDataNew>nAllocData) {
+ nAD = nDataNew + IMin(nAllocData/2+1,100);
+ data1 = new PData[nAD];
+ GetVectorMemory ( index1,nAD,0 );
+ for (i=0;i<nAllocData;i++) {
+ data1 [i] = data [i];
+ index1[i] = index[i];
+ }
+ for (i=nAllocData;i<nAD;i++) {
+ data1 [i] = NULL;
+ index1[i] = i;
+ }
+ if (data) delete[] data;
+ FreeVectorMemory ( index,0 );
+ data = data1;
+ index = index1;
+ nAllocData = nAD;
+ }
+ }
+
+ int File::AddCIFData ( cpstr DName ) {
+ // return -1: the CIF data structure has been added on the
+ // top of data array; the index is added and sorted
+ // automatically
+ // >=0: the CIF data structure is already in the array
+ // -- its position is returned
+ int i1,i;
+ if (!data) {
+ ExpandData ( 3 ); // get space for first 3 CIF data structures
+ data[0] = new Data ( DName );
+ nData = 1;
+ return -nData; // the CIF data structure has been added
+ // "on the top" of array
+ }
+ i1 = GetCIFDataNo ( DName );
+ if (i1>=0) return i1; // non-negative returns mean that the CIF
+ // data structure is already in the array
+ i1 = -i1-1; // otherwise the data has to be added and indexed at here
+ // put new CIF data structure on the top of array and update index
+ ExpandData ( nData+1 );
+ data[nData] = new Data ( DName );
+ for (i=nData;i>i1;i--)
+ index[i] = index[i-1];
+ index[i1] = nData;
+ nData++;
+ return -nData; // the tag has been added on the top of array
+ }
+
+
+ int File::DeleteCIFData ( cpstr DName ) {
+ int dataNo = GetCIFDataNo ( DName );
+
+ if (dataNo>=0) return DeleteCIFData ( dataNo );
+ return dataNo;
+
+ }
+
+ int File::DeleteCIFData ( int dataNo ) {
+ int i;
+
+ if ((0<=dataNo) && (dataNo<nData)) {
+
+ if (data[dataNo]) delete data[dataNo];
+ for (i=dataNo+1;i<nData;i++)
+ data[i-1] = data[i];
+ nData--;
+
+ Sort();
+
+ return 0;
+
+ }
+
+ return -nData;
+
+ }
+
+ void File::Copy ( PFile File ) {
+ int i;
+ FreeMemory();
+ nData = File->nData;
+ nAllocData = nData;
+ if (nData>0) {
+ data = new PData[nData];
+ for (i=0;i<nData;i++) {
+ if (File->data[i]) {
+ data[i] = new Data();
+ data[i]->Copy ( File->data[i] );
+ } else
+ data[i] = NULL;
+ }
+ }
+ }
+
+
+ void File::write ( io::RFile f ) {
+ int i,k;
+ f.WriteInt ( &nData );
+ for (i=0;i<nData;i++)
+ if (data[i]) {
+ k = 1;
+ f.WriteInt ( &k );
+ data[i]->write ( f );
+ } else {
+ k = 0;
+ f.WriteInt ( &k );
+ }
+ }
+
+ void File::read ( io::RFile f ) {
+ int i,k;
+ FreeMemory();
+ f.ReadInt ( &nData );
+ nAllocData = nData;
+ if (nData>0) {
+ data = new PData[nData];
+ for (i=0;i<nData;i++) {
+ f.ReadInt ( &k );
+ if (k) {
+ data[i] = new Data();
+ data[i]->read ( f );
+ } else
+ data[i] = NULL;
+ }
+ }
+ }
+
+
+ MakeStreamFunctions(File)
+
+
+ int isCIF ( cpstr FName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ int rc;
+
+ f.assign ( FName,true,false,gzipMode );
+ if (f.reset(true)) {
+ rc = isCIF ( f );
+ f.shut();
+ } else
+ rc = -1;
+
+ return rc;
+
+ }
+
+ int isCIF ( io::RFile f ) {
+ char S[_max_buf_len+1];
+ bool Done;
+ pstr p;
+
+ f.ReadLine ( S,_max_buf_len );
+ S[_max_buf_len] = char(0);
+ Done = false;
+ while (!Done) {
+ p = &(S[0]);
+ while ((*p==' ') || (*p==char(9))) p++;
+ Done = !strncmp(p,"data_",5);
+ if (!Done) {
+ if (f.FileEnd()) {
+ Done = true;
+ p = NULL;
+ } else {
+ f.ReadLine ( S,_max_buf_len );
+ S[_max_buf_len] = char(0);
+ }
+ }
+ }
+
+ if (!p) return 1;
+ if (!strncmp(p,"data_",5)) return 0;
+ else return 1;
+
+ }
+
+
+ pstr GetCIFMessage ( pstr M, int RC ) {
+ int LineNo;
+ pstr InputLine;
+
+ InputLine = GetMMCIFInputBuffer ( LineNo );
+
+ if (RC>10) {
+ if (RC & CIFW_UnrecognizedItems)
+ sprintf ( M,"unrecognized items found on %ith line\n%s",
+ LineNo,InputLine );
+ else if (RC & CIFW_MissingField)
+ sprintf ( M,"expected data field not found; line %i reads\n%s",
+ LineNo,InputLine );
+ else if (RC & CIFW_EmptyLoop)
+ sprintf ( M,"empty loop ('loop_') on %ith line\n%s",
+ LineNo,InputLine );
+ else if (RC & CIFW_UnexpectedEOF)
+ sprintf ( M,"unexpected end of file; line %i reads\n%s",
+ LineNo,InputLine );
+ else if (RC & CIFW_LoopFieldMissing)
+ sprintf ( M,"expected data field in a loop not found; "
+ "line %i reads\n%s", LineNo,InputLine );
+ else if (RC & CIFW_LoopFieldMissing)
+ sprintf ( M,"expected data field in a loop not found; "
+ "line %i reads\n%s", LineNo,InputLine );
+ else if (RC & CIFW_NotAStructure)
+ sprintf ( M,"a loop is used as a structure on line %i\n%s",
+ LineNo,InputLine );
+ else if (RC & CIFW_NotALoop)
+ sprintf ( M,"a structure is used as a loop on line %i\n%s",
+ LineNo,InputLine );
+ else if (RC & CIFW_DuplicateTag)
+ sprintf ( M,"duplicate tag was found on line %i\n%s",
+ LineNo,InputLine );
+ else
+ sprintf ( M,"undocumented warning issued for line %i\n%s",
+ LineNo,InputLine );
+ } else if (RC<0)
+ switch (RC) {
+ case CIFRC_StructureNoTag : strcpy(M,"tag of a structure not "
+ "found");
+ break;
+ case CIFRC_LoopNoTag : strcpy(M,"tag of a loop not found");
+ break;
+ case CIFRC_NoCategory : strcpy(M,"category not found");
+ break;
+ case CIFRC_WrongFormat : strcpy(M,"wrong format of a number");
+ break;
+ case CIFRC_NoTag : strcpy(M,"tag not found");
+ break;
+ case CIFRC_NotAStructure : strcpy(M,"category is not a "
+ "structure");
+ break;
+ case CIFRC_NotALoop : strcpy(M,"category is not a loop");
+ break;
+ case CIFRC_WrongIndex : strcpy(M,"index outside the loop's "
+ "limits");
+ break;
+ case CIFRC_NoField : strcpy(M,"data is absent");
+ break;
+ case CIFRC_Created : strcpy(M,"category created");
+ break;
+ case CIFRC_CantOpenFile : strcpy(M,"can't open CIF file");
+ break;
+ case CIFRC_NoDataLine : strcpy(M,"'data_' tag not found." );
+ break;
+ default : strcpy(M,"undocumented return code");
+ }
+
+ return M;
+
+ }
+
+ } // namespace mmcif
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_mmcif_.h b/mmdb2/mmdb_mmcif_.h
new file mode 100644
index 0000000..388a24f
--- /dev/null
+++ b/mmdb2/mmdb_mmcif_.h
@@ -0,0 +1,2146 @@
+// $Id: mmdb_mmcif_.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_MMCIF <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::mmcif::Category ( mmCIF category )
+// ~~~~~~~~~ mmdb::mmcif::Struct ( mmCIF structure )
+// mmdb::mmcif::Loop ( mmCIF loop )
+// mmdb::mmcif::Data ( mmCIF data block )
+// mmdb::mmcif::File ( mmCIF file )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+
+#ifndef __MMDB_MMCIF__
+#define __MMDB_MMCIF__
+
+
+#include "mmdb_io_stream.h"
+
+namespace mmdb {
+
+ namespace mmcif {
+
+
+ // ====================== Category ==========================
+
+ enum MMCIF_ITEM {
+ MMCIF_Category = 0,
+ MMCIF_Struct = 1,
+ MMCIF_Loop = 2,
+ MMCIF_Data = 3
+ };
+
+ DefineClass(Category);
+ DefineStreamFunctions(Category);
+
+ /// \brief mmcif::Category is a base class for mmcif::Struct and
+ /// mmcif::Loop, implementations of mmCIF's "structure" and
+ /// "loop" categories.
+ /*!
+ This class is not instantiated independently in any applications,
+ however, it provides a few public functions which work for
+ both mmcif::Struct and mmcif::Loop.
+
+ All data in mmCIF hierarchy is addressed using construct
+ "category.tag" plus row number (>=0) for loops. Category names
+ should always start from underscore, while tags normally start
+ with a letter, e.g. "_barrel.id".
+
+ See general principles of working with mmCIF files and mmCIF
+ hierarchies in Section \"\ref mmcif_handler\".
+ */
+
+ class Category : public io::Stream {
+
+ friend class Data;
+
+ public :
+
+ /// \brief Basic constructor.
+ Category ();
+
+ /// \brief Constructor that assigns category name.
+ /// \param[in] N category name (must start with underscore).
+ Category ( cpstr N );
+
+ /// \brief Constructor for MMDB data streaming functions.
+ Category ( io::RPStream Object );
+
+ /// \brief Destructor.
+ ~Category();
+
+ /// \brief Returns category name.
+ /// \return NULL if name was not set
+ /// \return pointer to character string if name was set
+ inline pstr GetCategoryName() { return name; }
+
+ /// \brief Sets category name.
+ /// \param N new category name
+ void SetCategoryName ( cpstr N );
+
+ /// \brief Returns category type.
+ /// This function may be used when retrieving categories
+ /// (structures and loops) from data blocks (mmcif::Data).
+ /// \return MMCIF_Category for mmcif::Category
+ /// \return MMCIF_Struct for mmcif::Struct
+ /// \return MMCIF_Loop for mmcif::Loop
+ virtual MMCIF_ITEM GetCategoryID() { return MMCIF_Category; }
+
+ /// \brief Virtual function for writing category's content
+ /// into mmCIF file.
+ /// Default implementation does nothing.
+ virtual void WriteMMCIF ( io::RFile ) {}
+
+ /// \brief Virtual function for optimizig data structures.
+ /// Optimized data structures take less RAM and their indexes
+ /// are sorted for quicker access. Sorting is done automatically
+ /// as new data is added to the category. If the
+ /// category is edited (fields/data removed), it may need
+ /// optimization and re-sorting for efficiency.\n\n
+ /// The sorting preserves the order of actual appearance of
+ /// tags in mmCIF file. If a category is created
+ /// programmatically, the order of tags in mmCIF file will be
+ /// the same as order of adding them to the category.
+ virtual void Optimize();
+
+ /// \brief Sorts category's data for quicker access.
+ /// The sorting is essentially re-indexing of data for quicker
+ /// access. It does not change the order of data in both mmCIF
+ /// hierarchy and mmCIF file. E.g., if tag "serial_no" was 2nd
+ /// one in given category before sorting, it will remain on 2nd
+ /// place after it, therefore no change in tag number passed
+ /// to functions in mmcif::Struct, mmcif::Loop and mmcif::Data.
+ void Sort();
+
+ /// \brief Returns serial number of a tag in the category.
+ /// \param[in] ttag tag (or name of a field in category)
+ /// \return \b >=0 : the tag is in given position
+ /// \return \b <0 : the tag was not found, but it could be
+ /// inserted before tag with (-rc-1)th index, where
+ /// 'rc' is the return.
+ int GetTagNo ( cpstr ttag );
+
+ /// \brief Adds a tag to the category.
+ /// Adding a tag in mmcif::Category does not reserve any
+ /// placeholder for the corresponding value. All tags get
+ /// automatically sorted (reindexed) for quicker access.
+ /// Tags will appear in mmCIF file in order of their addition
+ /// to the category.
+ /// \param[in] ttag tag to be added.
+ /// \return \b >=0 the tag is already in the category, and return
+ /// is its serial number. No changes to the category
+ /// is done
+ /// \return \b <0 the tag was added to the list of tags, and
+ /// return is minus total number of tags in the
+ /// category.
+ int AddTag ( cpstr ttag );
+
+ /// \brief Returns the total number of tags in the category
+ int GetNofTags() { return nTags; }
+
+ /// \brief Returns tag with the specified serial number.
+ /// The tags are enumerated as 0..GetNofTags()-1.
+ /// \param tagNo tag's serial number
+ /// \return \b NULL: tagNo is outside the range
+ /// of 0..GetNofTags()-1
+ /// \return \b not \b NULL: tag in tagNo'th position
+ pstr GetTag ( int tagNo ); // 0..nTags-1
+
+ /// \brief Prints list of tags to stdout.
+ /// Both sorted and unsorted tags are printed to standard
+ /// output. This function may be used for debugging.
+ void PrintTags();
+
+ /// \brief Returns true if all tags from the list are found
+ /// in the category.
+ /// The size of the list of tags may be less than the number
+ /// of tags in the category, and order of tags is disregarded.
+ /// \param[in] tagList list of tags to be checked for presence
+ /// in the category. The list must end with NULL
+ /// pointer, or your program will crash.
+ /// \return \b true if all tags from the list were found in the
+ /// category
+ /// \return \b false if one or more tags from the list were not
+ /// found in the category.
+ ///
+ /// Example:
+ /// \code
+ /// cpstr tagList[] = {"id","type","date",NULL};
+ /// mmcif::Struct cifStruct;
+ /// if (cifStruct.CheckTags(tagList))
+ /// printf ( " all tags are found in category %s\n",
+ /// cifStruct.GetCategoryName() );
+ /// \endcode
+ /// This function is useful for finding categories in
+ /// "dirty cifs", where category name is not given.
+ bool CheckTags ( cpstr * tagList );
+
+ /// \brief Deep copy of categories.
+ /// Deep copy duplicates all data and memory allocations,
+ /// producing a genuine clone of the original. Only deep copy
+ /// should be used for copying MMDB objects, a mere assignment
+ /// operator will fail you.
+ /// \param[in] Category a pointer to mmcif::Category, the content of
+ /// which is copied into 'this' category.
+ virtual void Copy ( PCategory Category );
+
+ /// \brief MMDB stream writer.
+ void write ( io::RFile f );
+
+ /// \brief MMDB stream reader.
+ void read ( io::RFile f );
+
+ protected:
+ int nTags;
+ pstr name;
+ psvector tag;
+ ivector index;
+ int nAllocTags;
+
+ void InitCategory ();
+ virtual void FreeMemory ();
+ void ExpandTags ( int nTagsNew );
+ void PutCategoryName ( cpstr newName );
+
+ };
+
+
+
+ // ====================== Struct ============================
+
+ DefineClass(Struct);
+ DefineStreamFunctions(Struct);
+
+ /// \brief Constants used to specify mmCIF's \"data not given\" and
+ /// \"data not available\" data types.
+ extern const int CIF_NODATA_DOT;
+ extern const int CIF_NODATA_QUESTION;
+ extern cpstr CIF_NODATA_DOT_FIELD;
+ extern cpstr CIF_NODATA_QUESTION_FIELD;
+
+ /// \brief mmcif::Struct represents mmCIF's \"structure\" category,
+ /// where data follows directly the corresponding tag.
+ /*!
+ mmCIF's \"structure\" category has the following form:
+ \code
+ _structure_name.tag0 value0
+ _structure_name.tag1 value1
+ ...........
+ _structure_name.tagN valueN
+ \endcode
+ mmcif::Struct represents this construct by keeping category name
+ (\"_structure_name\") and associated lists of tags
+ (\"tag0,tag1...tagN\") and their values (\"value0,value1...valueN\").
+
+ The structure is created automatically when an mmCIF file is read,
+ or it may be created programatically and then pushed into file.
+
+ Access to data is provided via tags. Internally, all values are kept
+ as character fields, and it is only on the retrieval stage that they
+ are converted to other data types (integers, floats or strings).
+ If conversion is not possible, an error code is returned by the
+ corresponding functions, which should be checked by the application.
+
+ See general principles of working with mmCIF files and mmCIF
+ hierarchies, as well as some code samples, in Section
+ \"\ref mmcif_handler\".
+ */
+
+ class Struct : public Category {
+
+ public :
+
+ /// \brief Basic constructor
+ Struct ();
+
+ /// \brief Constructor that assigns structure name.
+ /// \param[in] N structure name (must start with underscore).
+ Struct ( cpstr N );
+
+ /// \brief Constructor for MMDB data streaming functions
+ Struct ( io::RPStream Object );
+
+ /// \brief Destructor
+ ~Struct();
+
+ /// \brief Adds field to the structure.
+ /// \param[in] F field value
+ /// \param[in] T tag name
+ /// \param[in] Concatenate flag to concatenate existing field
+ /// with the value of \b F. If tag \b T is already in
+ /// the structure and \b Concatenate=true, then
+ /// value of \b F is appended to the existing field.
+ /// Otherwise, the field is replaced with the value
+ /// of \b F
+ void AddField ( cpstr F, cpstr T, bool Concatenate=false );
+
+ /// \brief Returns category type \b MMCIF_Struct.
+ MMCIF_ITEM GetCategoryID() { return MMCIF_Struct; }
+
+ /// \brief Optimizes structure for RAM and data access speed.
+ /// Optimized data structures take less RAM and their indexes
+ /// are sorted for quicker access. Sorting is done automatically
+ /// as new data is added to the category. If the structure
+ /// is edited (fields/data removed), it may need
+ /// optimization and re-sorting for efficiency.\n\n
+ /// The sorting preserves the order of actual appearance of
+ /// tags in mmCIF file. If a structure is created
+ /// programmatically, the order of tags in mmCIF file will be
+ /// the same as order of adding them to the structure.
+ void Optimize();
+
+ /// \brief Returns value of field corresponding to tag in the
+ /// specified position.
+ /// Tag positions are defined by the order of their appearance in
+ /// mmCIF file (if structure was read from a file), or by the
+ /// order of their addition to the structure (if structure was
+ /// created programmatically). Tags are numbered as
+ /// 0...GetNofTags()-1.
+ /// \param[in] tagNo tag number (position in the structure)
+ /// \return \b NULL: tag does not exist
+ /// \return \b CIF_NODATA_DOT_FIELD the field contains
+ /// \"data not given\" value
+ /// \return \b CIF_NODATA_QUESTION_FIELD the field contains
+ /// \"data not available\" value
+ /// \return \b not \b NULL: string value of the field
+ pstr GetField ( int tagNo ); // 0..nTags-1
+
+ /// \brief Fetches value, corresponding to the given tag, as
+ /// a string
+ /// \param[out] S pointer to string, which will point to newly
+ /// allocated character string, containing value
+ /// associated with tag \b TName. If tag or value
+ /// is not found, or if value corresponds to
+ /// mmCIF's \"data not given\" or
+ /// \"data not available\", \b S returns NULL.
+ /// \param[in] TName character string with tag name
+ /// \param[in] Remove flag to remove the tag and its value from
+ /// structure after it is read.
+ /// \return \b CIFRC_NoTag: tag is not found
+ /// \return \b CIFRC_NoField: value is not found
+ /// \return \b CIFRC_Ok: success. If \b S returns NULL, then
+ /// the value corresponds to either
+ /// \"data not available\" or
+ /// \"data not given\".
+ /// \remarks If \b S!=NULL at time of call, the function will
+ /// try to dispose the string it points on. This allows a slick
+ /// re-use of the same pointer in consequitive calls. This also
+ /// means that one should never pass unallocated pointer to
+ /// this function. Safe use assumes the following patern:
+ /// \code
+ /// mmcif::Struct mmCIFStruct;
+ /// pstr S; // this is merely "char *S"
+ /// int rc;
+ ///
+ /// S = NULL; // null pointer before first use
+ /// rc = mmCIFStruct.GetString ( S,"id" );
+ /// if (rc) CreateCopy ( S,"*** data not found" );
+ /// if (!S) CreateCopy ( S,"*** data not given or not available" );
+ /// printf ( " rc=%i, S='%s'\n",rc,S );
+ ///
+ /// rc = mmCIFStruct.GetString ( S,"property" );
+ /// if (rc) CreateCopy ( S,"*** data not found" );
+ /// if (!S) CreateCopy ( S,"*** data not given or not available" );
+ /// printf ( " rc=%i, S='%s'\n",rc,S );
+ ///
+ /// // etc etc etc
+ ///
+ /// delete[] S; // application is responsible for final
+ /// // disposal of memory
+ /// \endcode
+ int GetString ( pstr & S, cpstr TName, bool Remove=false );
+
+ /// \brief Returns pointer to value associated with given tag.
+ /// \param[in] TName character string with tag name
+ /// \param[out] RC return code:
+ /// \arg \b CIFRC_NoTag: tag is not found
+ /// \arg \b CIFRC_NoField: value is not found
+ /// \arg \b CIFRC_Ok: success. If function returns NULL, then
+ /// the value corresponds to either
+ /// \"data not available\" or
+ /// \"data not given\".
+ /// \return \b NULL: either tag or value is not found, or the
+ /// value is \"data not available\" or \"data not given\".
+ /// Read return code \b RC in order to interpret NULL return.
+ /// \return \b not \b NULL: pointer (\c char \c *) to value
+ /// associated with \b TName.
+ /// \remarks Never try to dispose memory pointed by the return
+ /// value, or your program will crash.
+ pstr GetString ( cpstr TName, int & RC ); // NULL if TName
+ // is not there
+
+ /// \brief Deletes field associated with given tag.
+ /// \param[in] TName character string with tag name
+ /// \return \b >=0: field deleted
+ /// \return \b <0: either field or tag is not found
+ int DeleteField ( cpstr TName ); // <0 the field was not there
+
+ /// \brief Fetches value, corresponding to the given tag, as
+ /// a real number.
+ /// \param[out] R reference to real number to accept the value.
+ /// In case of failure, \b R returns zero.
+ /// \param[in] TName character string with tag name
+ /// \param[in] Remove flag to remove the tag and its value from
+ /// structure after it is read.
+ /// \return \b CIFRC_NoTag: tag is not found
+ /// \return \b CIFRC_NoField: field is not found
+ /// \return \b CIFRC_WrongFormat: value is not a real or integer
+ /// number.
+ /// \return \b CIFRC_NoData: value is either
+ /// \"data not available\" or
+ /// \"data not given\".
+ /// \return \b CIFRC_Ok: success.
+ int GetReal ( realtype & R, cpstr TName, bool Remove=false );
+
+ /// \brief Fetches value, corresponding to the given tag, as
+ /// an integer number.
+ /// \param[out] I reference to integer number to accept the
+ /// value. In case of failure, \b I returns zero, except
+ /// when value is \"data not available\" or
+ /// \"data not given\", when I returns \c MinInt4.
+ /// \param[in] TName character string with tag name
+ /// \param[in] Remove flag to remove the tag and its value from
+ /// structure after it is read.
+ /// \return \arg \b CIFRC_NoTag: tag is not found
+ /// \return \b CIFRC_NoField: field is not found
+ /// \return \b CIFRC_WrongFormat: value is not an integer number.
+ /// \return \b CIFRC_NoData: value is either
+ /// \"data not available\" or
+ /// \"data not given\".
+ /// \return \b CIFRC_Ok: success.
+ int GetInteger ( int & I, cpstr TName, bool Remove=false );
+
+ /// \brief Sets string value for given tag.
+ /// \param[in] S character string with value to be set.
+ /// If \b S==NULL, the \"data not given\" value
+ /// will be set. If \b S==\"\" (empty string), the
+ /// \"data not available\" value is stored.
+ /// \param[in] TName character string with tag name. If tag
+ /// is not found, it will be added to the structure.
+ /// \param[in] NonBlankOnly flag to treat white-space-only
+ /// strings:
+ /// \arg \b false: set as is
+ /// \arg \b true: set \"data not available\" value instead.
+ void PutString ( cpstr S, cpstr TName,
+ bool NonBlankOnly=false );
+
+ /// \brief Sets current date in format YYYY-MM-DD as a value
+ /// for given tag.
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added to the structure.
+ void PutDate ( cpstr T );
+
+ /// \brief Sets \"data not given\" or \"data not available\"
+ /// values for given tag.
+ /// \param[in] NoDataType can be either
+ /// \arg \b CIF_NODATA_DOT for \"data not given\"
+ /// \arg \b CIF_NODATA_QUESTION for \"data not available\"
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added to the structure.
+ void PutNoData ( int NoDataType, cpstr T );
+
+ /// \brief Sets float-point value for given tag.
+ /// \param[in] R real number with value to be set.
+ /// \param[in] TName character string with tag name. If tag
+ /// is not found, it will be added to the structure.
+ /// \param[in] prec float-point precision; g-format with given
+ /// precision will be used
+ void PutReal ( realtype R, cpstr TName, int prec=8 );
+
+ /// \brief Sets float-point value for given tag.
+ /// \param[in] R real number with value to be set.
+ /// \param[in] TName character string with tag name. If tag
+ /// is not found, it will be added to the structure.
+ /// \param[in] format format string to convert \b R.
+ void PutReal ( realtype R, cpstr TName, cpstr format );
+
+ /// \brief Sets integer value for given tag.
+ /// \param[in] I integer number with value to be set.
+ /// \param[in] TName character string with tag name. If tag
+ /// is not found, it will be added to the structure.
+ void PutInteger ( int I, cpstr TName );
+
+ /// \brief Writes structure data in mmCIF format into file.
+ /// \param[in] FName character string with file name.
+ /// \param[in] gzipMode flag to controll compression of files:
+ /// \arg \b GZM_NONE: do not compress
+ /// \arg \b GZM_CHECK: check file name suffix and compress
+ /// (or not) accordingly
+ /// \arg \b GZM_ENFORCE_GZIP: force gzip compression despite
+ /// suffix
+ /// \arg \b GZM_ENFORCE_COMPRESS: force using compress despite
+ /// suffix
+ /// \return \b true: success
+ /// \return \b false: can not open file for writing.
+ /// \remarks This function does not create a valid mmCIF file
+ /// as \"data_XXX\" record will be missing. It may be used for
+ /// debugging though.
+ bool WriteMMCIFStruct ( cpstr FName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+ /// \brief Writes structure into given file.
+ /// \param f reference to MMDB's file class. The file should be
+ /// opened and closed by application.
+ /// \remarks There is a very limited use of this function on
+ /// application level. It is primarily used by mmcif::Data class.
+ void WriteMMCIF ( io::RFile f );
+
+ /// \brief Deep copy of structures.
+ /// Deep copy duplicates all data and memory allocations,
+ /// producing a genuine clone of the original. Only deep copy
+ /// should be used for copying MMDB objects, a mere assignment
+ /// operator will fail you.
+ /// \param[in] Struct a pointer to mmcif::Struct, the content of
+ /// which is copied into 'this' structure.
+ void Copy ( PCategory Struct );
+
+ /// \brief MMDB stream writer.
+ void write ( io::RFile f );
+
+ /// \brief MMDB stream reader.
+ void read ( io::RFile f );
+
+ protected:
+ psvector field;
+
+ void InitStruct();
+ void FreeMemory();
+
+ };
+
+
+
+ // ====================== Loop ==============================
+
+ DefineClass(Loop);
+ DefineStreamFunctions(Loop);
+
+ /// \brief mmcif::Loop represents mmCIF's \"loop\" category, which keeps
+ /// rows of data values associated with tags.
+ /*!
+ mmCIF's \"loop\" category has the following form:
+ \code
+ loop_
+ _loop_name.tag0 value0
+ _loop_name.tag1 value1
+ ...........
+ _loop_name.tagN valueN
+ value00 value10 ... valueN0
+ value01 value11 ... valueN1
+ ...........
+ value0M value1M ... valueNM
+ \endcode
+ mmcif::Loop represents this construct by keeping category name
+ (\"_loop_name\") and associated lists of tags
+ (\"tag0,tag1...tagN\") and data vectors
+ (\"[value00...value0M],[value10...value1M]...[valueN0...valueNM]\").
+
+ The loop object is created automatically when an mmCIF file is read,
+ or it may be created programatically and then pushed into file.
+
+ Access to data is provided via tags and data indexes. Internally,
+ all values are kept as character fields, and it is only on the
+ retrieval stage that they are converted to other data types
+ (integers, floats or strings). If conversion is not possible, an
+ error code is returned by the corresponding functions, which should
+ be checked by the application.
+
+ The following code gives an example of creating mmCIF loop category
+ and populating it with data:
+ \code
+ mmcif::Loop loop;
+ char S[100];
+ int i;
+
+ // Specify loop name:
+ loop.SetCategoryName ( "_sample_loop" );
+
+ // Create loop structure, i.e., list of tags first:
+ loop.AddLoopTag ( "id" );
+ loop.AddLoopTag ( "name" );
+ loop.AddLoopTag ( "value" );
+
+ // Now populate it with data. This my be done in 2 ways.
+ // Here is how you write loop data in stream fashion,
+ // value-after-value:
+ for (i=0;i<3;i++) {
+ loop.AddInteger ( i );
+ sprintf ( S,"1st_way-%i",i );
+ loop.AddString ( S );
+ loop.AddReal ( 2.5*(i+1) );
+ }
+
+ // Here is how you populate loop data using direct-access
+ // functions:
+ for (i=3;i<6;i++) {
+ loop.PutReal ( 2.5*(i+1),"value",i );
+ loop.PutInteger ( i,"id" );
+ sprintf ( S,"2nd way: %i",i );
+ loop.PutString ( S,"name" );
+ }
+
+ loop.WriteMMCIFLoop ( "sample_loop.cif" );
+
+ \endcode
+
+ The resulting file \b sample_loop.cif will contain:
+
+ \code
+
+ loop_
+ _sample_loop.id
+ _sample_loop.name
+ _sample_loop.value
+ 0 1st_way-0 2.5
+ 1 1st_way-1 5.0
+ 2 1st_way-2 7.5
+ 3 "2nd way: 3" 10.0
+ 4 "2nd way: 4" 12.5
+ 5 "2nd way: 5" 15.0
+
+ \endcode
+
+ See general principles of working with mmCIF files and mmCIF
+ hierarchies, as well as some code samples, in Section
+ \"\ref mmcif_handler\".
+ */
+
+ class Loop : public Category {
+
+ friend class Data;
+
+ public :
+
+ /// \brief Basic constructor
+ Loop ();
+
+ /// \brief Constructor that assigns structure name.
+ /// \param[in] N structure name (must start with underscore).
+ Loop ( cpstr N );
+
+ /// \brief Constructor for MMDB data streaming functions
+ Loop ( io::RPStream Object );
+
+ /// \brief Destructor
+ ~Loop();
+
+ /// \brief Adds tag to the loop.
+ /// The tag is appended to the list of existing tags. The order
+ /// of tags cannot be changed.
+ /// \param[in] T tag name
+ /// \param[in] Remove flag to remove all fields in the loop.
+ void AddLoopTag ( cpstr T, bool Remove=true );
+
+ /// \brief Sets string value at current loop position.
+ /// When \b mmcif::Loop::Add[Data] functions use internal loop
+ /// pointer. When category is created or cleared (by using
+ /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+ /// 0th row and 0th column (tag). After each call to
+ /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+ /// to next column (tag), and wraps over to next row, 0th tag,
+ /// if list of tags is exhausted. Any remaining fields in last
+ /// row will be populated with \"data not given\" value.
+ /// \param[in] S character string with value to be set.
+ /// If \b S==NULL, the \"data not given\" value
+ /// will be set. If \b S==\"\" (empty string), the
+ /// \"data not available\" value is stored.
+ /// \param[in] NonBlankOnly flag to treat white-space-only
+ /// strings:
+ /// \arg \b false: set as is
+ /// \arg \b true: set \"data not available\" value instead.
+ void AddString ( cpstr S, bool NonBlankOnly=false );
+
+ /// \brief Sets \"data not given\" or \"data not available\" at
+ /// current loop position.
+ /// When \b mmcif::Loop::Add[Data] functions use internal loop
+ /// pointer. When category is created or cleared (by using
+ /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+ /// 0th row and 0th column (tag). After each call to
+ /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+ /// to next column (tag), and wraps over to next row, 0th tag,
+ /// if list of tags is exhausted. Any remaining fields in last
+ /// row will be populated with \"data not given\" value.
+ /// \param[in] NoDataType integer key specifying which type of
+ /// data absence should be set as a value:
+ /// \arg \b CIF_NODATA_DOT for \"data not given\"
+ /// \arg \b CIF_NODATA_QUESTION for \"data not available\"
+ void AddNoData ( int NoDataType );
+
+ /// \brief Sets float-point value at current loop position.
+ /// When \b mmcif::Loop::Add[Data] functions use internal loop
+ /// pointer. When category is created or cleared (by using
+ /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+ /// 0th row and 0th column (tag). After each call to
+ /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+ /// to next column (tag), and wraps over to next row, 0th tag,
+ /// if list of tags is exhausted. Any remaining fields in last
+ /// row will be populated with \"data not given\" value.
+ /// \param[in] R real number with value to be set.
+ /// \param[in] prec float-point precision; g-format with given
+ /// precision will be used
+ void AddReal ( realtype R, int prec=8 );
+
+ /// \brief Sets float-point value at current loop position in
+ /// given format.
+ /// When \b mmcif::Loop::Add[Data] functions use internal loop
+ /// pointer. When category is created or cleared (by using
+ /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+ /// 0th row and 0th column (tag). After each call to
+ /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+ /// to next column (tag), and wraps over to next row, 0th tag,
+ /// if list of tags is exhausted. Any remaining fields in last
+ /// row will be populated with \"data not given\" value.
+ /// \brief Sets float-point value for given tag.
+ /// \param[in] R real number with value to be set.
+ /// \param[in] format format string to convert \b R.
+ void AddReal ( realtype R, cpstr format );
+
+ /// \brief Sets integer value at current loop position in given
+ /// format.
+ /// When \b mmcif::Loop::Add[Data] functions use internal loop
+ /// pointer. When category is created or cleared (by using
+ /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+ /// 0th row and 0th column (tag). After each call to
+ /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+ /// to next column (tag), and wraps over to next row, 0th tag,
+ /// if list of tags is exhausted. Any remaining fields in last
+ /// row will be populated with \"data not given\" value.
+ /// \param[in] I integer number with value to be set.
+ void AddInteger ( int I );
+
+ /// \brief Returns current length of the loop (i.e. the number
+ /// of rows).
+ /// \return number of data rows in the loop.
+ int GetLoopLength() { return nRows; }
+
+ /// \brief Returns string pointer on the field corresponding to
+ /// tag in the specified position, in the specified row.
+ /// Tag positions are defined by the order of their appearance in
+ /// mmCIF file (if loop was read from a file), or by the
+ /// order of their addition to the loop (if loop was
+ /// created programmatically).
+ /// \param[in] rowNo row number (0...GetLoopLength()-1)
+ /// \param[in] tagNo tag number (0...GetNofTags()-1)
+ /// \return \b NULL: tag or row do not exist
+ /// \return \b CIF_NODATA_DOT_FIELD the field contains
+ /// \"data not given\" value
+ /// \return \b CIF_NODATA_QUESTION_FIELD the field contains
+ /// \"data not available\" value
+ /// \return \b not \b NULL: string value of the field
+ /// \remarks Never try to dispose memory pointed by the return
+ /// value, or your program will crash.
+ pstr GetField ( int rowNo, int tagNo );
+
+ /// \brief Fetches value, corresponding to the given tag, in
+ /// the given row, as a string
+ /// \param[out] S pointer to string, which will point to newly
+ /// allocated character string, containing value
+ /// associated with tag \b TName and row \b nrow.
+ /// If tag, row or value
+ /// is not found, or if value corresponds to
+ /// mmCIF's \"data not given\" or
+ /// \"data not available\", \b S returns NULL.
+ /// \param[in] TName character string with tag name
+ /// \param[in] nrow row number (0...GetLoopLength()-1)
+ /// \param[in] Remove flag to remove the field from
+ /// structure after it is read.
+ /// \return \b CIFRC_NoTag: tag is not found
+ /// \return \b CIFRC_WrongIndex: row is not found
+ /// \return \b CIFRC_NoField: value is not found
+ /// \return \b CIFRC_Ok: success. If \b S returns NULL, then
+ /// the value corresponds to either
+ /// \"data not available\" or
+ /// \"data not given\".
+ /// \remarks If \b S!=NULL at time of call, the function will
+ /// try to dispose the string it points on. This allows a slick
+ /// re-use of the same pointer in consequitive calls. This also
+ /// means that one should never pass unallocated pointer to
+ /// this function. Safe use assumes the following patern:
+ /// \code
+ /// mmcif::Loop mmCIFLoop;
+ /// pstr S; // this is merely "char *S"
+ /// int rc;
+ ///
+ /// S = NULL; // null pointer before first use
+ /// rc = mmCIFLoop.GetString ( S,"id",1 );
+ /// if (rc) CreateCopy ( S,"*** data not found" );
+ /// if (!S) CreateCopy ( S,"*** data not given or not available" );
+ /// printf ( " rc=%i, S='%s'\n",rc,S );
+ ///
+ /// rc = mmCIFLoop.GetString ( S,"property",0 );
+ /// if (rc) CreateCopy ( S,"*** data not found" );
+ /// if (!S) CreateCopy ( S,"*** data not given or not available" );
+ /// printf ( " rc=%i, S='%s'\n",rc,S );
+ ///
+ /// // etc etc etc
+ ///
+ /// delete[] S; // application is responsible for final
+ /// // disposal of memory
+ /// \endcode
+ int GetString ( pstr & S, cpstr TName, int nrow,
+ bool Remove=false );
+
+ /// \brief Returns pointer to value associated with given tag,
+ /// in the given row of the loop.
+ /// \param[in] TName character string with tag name
+ /// \param[in] nrow row number (0...GetLoopLength()-1)
+ /// \param[out] RC return code:
+ /// \arg \b CIFRC_NoTag: tag is not found
+ /// \arg \b CIFRC_WrongIndex: row is not found
+ /// \arg \b CIFRC_NoField: value is not found
+ /// \arg \b CIFRC_Ok: success. If function returns NULL, then
+ /// the value corresponds to either
+ /// \"data not available\" or
+ /// \"data not given\".
+ /// \return \b NULL: either tag, row or value is not found, or the
+ /// value is \"data not available\" or \"data not given\".
+ /// Read return code \b RC in order to interpret NULL return.
+ /// \return \b not \b NULL: pointer (\c char \c *) to value
+ /// associated with \b TName.
+ /// \remarks Never try to dispose memory pointed by the return
+ /// value, or your program will crash.
+ pstr GetString ( cpstr TName, int nrow, int & RC );
+
+ /// \brief Copies value, associated with given tag,
+ /// in the given row, into specified buffer.
+ /// Terminating NULL character is appended.
+ /// \param[out] buf character string to accept the value
+ /// \param[in] maxlength maximum number of bytes to copy
+ /// \param[in] TName character string with tag name
+ /// \param[in] nrow row number (0...GetLoopLength()-1)
+ /// \param[out] RC return code:
+ /// \arg \b CIFRC_NoTag: tag is not found
+ /// \arg \b CIFRC_WrongIndex: row is not found
+ /// \arg \b CIFRC_NoField: value is not found
+ /// \arg \b CIFRC_Ok: success.
+ /// \remarks Destination string \b buf is not modified if
+ /// \b RC!=CIFRC_Ok .
+ void CopyString ( pstr buf, int maxlength,
+ cpstr TName, int nrow, int & RC );
+
+ /// \brief Deletes field associated with given tag in
+ /// the given row.
+ /// \param[in] TName character string with tag name
+ /// \param[in] nrow row number (0...GetLoopLength()-1)
+ /// \return \b >=0: field deleted
+ /// \return \b <0: either field or tag is not found
+ int DeleteField ( cpstr TName, int nrow );
+
+ /// \brief Deletes all fields in given row.
+ /// \param[in] nrow row number (0...GetLoopLength()-1)
+ /// \return \b CIFRC_Ok: fields deleted
+ /// \return \b CIFRC_WrongIndex: row not found
+ /// \remarks Note that this function delets just the fields, but
+ /// not the row. If you wish the row to be deleted, call
+ /// mmcif::Loop::Optimize() function after this one.
+ int DeleteRow ( int nrow );
+
+ /// \brief Fetches value, corresponding to the given tag,
+ /// in the given row, as a real number.
+ /// \param[out] R reference to real number to accept the value.
+ /// In case of failure, \b R returns zero.
+ /// \param[in] TName character string with tag name
+ /// \param[in] nrow row number (0...GetLoopLength()-1)
+ /// \param[in] Remove flag to remove the field from
+ /// the loop after it is read.
+ /// \return \b CIFRC_NoTag: tag is not found
+ /// \return \b CIFRC_WrongIndex: row not found
+ /// \return \b CIFRC_NoField: field is not found
+ /// \return \b CIFRC_WrongFormat: value is not a real or integer
+ /// number.
+ /// \return \b CIFRC_NoData: value is either
+ /// \"data not available\" or
+ /// \"data not given\".
+ /// \return \b CIFRC_Ok: success.
+ int GetReal ( realtype & R, cpstr TName, int nrow,
+ bool Remove=false );
+
+ /// \brief Copies value, associated with given tag,
+ /// in the given row, into specified destination as
+ /// a real number.
+ /// \param[out] R reference to real number to accept the value
+ /// \param[in] TName character string with tag name
+ /// \param[in] nrow row number (0...GetLoopLength()-1)
+ /// \param[out] RC return code:
+ /// \arg \b CIFRC_NoTag: tag is not found
+ /// \arg \b CIFRC_WrongIndex: row is not found
+ /// \arg \b CIFRC_NoField: value is not found
+ /// \arg \b CIFRC_Ok: success.
+ /// \remarks Destination \b R is set 0 if \b RC!=CIFRC_Ok.
+ void CopyReal ( realtype & R, cpstr TName, int nrow, int & RC );
+
+ /// \brief Copies value, associated with given tag,
+ /// in the given row, into specified destination as
+ /// an integer number.
+ /// \param[out] I reference to integer number to accept the value
+ /// \param[in] TName character string with tag name
+ /// \param[in] nrow row number (0...GetLoopLength()-1)
+ /// \param[out] RC return code:
+ /// \arg \b CIFRC_NoTag: tag is not found
+ /// \arg \b CIFRC_WrongIndex: row is not found
+ /// \arg \b CIFRC_NoField: value is not found
+ /// \arg \b CIFRC_Ok: success.
+ /// \remarks Destination \b I is set 0 if \b RC!=CIFRC_Ok.
+ void CopyInteger ( int & I, cpstr TName, int nrow, int & RC );
+
+ /// \brief Fetches value, corresponding to the given tag,
+ /// in the given row, as an integer number.
+ /// \param[out] I reference to integer number to accept the value.
+ /// In case of failure, \b R returns zero.
+ /// \param[in] TName character string with tag name
+ /// \param[in] nrow row number (0...GetLoopLength()-1)
+ /// \param[in] Remove flag to remove the field from
+ /// the loop after it is read.
+ /// \return \b CIFRC_NoTag: tag is not found
+ /// \return \b CIFRC_WrongIndex: row not found
+ /// \return \b CIFRC_NoField: field is not found
+ /// \return \b CIFRC_WrongFormat: value is not a real or integer
+ /// number.
+ /// \return \b CIFRC_NoData: value is either
+ /// \"data not available\" or
+ /// \"data not given\".
+ /// \return \b CIFRC_Ok: success.
+ int GetInteger ( int & I, cpstr TName, int nrow,
+ bool Remove=false );
+
+ /// \brief Fetches set of values, corresponding to the given
+ /// tag, in the given range of rows, as a vector of
+ /// strings.
+ /// \param[out] S reference to string vector to accept
+ /// the values. if \b S==NULL , the vector will be
+ /// allocated with starting index of \b i1.
+ /// \param[in] TName character string with tag name
+ /// \param[in] i1 minimum row number to fetch, the actual
+ /// index will be calculated as \b max(0,min(i1,i2))
+ /// \param[in] i2 maximum row number to fetch, the actual
+ /// index will be calculated as
+ /// \b min(GetLoopLength()-1,max(i1,i2))
+ /// \param[in] Remove flag to remove fetched fields from
+ /// the loop after they are read.
+ /// \return \b CIFRC_NoTag: tag is not found
+ /// \return \b CIFRC_WrongIndex: invalid range of rows
+ /// \return \b CIFRC_Ok: success.
+ ///
+ /// For safe use, \b S should be pre-allocated by calling
+ /// process. Only elements \b S[i1] to \b S[i2] will contain
+ /// fetched data, others remain untouched. The calling
+ /// process is responsible for the disposal of \b S. Example:
+ /// \code
+ /// mmcif::Loop loop;
+ /// psvector S; // equivalent to char **S
+ /// int i,i1,i2,rc,n;
+ ///
+ /// // ... get loop data
+ ///
+ /// n = loop.GetLoopLength();
+ /// i1 = 5; i2 = n - 5; // could be wrong!
+ ///
+ /// // allocate vector of strings
+ /// GetVectorMemory ( S,n,0 ); // "0" for starting index
+ /// for (i=0;i<n;i++)
+ /// S[i] = NULL; // initialize NULL string pointers
+ ///
+ /// loop.GetSVector ( S,"name",i1,i2 );
+ /// printf ( " Fetched with return code rc=%i\n",rc );
+ /// // you may want a more thorough treatment of
+ /// // the return code here
+ /// for (i=i1;i<=i2;i++)
+ /// if (S[i]) printf ( " %4i. name='%s'\n",i,S[i] );
+ /// else printf ( " %4i. name is not available\n",i );
+ ///
+ /// // S[] may be re-used for as many fetches as necessary
+ /// // without cleaning or disposals
+ ///
+ /// // dispose of vector of strings
+ /// for (i=0;i<n;i++)
+ /// if (S[i]) delete[] S[i];
+ /// FreeVectorMemory ( S,0 ); // "0" for starting index
+ ///
+ /// \endcode
+ int GetSVector ( psvector & S, cpstr TName,
+ int i1=0, int i2=MaxInt4,
+ bool Remove=false );
+
+ /// \brief Fetches set of values, corresponding to the given
+ /// tag, in the given range of rows, as a vector of
+ /// float-point numbers.
+ /// \param[out] R reference to float-point vector to accept
+ /// the values. if \b R==NULL , the vector will be
+ /// allocated with starting index of \b i1.
+ /// \param[in] TName character string with tag name
+ /// \param[in] i1 minimum row number to fetch, the actual
+ /// index will be calculated as \b max(0,min(i1,i2))
+ /// \param[in] i2 maximum row number to fetch, the actual
+ /// index will be calculated as
+ /// \b min(GetLoopLength()-1,max(i1,i2))
+ /// \param[in] Remove flag to remove fetched fields from
+ /// the loop after they are read.
+ /// \return \b CIFRC_NoTag: tag is not found
+ /// \return \b CIFRC_WrongIndex: invalid range of rows
+ /// \return \b CIFRC_Ok: success.
+ ///
+ /// For safe use, \b R should be pre-allocated by calling
+ /// process. Only elements \b R[i1] to \b R[i2] will contain
+ /// fetched data, others remain untouched. The calling
+ /// process is responsible for the disposal of \b R. Example:
+ /// \code
+ /// mmcif::Loop loop;
+ /// rvector R; // equivalent to realtype *R
+ /// int i,i1,i2,rc,n;
+ ///
+ /// // ... get loop data
+ ///
+ /// n = loop.GetLoopLength();
+ /// i1 = 5; i2 = n - 5; // could be wrong!
+ ///
+ /// // allocate a vector of real numbers
+ /// GetVectorMemory ( R,n,0 ); // "0" for starting index
+ /// // no need to initiaize unless required for the
+ /// // application
+ ///
+ /// rc = loop.GetRVector ( R,"value",i1,i2 );
+ /// printf ( " Fetched with return code rc=%i\n",rc );
+ /// // you may want a more thorough treatment of
+ /// // the return code here
+ /// for (i=i1;i<=i2;i++)
+ /// printf ( " value[%4i] = %15.7g\n",i,R[i] );
+ ///
+ /// // R[] may be re-used for as many fetches as necessary
+ /// // without cleaning or disposals
+ ///
+ /// // dispose of the vector
+ /// FreeVectorMemory ( R,0 ); // "0" for starting index
+ ///
+ /// \endcode
+ int GetRVector ( rvector & R, cpstr TName,
+ int i1=0, int i2=MaxInt4,
+ bool Remove=false );
+
+ /// \brief Fetches set of values, corresponding to the given
+ /// tag, in the given range of rows, as a vector of
+ /// integer numbers.
+ /// \param[out] I reference to float-point vector to accept
+ /// the values. if \b I==NULL , the vector will be
+ /// allocated with starting index of \b i1.
+ /// \param[in] TName character string with tag name
+ /// \param[in] i1 minimum row number to fetch, the actual
+ /// index will be calculated as \b max(0,min(i1,i2))
+ /// \param[in] i2 maximum row number to fetch, the actual
+ /// index will be calculated as
+ /// \b min(GetLoopLength()-1,max(i1,i2))
+ /// \param[in] Remove flag to remove fetched fields from
+ /// the loop after they are read.
+ /// \return \b CIFRC_NoTag: tag is not found
+ /// \return \b CIFRC_WrongIndex: invalid range of rows
+ /// \return \b CIFRC_Ok: success.
+ ///
+ /// For safe use, \b I should be pre-allocated by calling
+ /// process. Only elements \b I[i1] to \b I[i2] will contain
+ /// fetched data, others remain untouched. The calling
+ /// process is responsible for the disposal of \b I.
+ /// See example in mmcif::Loop::GetRVector documentation
+ /// for details.
+ int GetIVector ( ivector & I, cpstr TName,
+ int i1=0, int i2=MaxInt4,
+ bool Remove=false );
+
+ /// \brief Sets string value for given tag and row.
+ /// \param[in] S character string with value to be set.
+ /// If \b S==NULL, the \"data not given\" value
+ /// will be set. If \b S==\"\" (empty string), the
+ /// \"data not available\" value is stored.
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added, and all data in
+ /// the loop will be reindexed accordingly.
+ /// \param[in] nrow row number. If the row does not exist then
+ /// it will be created, along with all other rows
+ /// between GetLoopLength()-1 and \b nrow as
+ /// necessary. All newly created fields will be
+ /// initialised with \"data not given\" value.
+ void PutString ( cpstr S, cpstr T, int nrow );
+
+ /// \brief Sets \"data not given\" or \"data not available\"
+ /// values for given tag and row.
+ /// \param[in] NoDataType can be either
+ /// \arg \b CIF_NODATA_DOT for \"data not given\"
+ /// \arg \b CIF_NODATA_QUESTION for \"data not available\"
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added, and all data in
+ /// the loop will be reindexed accordingly.
+ /// \param[in] nrow row number. If the row does not exist then
+ /// it will be created, along with all other rows
+ /// between GetLoopLength()-1 and \b nrow as
+ /// necessary. All newly created fields will be
+ /// initialised with \"data not given\" value.
+ void PutNoData ( int NoDataType, cpstr T, int nrow );
+
+ /// \brief Sets float-point value for given tag and row.
+ /// \param[in] R real number with value to be set.
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added, and all data in
+ /// the loop will be reindexed accordingly.
+ /// \param[in] nrow row number. If the row does not exist then
+ /// it will be created, along with all other rows
+ /// between GetLoopLength()-1 and \b nrow as
+ /// necessary. All newly created fields will be
+ /// initialised with \"data not given\" value.
+ /// \param[in] prec float-point precision; g-format with given
+ /// precision will be used
+ void PutReal ( realtype R, cpstr T, int nrow, int prec=8 );
+
+ /// \brief Sets float-point value for given tag and row.
+ /// \param[in] R real number with value to be set.
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added, and all data in
+ /// the loop will be reindexed accordingly.
+ /// \param[in] nrow row number. If the row does not exist then
+ /// it will be created, along with all other rows
+ /// between GetLoopLength()-1 and \b nrow as
+ /// necessary. All newly created fields will be
+ /// initialised with \"data not given\" value.
+ /// \param[in] format format string to convert \b R.
+ void PutReal ( realtype R, cpstr T, int nrow, cpstr format );
+
+ /// \brief Sets integer value for given tag.
+ /// \param[in] I integer number with value to be set.
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added, and all data in
+ /// the loop will be reindexed accordingly.
+ /// \param[in] nrow row number. If the row does not exist then
+ /// it will be created, along with all other rows
+ /// between GetLoopLength()-1 and \b nrow as
+ /// necessary. All newly created fields will be
+ /// initialised with \"data not given\" value.
+ void PutInteger ( int I, cpstr T, int nrow );
+
+ /// \brief Sets a set of string values for the given tag and
+ /// range of rows.
+ /// \param[in] S string vector with values to store in the loop
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added, and all data in
+ /// the loop will be reindexed accordingly.
+ /// \param[in] i1 minimum data index in \b S to set in the loop
+ /// \param[in] i2 maximum data index in \b S to set in the loop.
+ ///
+ /// The data will be set in rows \b i1 to \b i2 (inclusive) in
+ /// the loop. If range \b [i1,i2] is not contained in the loop,
+ /// all missing rows will be created and initialised to
+ /// \"data not given\" value. Example:
+ /// \code
+ /// mmcif::Loop loop("_sample_loop");
+ /// pstr S[100];
+ /// int i;
+ ///
+ /// // initialize vector of strings
+ /// for (i=0;i<100;i++) {
+ /// S[i] = new char[20];
+ /// sprintf ( S[i],"value i=%i",i );
+ /// }
+ ///
+ /// // put data in loop
+ /// loop.PutSVector ( S,"made_up_string_value",0,99 );
+ ///
+ /// // dispose of vector of strings
+ /// for (i=0;i<100;i++)
+ /// if (S[i]) delete[] S[i];
+ ///
+ /// \endcode
+ void PutSVector ( psvector S, cpstr T, int i1, int i2 );
+
+ /// \brief Sets a set of float-point values for the given tag and
+ /// range of rows.
+ /// \param[in] R vector of real numbers to store in the loop
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added, and all data in
+ /// the loop will be reindexed accordingly.
+ /// \param[in] i1 minimum data index in \b S to set in the loop
+ /// \param[in] i2 maximum data index in \b S to set in the loop
+ /// \param[in] prec float-point precision; g-format with given
+ /// precision will be used.
+ ///
+ /// The data will be set in rows \b i1 to \b i2 (inclusive) in
+ /// the loop. If range \b [i1,i2] is not contained in the loop,
+ /// all missing rows will be created and initialised to
+ /// \"data not given\" value.
+ void PutRVector ( rvector R, cpstr T, int i1, int i2,
+ int prec=8 );
+
+ /// \brief Sets a set of integer values for the given tag and
+ /// range of rows.
+ /// \param[in] I vector of integers to store in the loop
+ /// \param[in] T character string with tag name. If tag
+ /// is not found, it will be added, and all data in
+ /// the loop will be reindexed accordingly.
+ /// \param[in] i1 minimum data index in \b S to set in the loop
+ /// \param[in] i2 maximum data index in \b S to set in the loop.
+ ///
+ /// The data will be set in rows \b i1 to \b i2 (inclusive) in
+ /// the loop. If range \b [i1,i2] is not contained in the loop,
+ /// all missing rows will be created and initialised to
+ /// \"data not given\" value.
+ void PutIVector ( ivector I, cpstr T, int i1, int i2 );
+
+ /// \brief Returns category type \b MMCIF_Loop.
+ MMCIF_ITEM GetCategoryID() { return MMCIF_Loop; }
+
+ /// \brief Optimizes loop for RAM and data access speed.
+ /// Optimized data structures take less RAM and their indexes
+ /// are sorted for quicker access. Sorting is done automatically
+ /// as new data is added to the category. If the structure
+ /// is edited (fields/data removed), it may need
+ /// optimization and re-sorting for efficiency.\n\n
+ /// The sorting preserves the order of actual appearance of
+ /// tags and rows in mmCIF file. If a loop is created
+ /// programmatically, the order of tags and rows in mmCIF file
+ /// will be the same as order of adding them to the loop.
+ void Optimize();
+
+ /// \brief Writes loop data in mmCIF format into file.
+ /// \param[in] FName character string with file name.
+ /// \param[in] gzipMode flag to controll compression of files:
+ /// \arg \b GZM_NONE: do not compress
+ /// \arg \b GZM_CHECK: check file name suffix and compress
+ /// (or not) accordingly
+ /// \arg \b GZM_ENFORCE_GZIP: force gzip compression despite
+ /// suffix
+ /// \arg \b GZM_ENFORCE_COMPRESS: force using compress despite
+ /// suffix
+ /// \return \b true: success
+ /// \return \b false: can not open file for writing.
+ /// \remarks This function does not create a valid mmCIF file
+ /// as \"data_XXX\" record will be missing. It may be used for
+ /// debugging though.
+ bool WriteMMCIFLoop ( cpstr FName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+ /// \brief Writes loop data into given file.
+ /// \param f reference to MMDB's file class. The file should be
+ /// opened and closed by application.
+ /// \remarks There is a very limited use of this function on
+ /// application level. It is primarily used by mmcif::Data class.
+ void WriteMMCIF ( io::RFile f );
+
+ /// \brief Deep copy of loops.
+ /// Deep copy duplicates all data and memory allocations,
+ /// producing a genuine clone of the original. Only deep copy
+ /// should be used for copying MMDB objects, a mere assignment
+ /// operator will fail you.
+ /// \param[in] Loop a pointer to mmcif::Loop, the content of
+ /// which is copied into 'this' loop.
+ void Copy ( PCategory Loop );
+
+ /// \brief MMDB stream writer.
+ void write ( io::RFile f );
+
+ /// \brief MMDB stream reader.
+ void read ( io::RFile f );
+
+ protected:
+ int nRows;
+ psmatrix field;
+ int iColumn,nAllocRows;
+
+ void InitLoop ();
+ void FreeMemory ();
+ void DeleteFields ();
+ void ExpandRows ( int nRowsNew );
+
+ };
+
+
+
+ // ====================== Data =============================
+
+
+ // CIFW are warnings which may be issued on reading the CIF file.
+ // Each of them means actually a CIF syntax error.
+
+ enum CIF_WARNING {
+ CIFW_UnrecognizedItems = 0x00000020,
+ CIFW_MissingField = 0x00000040,
+ CIFW_EmptyLoop = 0x00000080,
+ CIFW_UnexpectedEOF = 0x00000100,
+ CIFW_LoopFieldMissing = 0x00000200,
+ CIFW_NotAStructure = 0x00000400,
+ CIFW_NotALoop = 0x00000800,
+ CIFW_DuplicateTag = 0x00001000
+ };
+
+ // CIFRC are return codes from procedures of extracting data from
+ // the read CIF file. Negative returns reflect unsuccessful and
+ // not accomplished operation.
+ enum CIF_RC {
+ CIFRC_Loop = 2,
+ CIFRC_Structure = 1,
+ CIFRC_Ok = 0,
+ CIFRC_StructureNoTag = -1,
+ CIFRC_LoopNoTag = -2,
+ CIFRC_NoCategory = -3,
+ CIFRC_WrongFormat = -4,
+ CIFRC_NoTag = -5,
+ CIFRC_NotAStructure = -6,
+ CIFRC_NotALoop = -7,
+ CIFRC_WrongIndex = -8,
+ CIFRC_NoField = -9,
+ CIFRC_Created = -12,
+ CIFRC_CantOpenFile = -13,
+ CIFRC_NoDataLine = -14,
+ CIFRC_NoData = -15
+ };
+
+ //
+ // Functional flags:
+ // ~~~~~~~~~~~~~~~~~
+ //
+ // CIFFL_PrintWarnings when reading CIF file, all warning
+ // messages will be printed. If the flag
+ // is off, the warnings will be bit-encoded
+ // in the return code
+ // CIFFL_StopOnWarnings reading CIF file will stop at first
+ // warning issued
+ // CIFFL_SuggestCategories allows reading CIF file with loops having
+ // no categories. Hidden category names
+ // will be automatically generated for
+ // internal consistency of the system.
+ // These names will not appear in output.
+ // As these names are hidden, they cannot
+ // be used to access data. It is therefore
+ // assumed that all tags in all loops without
+ // categories are unique. Simply specify ""
+ // for category when accessing such data
+ // (it cannot be accessed through mmcif::Loop,
+ // but only through mmcif::Data functions
+ // taking both Category and Tag; note that
+ // CIFFL_SuggestCategories flag must be on
+ // while accessing such data).
+ // CIFFL_SuggestTags allows for identical tags in a category
+ // (including a hidden category). Hidden
+ // suffixes to tag names will be generated
+ // for internal consistency. At present,
+ // only data for first non-unique tag may be
+ // accessed.
+ //
+ enum CIF_FLAG {
+ CIFFL_PrintWarnings = 0x00000001,
+ CIFFL_StopOnWarnings = 0x00000002,
+ CIFFL_SuggestCategories = 0x00000004,
+ CIFFL_SuggestTags = 0x00000008
+ };
+
+ DefineClass(Data);
+ DefineStreamFunctions(Data);
+
+
+ /// \brief mmcif::Data represents mmCIF's \"data\" category, which keeps
+ /// structures and loops and is mandatory element of mmCIF file.
+ /*!
+ mmCIF's \"data\" category has the following form:
+ \code
+ data_DataName
+
+ _structure1.tag1 value1
+ ..........
+
+ loop_
+ ..........
+
+ \endcode
+ In the above example, all structures and loops that follow \b data_
+ keyword until next \b data_ or end of file are part of data category
+ with name \b DataName.
+
+ mmcif::Data represents this construct by keeping a list of mmcif::Struct
+ and mmcif::Loop class instances associated with the corresponding
+ categories in the data block.
+
+ The data object is created automatically when an mmCIF file is read,
+ or it may be created programatically and then pushed into file.
+
+ Access to data is provided via category (structures and loops) names,
+ tags and data indexes (in case of loops). Alternatively, pointers to
+ contained structures and loops may be obtained first, an used for
+ fetching data using mmcif::Struct's and mmcif::Loop's interface
+ functions.
+
+ The following code gives an example of creating mmCIF's data category
+ and populating it:
+ \code
+ mmcif::Data data;
+
+ // Specify data name:
+ data.PutDataName ( "Sample_Data" );
+
+ // the following statement:
+ data.PutInteger ( 12345,"_category1","id" );
+ // creates structure "_category1" with tag "id" and assigns it
+ // the integer value of 12345.
+
+ data.PutString ( "a name","_category1","name" );
+
+ // Loops may be created quite similarly:
+ data.PutLoopInteger ( 12345 ,"_loop1","id" ,2 );
+ data.PutLoopInteger ( "a name","_loop1","name",0 );
+
+ // push data into a file
+ data.WriteMMCIFData ( "sample.cif" );
+
+ \endcode
+
+ The resulting file \b sample.cif will contain:
+
+ \code
+ data_Sample_Data
+
+ _category1.id 12345
+ _category1.name "a name"
+
+ loop_
+ _loop1.id
+ _loop1.name
+ . "a name"
+ . .
+ 12345 .
+ \endcode
+
+ The same result may be achieved differently:
+
+ \code
+ mmcif::Data data;
+ mmcif::PStruct mmCIFStruct; // equivalent to mmcif::Struct *mmCIFStruct
+ mmcif::PLoop mmCIFLoop; // equivalent to mmcif::Loop *mmCIFLoop
+
+ // Specify data name:
+ data.PutDataName ( "Sample_Data" );
+
+ // create new mmCIF's structure in the data block:
+ data.AddStructure ( "_category1",mmCIFStruct );
+ if (mmCIFStruct) {
+ mmCIFStruct->PutInteger ( 12345 ,"id" );
+ mmCIFStruct->PutString ( "a name","name" );
+ }
+
+ // similarly for the loop:
+ data.AddLoop ( "_loop1",mmCIFLoop );
+ if (mmCIFLoop) {
+ mmCIFLoop->PutInteger ( 12345 ,"id" ,2 );
+ mmCIFLoop->PutString ( "a name","name",0 );
+ }
+
+ // push data into a file
+ data.WriteMMCIFData ( "sample.cif" );
+
+ \endcode
+
+ See general principles of working with mmCIF files and mmCIF
+ hierarchies, as well as some code samples, in Section
+ \"\ref mmcif_handler\".
+ */
+
+ class Data : public io::Stream {
+
+ friend class File;
+
+ public :
+
+ /// \brief Basic constructor.
+ Data ();
+
+ /// \brief Constructor that assigns data block name.
+ /// \param[in] N data block name.
+ Data ( cpstr N );
+
+ /// \brief Constructor for MMDB data streaming functions.
+ Data ( io::RPStream Object );
+
+ /// \brief Destructor.
+ ~Data();
+
+
+ // -------- General I/O functions
+
+ /// \brief Sets flag to print warnings on reading mmCIF files.
+ /// \param[in] SPW flag to print warnings:
+ /// \arg \b true : warnings will be printed to stdout
+ /// \arg \b false : warnings will not be printed but returned
+ /// in return code (default)
+ void SetPrintWarnings ( bool SPW );
+
+ /// \brief Sets flag to stop on warning when reading an mmCIF file.
+ /// \param[in] SOW flag to stop on warning:
+ /// \arg \b true : reading will stop on first warning encountered
+ /// \arg \b false : warnings will not stop reading (default)
+ void SetStopOnWarning ( bool SOW );
+
+ /// \brief Sets optional flag(s) for reading mmCIF files.
+ /// By default, no flags are set.
+ /// \param[in] F flag or logical \"or\" of several flags to be set:
+ /// \arg \b CIFFL_PrintWarnings toggles printing warning messages
+ /// at reading an mmCIF file, in stdout. If this
+ /// flag is not set (default), the warnings will
+ /// be returned in the bit-encoded return code
+ /// \arg \b CIFFL_StopOnWarnings if set, reading an mmCIF file
+ /// will stop at first warning issued
+ /// \arg \b CIFFL_SuggestCategories allows for reading of mmCIF
+ /// files with loops and structures having no
+ /// category names (\"dirty CIFs\"). If this flag is
+ /// set, then hidden category names will be
+ /// automatically generated. These names will not
+ /// appear in the output. As these names are hidden,
+ /// they cannot be used to access data. In order to
+ /// access data in such categories, consider whether
+ /// they are structures or loops. In case of a
+ /// unnamed structure, simply specify \"\" (empty
+ /// string) for structure name in all access
+ /// functions ( note that \b CIFFL_SuggestCategories
+ /// flag must be on while accessing such data). In
+ /// case of a loop, first use the mmcif::Data::FindLoop
+ /// function to retrieve pointer on the hidden loop,
+ /// and then use mmcif::Loop's interface function to
+ /// fetch data from the loop.
+ /// \arg \b CIFFL_SuggestTags allows for duplicate tags in a
+ /// category (structure or loop, including hidden
+ /// categories). This may help reading \"dirty CIFs\".
+ /// At present, only data for first non-unique tag
+ /// may be accessed.
+ void SetFlag ( CIF_FLAG F );
+
+ /// \brief Removes optional flag(s) for reading mmCIF files.
+ /// By default, no flags are set.
+ /// \param[in] F flag or logical \"or\" of several flags to be
+ /// removed (unset):
+ /// \arg \b CIFFL_PrintWarnings no wornings will be printed in
+ /// stdout, but rather returned in the bit-encoded
+ /// return code
+ /// \arg \b CIFFL_StopOnWarnings warnings will not stop reading
+ /// \arg \b CIFFL_SuggestCategories loops without names will
+ /// count as errors and stop reading
+ /// \arg \b CIFFL_SuggestTags duplicate tags in structures and
+ /// loops will count as errors and stop reading.
+ ///
+ /// See more detail flag description in mmcif::Data::SetFlag().
+ void RemoveFlag ( CIF_FLAG F );
+
+ /// \brief Returns bit-encoded warnings issued at last file read.
+ /// \return an integer number, which is an or-superposition of
+ /// warning flags:
+ /// \arg \b CIFW_UnrecognizedItems: unrecognized items were found
+ /// \arg \b CIFW_MissingField: expected data field not found
+ /// \arg \b CIFW_EmptyLoop: loop category was defined but has no
+ /// data
+ /// \arg \b CIFW_UnexpectedEOF: mmCIF construct finished prematurely
+ /// \arg \b CIFW_LoopFieldMissing: loop category has wrong number
+ /// of data fields
+ /// \arg \b CIFW_NotAStructure: attempt to use a category name,
+ /// which was once defined as a structure,
+ /// as a loop
+ /// \arg \b CIFW_NotALoop: attempt to use a category name, which was
+ /// once defined as a loop, as a structure
+ /// \arg \b CIFW_DuplicateTag: duplicate tag was found in a
+ /// structure or loop
+ inline int GetWarnings() { return Warning; }
+
+ /// \brief Sets category names and tags that are to be ignored
+ /// on file read.
+ /// \param[in] cats list of categories, terminated by NULL
+ /// \param[in] tags list of tags, terminated by NULL.
+ ///
+ /// This special function is to aid reading corrupt mmCIF files.
+ /// The input lists should be of equal length 'n', and specify
+ /// 'n' \"wrong fields\" that should be ignored on input. E.g.,
+ /// ith \"wrong field\" is identified as \"cats[i].taga[i]\".
+ /// If \"wrong field\" belongs to a loop, then all the corresponding
+ /// column is assumed to be absent. This corrects for mmCIF errors
+ /// when defined tags in loops or structures do not have actual data
+ /// associated with them.
+ ///
+ /// In order to remove settings, call SetWrongFields(NULL,NULL).
+ ///
+ /// Example:
+ /*!
+ \code
+ // assume data for "_category.item1" and "_category.item2"
+ // missed in a file to-be-read
+ mmcif::Data data;
+ cpstr cats[] = { "_category", "_category", NULL };
+ cpstr tags[] = { "item1" , "item2" , NULL };
+
+ data.SetWrongFields ( cats,tags );
+ data.ReadMMCIFData ( "corrupt.cif" );
+ \endcode
+ */
+ void SetWrongFields ( cpstr *cats, cpstr *tags );
+
+ /// \brief Reads mmCIF data block from file.
+ /// \param FName character null-terminated string with file name
+ /// \param gzipMode flag to read compressed files:
+ /// \arg \b GZM_NONE: do not assume any compression
+ /// \arg \b GZM_CHECK: check compression type by file extension
+ /// \arg \b GZM_ENFORCE: same as \b GZM_ENFORCE_GZIP
+ /// \arg \b GZM_ENFORCE_GZIP: assume gzip compression (*.gz files)
+ /// \arg \b GZM_ENFORCE_COMPRESS: assume compression with 'compress'
+ /// (*.Z files).
+ /// \return \b CIFRC_Ok: no errors
+ /// \return \b negative: there were errors
+ /// \return \b positive: there were warnings.
+ ///
+ /// This function will read 1st data block from the specified file.
+ /// In case of non-zero return, use GetCIFMessage() function to
+ /// print the corresponding error message or warning:
+ /*!
+ \code
+ mmcif::Data data;
+ char errLog[500];
+ int rc;
+ rc = data.ReadMMCIFData ( "myfile.cif" );
+ if (rc<0)
+ printf ( " There was an error:\n %s\n",
+ GetCIFMessage(errLog,rc) );
+ else if (rc>0)
+ printf ( " There were warnings:\n %s\n",
+ GetCIFMessage(errLog,rc) );
+ else
+ printf ( " mmCIF file has be read in successfully.\n" );
+ \endcode
+ */
+ int ReadMMCIFData ( cpstr FName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+ /// \brief Reads sequential mmCIF data blocks from file.
+ /// \param RCFile reference to a CFile object opened on a file
+ /// \param S buffer string which represent a sliding read window.
+ /// The string should be at least 500 characters long,
+ /// initialized with empty-string value before first read,
+ /// and passed unchanged between the reads
+ /// \param lcount line counter, should be set zero before first
+ /// read and passed unchanged between the reads.
+ /// \return \b CIFRC_Ok: no errors
+ /// \return \b negative: there were errors
+ /// \return \b positive: there were warnings.
+ ///
+ /// This function will read 1st data block from the current position
+ /// of the file. The function is useful if a file contains more than
+ /// a single data block, which should be read sequentially.
+ ///
+ /// \note Alternatively, files with multiple data blocks can be
+ /// read using mmcif::File class.
+ ///
+ /// In case of non-zero return, use GetCIFMessage() function to
+ /// print the corresponding error message or warning:
+ /*!
+ \code
+ mmcif::Data mmCIFData;
+ CFile f;
+ char S[1000];
+ int rc,lcount;
+
+ // open file first
+ f.assign ( "/path/example.cif" );
+ if (!f.reset(true)) {
+ printf ( " *** cannot open file '%s' for reading.\n",
+ f.FileName() );
+ return -1;
+ }
+
+ lcount = 0; // global line counter through the file
+ S[0] = char(0); // buffer string
+ while (!f.FileEnd()) {
+
+ rc = mmCIFData.ReadMMCIFData ( f,S,lcount );
+
+ if (rc!=CIFRC_Ok) { // error or warning
+ if ((rc<0) && (!f.FileEnd())) { // error
+ printf ( " *** error reading file %s:\n"
+ " %s\n",f.FileName(),GetCIFMessage(S,rc) );
+ return rc;
+ } else if (rc>0) { // warning
+ printf ( " ... warning on reading file %s:\n"
+ " %s\n",f.FileName(),GetCIFMessage(S,rc) );
+ }
+ } else {
+ // fetch needful values from the data block
+ // ........
+ }
+
+ }
+
+ f.shut(); // close file
+
+ // NOTE: do not delete mmcif::Struct/mmcif::Loop
+ // classes obtained from mmcif::Data. If you do, get a crash.
+ // All these structures are containers that dispose their
+ // content automatically.
+ \endcode
+ */
+ int ReadMMCIFData ( io::RFile f, pstr S, int & lcount );
+
+ /// \brief Writes mmCIF data block into file.
+ /// \param FName character null-terminated string with file name
+ /// \param gzipMode flag to read compressed files:
+ /// \arg \b GZM_NONE: do not compress
+ /// \arg \b GZM_CHECK: compress according to file extension
+ /// \arg \b GZM_ENFORCE: same as \b GZM_ENFORCE_GZIP
+ /// \arg \b GZM_ENFORCE_GZIP: compress with gzip
+ /// \arg \b GZM_ENFORCE_COMPRESS: compression with 'compress'.
+ /// \return \b true: no errors
+ /// \return \b false: file cannot be open for writing.
+ bool WriteMMCIFData ( cpstr FName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+ /// \brief Writes (next) mmCIF data block into file.
+ /// \param RCFile reference to a CFile object opened on a file.
+ ///
+ /// This function allows for sequential write of mmCIF data blocks
+ /// into a file.
+ ///
+ /// \note Alternatively, files with multiple data blocks can be
+ /// created using mmcif::File class.
+ ///
+ /// Example:
+ /*!
+ \code
+ io::File f;
+ mmcif::Data cifData;
+
+ // open file first
+ f.assign ( "/path/example.cif" );
+ if (!f.rewrite()) {
+ printf ( " *** cannot open file '%s' for writing.\n",
+ f.FileName() );
+ return -1;
+ }
+
+ cifData.PutDataName ( "name1" );
+ // fill cifData with all data needed
+ cifData.WriteMMCIF ( f ); // first data block written
+
+ cifData.FreeMemory ( 0 ); // reset data block to empty
+ cifData.PutDataName ( "name2" );
+ // fill cifData with all data needed
+ cifData.WriteMMCIF ( f ); // second data block written
+
+ // add as many data blocks as needed
+
+ // now close the file
+ f.shut();
+
+ \endcode
+
+ */
+ void WriteMMCIF ( io::RFile f );
+
+
+ // -------- Retrieving data
+
+ /// \brief Returns the number of categories (structures and loops)
+ /// in data block.
+ inline int GetNumberOfCategories () { return nCategories; }
+
+ /// \brief Retrieves pointer to category (a structure or a loop) by
+ /// category number.
+ /// \param categoryNo category number to retrieve. Categories are
+ /// numbered from 0 to GetNumberOfCategories()-1.
+ /// \return pointer to category, if \b categoryNo is in the right
+ /// range, or \b NULL otherwise.
+ ///
+ /// \note The category type (structure or loop) is returned by
+ /// function mmcif::Category::GetCategoryID().
+ /// \note The application should never attempt to deallocate
+ /// the category returned. It will be properly disposed of by
+ /// mmcif::Data's destructor.
+ PCategory GetCategory ( int categoryNo ); // 0..nCategories-1
+
+ /// \brief Retrieves mmCIF structure with given name.
+ /// \param CName character string with name of the structure (must
+ /// start with underscore).
+ /// \return pointer to structure if structure with given name was
+ /// found, and \b NULL otherwise.
+ /// \note The application should never attempt to deallocate
+ /// the structure returned. It will be properly disposed of by
+ /// mmcif::Data's destructor.
+ PStruct GetStructure ( cpstr CName );
+
+ /// \brief Retrieves mmCIF loop with given name.
+ /// \param CName character string with name of the loop (must
+ /// start with underscore).
+ /// \return pointer to loop if loop with given name was
+ /// found, and \b NULL otherwise.
+ /// \note The application should never attempt to deallocate
+ /// the loop returned. It will be properly disposed of by
+ /// mmcif::Data's destructor.
+ PLoop GetLoop ( cpstr CName );
+
+ /// \brief Finds loop containing all tags from the tag list
+ /// provided.
+ /// \param tagList list of tags to be looked for. The list should
+ /// be terminated by empty string \"\". The order of tags
+ /// is not significant.
+ /// \return pointer to loop if loop with given tags was found, and
+ /// \b NULL otherwise.
+ ///
+ /// The function will look for first loop that includes all tags
+ /// from the list. The list does not have to include all tags for
+ /// that loop in order for function to succeed. This function is
+ /// useful for reading \"dirty cifs\" that may contain loops without
+ /// a name.
+ PLoop FindLoop ( cpstr * tagList );
+
+ /// \brief Retrieves data block name into dynamically-allocated
+ /// string.
+ /// \param dname pointer reference to a string that accepts data
+ /// block name. If \b dname is not \b NULL, it is treated
+ /// as a pre-allocated string, which is disposed before
+ /// copying. The application is responsible for deallocating
+ /// \b dname.
+ /// \param Remove flag to remove name from the data block.
+ void GetDataName ( pstr & dname, bool Remove=false );
+
+ /// \brief Returns data block name.
+ inline pstr GetDataName() { return name; }
+
+ // CheckData(..) returns positive value if the field is in the
+ // file:
+ // CIFRC_Structure category CName is a structure
+ // CIFRC_Loop category CName is a loop
+ // Negative returns mean:
+ // CIFRC_StructureNoTag category CName is present,
+ // it is a structure, but it does not
+ // have tag TName
+ // CIFRC_LoopNoTag category CName is present,
+ // it is a loop, but it does not have
+ // tag TName
+ // CIFRC_NoCategory category CName is not present.
+ // If TName is set to NULL then only the CName is checked and
+ // possible returns are CIFRC_Structure, CIFRC_Loop and
+ // CIFRC_NoCategory.
+ int CheckData ( cpstr CName, cpstr TName );
+
+ int DeleteCategory ( cpstr CName );
+ int DeleteStructure ( cpstr CName );
+ int DeleteLoop ( cpstr CName );
+
+ // Optimize() optimizes the CIF data in memory allocation. It is
+ // a good idea to call it once after extraction of data (GetXXXXXX
+ // functions) with Remove flag set on has been completed.
+ void Optimize();
+
+ // GetString(..), GetReal(..) and GetInteger(..) return 0 if the
+ // requested field was found and successfully converted. Negative
+ // returns mean:
+ // CIFRC_WrongFormat the field was found but failed to convert
+ // due to improper numeric format
+ // CIFRC_NoTag category CName was found, but it does not
+ // have tag TName
+ // CIFRC_NoCategory category CName was not found
+ // CIFRC_NotAStructure category CName was found, but it is
+ // a loop rather than a structure.
+ // GetString(..) will try to dispose Dest unless it is assigned
+ // NULL value before the call. The string will be then dynamically
+ // allocated and copied.
+ // If Remove is set to true, the field will be removed after
+ // extraction.
+ int GetString ( pstr & Dest, cpstr CName, cpstr TName,
+ bool Remove=false );
+ pstr GetString ( cpstr CName, cpstr TName, int & RC );
+ int DeleteField ( cpstr CName, cpstr TName );
+ int GetReal ( realtype & R, cpstr CName,
+ cpstr TName, bool Remove=false );
+ int GetInteger ( int & I, cpstr CName, cpstr TName,
+ bool Remove=false );
+
+ // GetLoopLength(..) returns CIFRC_NotALoop if the category CName
+ // is not a loop, CIFRC_NoCategory if the category CName is not
+ // found. Non-negative returns give the length of the loop (may be
+ // 0 if the loop is empty).
+ int GetLoopLength ( cpstr CName );
+
+ // GetLoopString(..), GetLoopReal(..) and GetLoopInteger(..) act
+ // like GetString(..), GetReal(..) and GetInteger(..) above for
+ // nrow-th element of the 'loop_' (indexed like 0..N-1 where N
+ // is obtained through GetLoopLength(..)). They will return
+ // CIFRC_WrongIndex if nrow is out of range.
+ // If Remove is set to true, the field will be removed after
+ // extraction.
+ int GetLoopString ( pstr & Dest, cpstr CName,
+ cpstr TName, int nrow,
+ bool Remove=false );
+ pstr GetLoopString ( cpstr CName, cpstr TName,
+ int nrow, int & RC );
+ int DeleteLoopField ( cpstr CName, cpstr TName,
+ int nrow );
+ int GetLoopReal ( realtype & R, cpstr CName,
+ cpstr TName, int nrow,
+ bool Remove=false );
+ int GetLoopInteger ( int & I, cpstr CName,
+ cpstr TName, int nrow,
+ bool Remove=false );
+
+ // GetLoopSVector(..), GetLoopRVector(..) and GetLoopIVector(..)
+ // read CIF 'loop_' data into allocated vectors of strings, reals
+ // and integers, correspondingly. The vectors may be deallocated
+ // prior to call and assigned NULL, in which case they will be
+ // allocated with offsets of i1, which is also the lower index of
+ // the 'loop_' data transferred into it. The upper vector index is
+ // given by i2 or by the loop's length whichever is less. If
+ // vectors are not assigned NULL prior the call, it is assumed
+ // that they are properly (i1-offset, i2-i1+1 length) allocated.
+ // The return codes are same as those of GetLoopString(..),
+ // GetLoopReal(..) and GetLoopInteger(..).
+ int GetLoopSVector ( psvector & S, cpstr CName,
+ cpstr TName, int i1=0, int i2=MaxInt4,
+ bool Remove=false );
+ int GetLoopRVector ( rvector & R, cpstr CName,
+ cpstr TName, int i1=0, int i2=MaxInt4,
+ bool Remove=false );
+ int GetLoopIVector ( ivector & I, cpstr CName,
+ cpstr TName, int i1=0, int i2=MaxInt4,
+ bool Remove=false );
+
+
+ // -------- Storing data
+
+ // Unless the data are to be added to the existing CIF structure,
+ // FreeMemory() should be called once before creating a new
+ // CIF data set.
+ void FreeMemory ( int key );
+
+ void PutDataName ( cpstr dname ); // stores name for 'data_'
+ // record
+
+ // PutString(..), PutReal(..) and PutInteger(..) will put the
+ // values given into the specified category (CName) under the
+ // specified tag (TName). The category, tag and field are created
+ // automatically; the field will be replaced silently if identical
+ // CName.TName is specified in two calls. Calls of these functions
+ // may follow in random order; however CIF file will have all tags
+ // grouped by categories and catgories will follow in the order
+ // of first appearance in PutString(..), PutReal(..) or
+ // PutInteger(..).
+ // Return code - one of CIFRC_Ok or CIFRC_NotAStruct
+ int PutNoData ( int NoDataType, cpstr CName,
+ cpstr TName );
+ int PutString ( cpstr S, cpstr CName,
+ cpstr TName, bool Concatenate=false );
+ int PutDate ( cpstr CName, cpstr TName );
+ int PutReal ( realtype R, cpstr CName, cpstr TName,
+ int prec=8 );
+ int PutInteger ( int I, cpstr CName, cpstr TName );
+
+ // If loop category CName is not present in the CIF data
+ // structure, AddLoop(..) creates an empty one and returns
+ // its pointer in Loop. If loop category CName is already in
+ // the CIF data structure, its pointer is returned, and any
+ // data which might be contained in it, remains untouched.
+ // To stuff the loop with data, first the data tags have to
+ // be specified by calling Loop->AddLoopTag(..). After all
+ // tags are given, the data comes as a stream of calls
+ // Loop->AddString(..), Loop->AddReal(..) and
+ // Loop->AddInteger(..) which should provide data for every
+ // tag in sequence in strictly the same order as the tags
+ // were given. This essentially reflects reading a CIF loop
+ // from a file.
+ // Alternatively, the loop data may be stored with PutLoopXXX()
+ // functions given below, although this way may be less
+ // efficient (but more flexible).
+ // AddLoop(..) may return
+ // CIFRC_Ok category was present
+ // CIFRC_Created category was not present but it has
+ // been created; the category is empty
+ // CIFRC_NotALoop category was present as a structure, but
+ // has been replaced for a loop;
+ // the category is empty.
+ int AddLoop ( cpstr CName, PLoop & cifLoop );
+ int AddStructure ( cpstr CName, PStruct & cifStruct );
+
+ // PutLoopString(..), PutLoopReal(..) and PutLoopInteger(..) act
+ // like PutString(..), PutReal(..) and PutInteger(..) above for
+ // nrow-th element of the 'loop_' CName (indexed begining from 0).
+ // In consequitive calls, given values of nrow does not have to be
+ // ordered; the most efficient way is to start with HIGHEST value
+ // for nrow in the loop and move down to 0. The least efficient way
+ // is to start with nrow=0 and move up.
+ // These functions allow to form loops in arbitrary way.
+ // The functions may return CIFRC_Ok or CIFRC_NotALoop.
+ int PutLoopNoData ( int NoDataType, cpstr CName,
+ cpstr TName, int nrow );
+ int PutLoopString ( cpstr S, cpstr CName,
+ cpstr TName, int nrow );
+ int PutLoopReal ( realtype R, cpstr CName,
+ cpstr TName, int nrow,
+ int prec=8 );
+ int PutLoopInteger ( int I, cpstr CName, cpstr TName,
+ int nrow );
+
+ // PutLoopSVector(..), PutLoopRVector(..) and PutLoopIVector(..)
+ // put vectors of values into specified loop fields. Parameters i1
+ // and i2 give the range of indices of values which are to be
+ // transfered. To transfer an entire vector allocated as [0..N-1]
+ // i1 shoudl be set to 0 and i2 - to N-1. Note that the loop is
+ // always indexed as starting form 0 on, therefore negative i1 and
+ // i2 are not allowed, and specifying i1>0 will leave first i1
+ // elements of the CIF loop for the corresponding tag undefined
+ // (will be output like '?').
+ // These functions allow to form loops in arbitrary way.
+ int PutLoopSVector ( psvector S, cpstr CName,
+ cpstr TName, int i1, int i2 );
+ int PutLoopRVector ( rvector R, cpstr CName,
+ cpstr TName, int i1, int i2,
+ int prec=8 );
+ int PutLoopIVector ( ivector I, cpstr CName,
+ cpstr TName, int i1, int i2 );
+
+ int RenameCategory ( cpstr CName, cpstr newCName );
+
+ // --------
+
+ void Copy ( PData Data );
+ int CopyCategory ( PData Data, cpstr CName,
+ cpstr newCName=NULL );
+
+ void PrintCategories(); // for debuging only
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected:
+ pstr name;
+ int nCategories;
+ PPCategory Category;
+ ivector index;
+ int flags;
+ int Warning;
+ int loopNo; // used locally for suggesting categories
+ int tagNo; // used locally for suggesting tags
+ psvector WrongCat;
+ psvector WrongTag;
+ int nWrongFields;
+
+ void InitData ();
+ void FreeWrongFields ();
+ bool CheckWrongField ( cpstr C, cpstr T );
+ void Sort ();
+
+ // GetCategoryNo searches for index of category cname
+ // in Category[]. Return:
+ // >=0 : position of the category found
+ // <0 : the category was not found, it could be inserted before
+ // (-RC-1)th element, where RC is the return value
+ int GetCategoryNo ( cpstr cname );
+ int AddCategory ( cpstr cname );
+ int DeleteCategory ( int CatNo );
+
+ void GetDataItem ( io::RFile f, pstr S, pstr & L, pstr & p,
+ int & lcount, int & llen );
+ void GetLoop ( io::RFile f, pstr S, pstr & L, pstr & p,
+ int & lcount, int & llen );
+ int GetField ( io::RFile f, pstr S, pstr & L, pstr & p,
+ int & lcount, int & llen );
+
+ };
+
+
+
+ // ======================== File =============================
+
+ DefineClass(File);
+ DefineStreamFunctions(File);
+
+ class File : public io::Stream {
+
+ public :
+ int nData;
+ ivector index;
+ PPData data;
+
+ File ();
+ File ( cpstr FName, io::GZ_MODE gzipMode=io::GZM_CHECK );
+ File ( io::RPStream Object );
+ ~File();
+
+ void SetPrintWarnings ( bool SPW ) { PrintWarnings = SPW; }
+ void SetStopOnWarning ( bool SOW ) { StopOnWarning = SOW; }
+
+ int ReadMMCIFFile ( cpstr FName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ int WriteMMCIFFile ( cpstr FName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+ int GetNofData() { return nData; }
+ PData GetCIFData ( int dataNo ); // 0..nData-1
+ PData GetCIFData ( cpstr DName );
+ int AddCIFData ( cpstr DName );
+ int DeleteCIFData ( cpstr DName );
+ int DeleteCIFData ( int dataNo );
+ int GetCIFDataNo ( cpstr DName );
+
+ void WriteMMCIF ( io::RFile f );
+
+ void Copy ( PFile File );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected:
+ int nAllocData;
+ bool PrintWarnings;
+ bool StopOnWarning;
+
+ void InitFile ();
+ void FreeMemory ();
+ void Sort ();
+ void ExpandData ( int nDataNew );
+
+ };
+
+
+ extern pstr GetMMCIFInputBuffer ( int & LineNo );
+
+ // isCIF will return
+ // -1 if file FName does not exist
+ // 0 if file FName is likely a CIF file ( 'data_' is present )
+ // 1 if file FName is not a CIF file ( 'data_' is absent )
+ extern int isCIF ( cpstr FName, io::GZ_MODE gzipMode=io::GZM_CHECK );
+ extern int isCIF ( io::RFile f );
+
+ pstr GetCIFMessage ( pstr M, int RC );
+
+
+ } // namespace mmcif
+
+} // namespace mmdb
+
+
+#endif
+
+
diff --git a/mmdb2/mmdb_model.cpp b/mmdb2/mmdb_model.cpp
new file mode 100644
index 0000000..ca1d537
--- /dev/null
+++ b/mmdb2/mmdb_model.cpp
@@ -0,0 +1,5332 @@
+// $Id: mmdb_model.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Model <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::HetCompound ( description of het compounds )
+// ~~~~~~~~~ mmdb::HetCompounds (HETNAM, HETSYN, FORMULA records)
+// mmdb::SSContainer (container for helixes and turns)
+// mmdb::Helix ( helix info )
+// mmdb::Strand ( strand info )
+// mmdb::Sheet ( sheet info )
+// mmdb::Sheets ( container for sheets )
+// mmdb::Turn ( turn info )
+// mmdb::LinkContainer ( container for link data )
+// mmdb::Link ( link data )
+// mmdb::LinkRContainer ( container for refmac link )
+// mmdb::LinkR ( link data )
+// mmdb::CisPepContainer ( container for CisPep data )
+// mmdb::CisPep ( CisPep data )
+// mmdb::Model ( PDB model )
+//
+// Copyright (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mmdb_model.h"
+#include "mmdb_manager.h"
+#include "mmdb_cifdefs.h"
+
+namespace mmdb {
+
+ // =================== HetCompound =========================
+
+ HetCompound::HetCompound ( cpstr HetName ) : io::Stream() {
+ InitHetCompound ( HetName );
+ }
+
+ HetCompound::HetCompound ( io::RPStream Object ) : io::Stream(Object) {
+ InitHetCompound ( pstr("---") );
+ }
+
+ HetCompound::~HetCompound() {
+ FreeMemory();
+ }
+
+ void HetCompound::InitHetCompound ( cpstr HetName ) {
+ strcpy_n0 ( hetID,HetName,sizeof(ResName) );
+ comment = NULL;
+ nSynonyms = 0;
+ hetSynonym = NULL;
+ compNum = MinInt4;
+ wc = ' ';
+ Formula = NULL;
+ }
+
+ void HetCompound::FreeMemory() {
+ int i;
+ if (comment) {
+ delete[] comment;
+ comment = NULL;
+ }
+ if (hetSynonym) {
+ for (i=0;i<nSynonyms;i++)
+ if (hetSynonym[i]) delete[] hetSynonym[i];
+ delete[] hetSynonym;
+ hetSynonym = NULL;
+ }
+ nSynonyms = 0;
+ if (Formula) {
+ delete[] Formula;
+ Formula = NULL;
+ }
+ }
+
+ void HetCompound::AddKeyWord ( cpstr W, bool Closed ) {
+ psvector HS1;
+ int i;
+ if (Closed || (!hetSynonym)) {
+ // first synonym orthe previous synonym was closed by semicolon
+ // -- add a new one
+ HS1 = new pstr[nSynonyms+1];
+ for (i=0;i<nSynonyms;i++)
+ HS1[i] = hetSynonym[i];
+ if (hetSynonym) delete[] hetSynonym;
+ hetSynonym = HS1;
+ hetSynonym[nSynonyms] = NULL;
+ CreateCopy ( hetSynonym[nSynonyms],W );
+ nSynonyms++;
+ } else {
+ // just add W to the last synonym
+ CreateConcat ( hetSynonym[nSynonyms-1],pstr(" "),W );
+ }
+ }
+
+
+ void HetCompound::HETNAM_PDBDump ( io::RFile f ) {
+ char S[100];
+ pstr p1,p2;
+ char c;
+ int N,i;
+
+ if (!comment) return;
+
+ c = ' ';
+ N = 0;
+ p1 = comment;
+ do {
+ N++;
+ if (N==1) sprintf ( S,"HETNAM %3s " ,hetID );
+ else sprintf ( S,"HETNAM %2i %3s ",N,hetID );
+ while (*p1==' ') p1++;
+ p2 = strchr(p1,'\n');
+ if (p2) {
+ c = *p2;
+ *p2 = char(0);
+ } else if (strlen(p1)>53) {
+ i = 0;
+ while (p1[i] && (i<53) && (p1[i]!=' ')) i++;
+ p2 = &(p1[i]);
+ c = *p2;
+ *p2 = char(0);
+ }
+ if (*p1) {
+ strcat ( S,p1 );
+ PadSpaces ( S,80 );
+ f.WriteLine ( S );
+ } else
+ N--;
+ if (p2) {
+ *p2 = c;
+ if (c) p1 = p2+1;
+ else p2 = NULL;
+ }
+ } while (p2);
+
+ }
+
+
+ void HetCompound::HETSYN_PDBDump ( io::RFile f ) {
+ char S[100];
+ pstr p;
+ char c;
+ int N,k,i,l;
+ if (!hetSynonym) return;
+ N = 0;
+ k = 0;
+ p = &(hetSynonym[0][0]);
+ do {
+ N++;
+ if (N==1) sprintf ( S,"HETSYN %3s " ,hetID );
+ else sprintf ( S,"HETSYN %2i %3s ",N,hetID );
+ i = 0;
+ do {
+ l = strlen(p)+2;
+ if (i+l<54) {
+ strcat ( S,p );
+ if (k<nSynonyms-1) strcat ( S,"; " );
+ k++;
+ i += l;
+ if (k<nSynonyms) p = &(hetSynonym[k][0]);
+ else i = 60; // break loop
+ } else {
+ if (i==0) {
+ // too long synonym, has to be split over several lines
+ i = l-3;
+ while (i>51) {
+ i--;
+ while ((i>0) && (p[i]!=' ')) i--;
+ }
+ if (i<2) i = 51; // no spaces!
+ c = p[i];
+ p[i] = char(0);
+ strcat ( S,p );
+ p[i] = c;
+ p = &(p[i]);
+ while (*p==' ') p++;
+ }
+ i = 60; // break loop
+ }
+ } while (i<54);
+ PadSpaces ( S,80 );
+ f.WriteLine ( S );
+ } while (k<nSynonyms);
+ }
+
+
+ void HetCompound::FORMUL_PDBDump ( io::RFile f ) {
+ char S[100];
+ pstr p1,p2;
+ char c;
+ int N,i;
+ if (!Formula) return;
+ N = 0;
+ p1 = Formula;
+ do {
+ N++;
+ if (compNum>MinInt4) {
+ if (N==1) sprintf ( S,"FORMUL %2i %3s " ,compNum,hetID );
+ else sprintf ( S,"FORMUL %2i %3s %2i ",compNum,hetID,N );
+ } else {
+ if (N==1) sprintf ( S,"FORMUL %3s " ,hetID );
+ else sprintf ( S,"FORMUL %3s %2i ",hetID,N );
+ }
+ S[18] = wc;
+ p2 = strchr(p1,'\n');
+ if (p2) {
+ c = *p2;
+ *p2 = char(0);
+ } else if (strlen(p1)>50) {
+ while (*p1==' ') p1++;
+ i = 0;
+ while (p1[i] && (i<50) && (p1[i]!=' ')) i++;
+ p2 = &(p1[i]);
+ c = *p2;
+ *p2 = char(0);
+ }
+ strcat ( S,p1 );
+ if (p2) {
+ *p2 = c;
+ p1 = p2+1;
+ }
+ PadSpaces ( S,80 );
+ f.WriteLine ( S );
+ } while (p2);
+ }
+
+
+ void HetCompound::FormComString ( pstr & F ) {
+ pstr p;
+ int i;
+ if (F) {
+ delete[] F;
+ F = NULL;
+ }
+ if (comment) {
+ CreateCopy ( F,comment );
+ i = 0;
+ p = comment;
+ while (*p) {
+ p++;
+ if (*p=='\n') i = 0;
+ else i++;
+ if (i>68) {
+ F[i] = char(0);
+ CreateConcat ( F,pstr("\n"),p );
+ i = 0;
+ }
+ }
+ }
+ }
+
+
+ void HetCompound::FormSynString ( pstr & F ) {
+ pstr p;
+ char c;
+ int i,k,l;
+ if (F) {
+ delete[] F;
+ F = NULL;
+ }
+ if (hetSynonym) {
+ CreateCopy ( F,pstr(" ") );
+ k = 0;
+ p = &(hetSynonym[0][0]);
+ do {
+ l = strlen(p)+2;
+ if (l<=60) {
+ if (k<nSynonyms-1) CreateConcat ( F,p,pstr(";\n ") );
+ else CreateConcat ( F,p );
+ k++;
+ if (k<nSynonyms) p = &(hetSynonym[k][0]);
+ } else {
+ // too long synonym, has to be split over several lines
+ i = l-3;
+ while (i>60) {
+ i--;
+ while ((i>0) && (p[i]!=' ')) i--;
+ }
+ if (i<2) i = 60; // no spaces!
+ c = p[i];
+ p[i] = char(0);
+ CreateConcat ( F,p,pstr("\n ") );
+ p[i] = c;
+ p = &(p[i]);
+ while (*p==' ') p++;
+ }
+ } while (k<nSynonyms);
+ }
+ }
+
+ void HetCompound::FormForString ( pstr & F ) {
+ pstr p;
+ int i;
+ if (F) {
+ delete[] F;
+ F = NULL;
+ }
+ if (Formula) {
+ CreateCopy ( F,Formula );
+ i = 0;
+ p = &(Formula[0]);
+ while (*p) {
+ p++;
+ if (*p=='\n') i = 0;
+ else i++;
+ if (i>68) {
+ F[i] = char(0);
+ CreateConcat ( F,pstr("\n"),p );
+ i = 0;
+ }
+ }
+ }
+ }
+
+
+ void HetCompound::Copy ( PHetCompound hetCompound ) {
+ int i;
+ FreeMemory ();
+ strcpy ( hetID ,hetCompound->hetID );
+ CreateCopy ( comment,hetCompound->comment );
+ nSynonyms = hetCompound->nSynonyms;
+ if (nSynonyms>0) {
+ hetSynonym = new pstr[nSynonyms];
+ for (i=0;i<nSynonyms;i++) {
+ hetSynonym[i] = NULL;
+ CreateCopy ( hetSynonym[i],hetCompound->hetSynonym[i] );
+ }
+ }
+ compNum = hetCompound->compNum;
+ wc = hetCompound->wc;
+ CreateCopy ( Formula,hetCompound->Formula );
+ }
+
+ void HetCompound::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteTerLine ( hetID,false );
+ f.CreateWrite ( comment );
+ f.WriteInt ( &nSynonyms );
+ for (i=0;i<nSynonyms;i++)
+ f.CreateWrite ( hetSynonym[i] );
+ f.WriteInt ( &compNum );
+ f.WriteFile ( &wc,sizeof(wc) );
+ f.CreateWrite ( Formula );
+ }
+
+ void HetCompound::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ FreeMemory();
+ f.ReadByte ( &Version );
+ f.ReadTerLine ( hetID,false );
+ f.CreateRead ( comment );
+ f.ReadInt ( &nSynonyms );
+ if (nSynonyms>0) {
+ hetSynonym = new pstr[nSynonyms];
+ for (i=0;i<nSynonyms;i++) {
+ hetSynonym[i] = NULL;
+ f.CreateRead ( hetSynonym[i] );
+ }
+ }
+ f.ReadInt ( &compNum );
+ f.ReadFile ( &wc,sizeof(wc) );
+ f.CreateRead ( Formula );
+ }
+
+ MakeStreamFunctions(HetCompound)
+
+
+ // ==================== HetCompounds =======================
+
+
+ HetCompounds::HetCompounds() : io::Stream() {
+ InitHetCompounds();
+ }
+
+ HetCompounds::HetCompounds ( io::RPStream Object )
+ : io::Stream(Object) {
+ InitHetCompounds();
+ }
+
+ HetCompounds::~HetCompounds() {
+ FreeMemory();
+ }
+
+ void HetCompounds::InitHetCompounds() {
+ nHets = 0;
+ hetCompound = NULL;
+ Closed = false;
+ }
+
+ void HetCompounds::FreeMemory() {
+ int i;
+ if (hetCompound) {
+ for (i=0;i<nHets;i++)
+ if (hetCompound[i]) delete hetCompound[i];
+ delete[] hetCompound;
+ hetCompound = NULL;
+ }
+ nHets = 0;
+ }
+
+ void HetCompounds::ConvertHETNAM ( cpstr S ) {
+ ResName hetID;
+ char L[100];
+ int l,i;
+ l = strlen(S);
+ if (l>12) {
+ strcpy_n0 ( hetID,&(S[11]),3 );
+ i = AddHetName ( hetID );
+ if (l>15) {
+ if (hetCompound[i]->comment) strcpy ( L,"\n" );
+ else L[0] = char(0);
+ strcat ( L,&(S[15]) );
+ CutSpaces ( L,SCUTKEY_END );
+ CreateConcat ( hetCompound[i]->comment,L );
+ }
+ }
+ }
+
+ void HetCompounds::ConvertHETSYN ( cpstr S ) {
+ ResName hetID;
+ char L[100];
+ int l,i,j,k;
+ l = strlen(S);
+ if (l>12) {
+ strcpy_n0 ( hetID,&(S[11]),3 );
+ i = AddHetName ( hetID );
+ if (l>15) {
+ j = 15;
+ do {
+ while (S[j]==' ') j++;
+ k = 0;
+ if (S[j]) {
+ while (S[j] && (S[j]!=';'))
+ L[k++] = S[j++];
+ L[k--] = char(0);
+ while ((k>0) && (L[k]==' ')) L[k--] = char(0);
+ if (L[0]) {
+ hetCompound[i]->AddKeyWord ( L,Closed );
+ Closed = (S[j]==';');
+ }
+ if (S[j]) j++;
+ }
+ } while (S[j]);
+ /*
+ p1 = &(S[15]);
+ do {
+ p2 = strchr ( p1,';' );
+ if (p2) {
+ c = *p2;
+ *p2 = char(0);
+ }
+ strcpy_css ( L,p1 );
+ if (L[0])
+ hetCompound[i]->AddKeyWord ( L,Closed );
+ if (p2) {
+ if (L[0]) Closed = true;
+ *p2 = c;
+ p1 = p2+1;
+ } else if (L[0])
+ Closed = false;
+ } while (p2);
+ */
+ }
+ }
+ }
+
+ void HetCompounds::ConvertFORMUL ( cpstr S ) {
+ ResName hetID;
+ char L[100];
+ int l,i;
+ l = strlen(S);
+ if (l>13) {
+ strcpy_n0 ( hetID,&(S[12]),3 );
+ i = AddHetName ( hetID );
+ if (l>18) {
+ GetInteger ( hetCompound[i]->compNum,&(S[9]),2 );
+ hetCompound[i]->wc = S[18];
+ if (strlen(S)>19) {
+ if (hetCompound[i]->Formula) strcpy ( L,"\n" );
+ else L[0] = char(0);
+ strcat ( L,&(S[19]) );
+ CutSpaces ( L,SCUTKEY_END );
+ CreateConcat ( hetCompound[i]->Formula,L );
+ }
+ }
+ }
+ }
+ int HetCompounds::AddHetName ( cpstr H ) {
+ PPHetCompound HC1;
+ int i;
+ i = 0;
+ while (i<nHets) {
+ if (hetCompound[i]) {
+ if (!strcmp(hetCompound[i]->hetID,H)) break;
+ }
+ i++;
+ }
+ if (i>=nHets) {
+ HC1 = new PHetCompound[nHets+1];
+ for (i=0;i<nHets;i++)
+ HC1[i] = hetCompound[i];
+ if (hetCompound) delete[] hetCompound;
+ hetCompound = HC1;
+ hetCompound[nHets] = new HetCompound ( H );
+ i = nHets;
+ nHets++;
+ }
+ return i;
+ }
+
+ void HetCompounds::PDBASCIIDump ( io::RFile f ) {
+ int i;
+
+ for (i=0;i<nHets;i++)
+ if (hetCompound[i])
+ hetCompound[i]->HETNAM_PDBDump ( f );
+
+ for (i=0;i<nHets;i++)
+ if (hetCompound[i])
+ hetCompound[i]->HETSYN_PDBDump ( f );
+
+ for (i=0;i<nHets;i++)
+ if (hetCompound[i])
+ hetCompound[i]->FORMUL_PDBDump ( f );
+
+ }
+
+
+ void HetCompounds::MakeCIF ( mmcif::PData CIF ) {
+ mmcif::PLoop Loop;
+ pstr F;
+ int RC;
+ int i;
+
+ if (!hetCompound) return;
+
+ RC = CIF->AddLoop ( CIFCAT_CHEM_COMP,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_NAME );
+ Loop->AddLoopTag ( CIFTAG_NDB_SYNONYMS );
+ Loop->AddLoopTag ( CIFTAG_NDB_COMPONENT_NO );
+ Loop->AddLoopTag ( CIFTAG_FORMULA );
+ }
+
+ F = NULL;
+ for (i=0;i<nHets;i++)
+ if (hetCompound[i]) {
+ Loop->AddString ( hetCompound[i]->hetID );
+ hetCompound[i]->FormComString ( F );
+ Loop->AddString ( F );
+ hetCompound[i]->FormSynString ( F );
+ Loop->AddString ( F );
+ if (hetCompound[i]->compNum>MinInt4)
+ Loop->AddInteger ( hetCompound[i]->compNum );
+ else Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+ hetCompound[i]->FormForString ( F );
+ Loop->AddString ( F );
+ }
+
+ if (F) delete[] F;
+
+ }
+
+ ERROR_CODE HetCompounds::GetCIF ( mmcif::PData CIF ) {
+ mmcif::PLoop Loop;
+ char L[100];
+ ResName hetID;
+ pstr F,p1,p2;
+ char c;
+ int RC,i,l,k;
+
+ FreeMemory();
+ c = char(0); // only to supress compiler warnings
+
+ Loop = CIF->GetLoop ( CIFCAT_CHEM_COMP );
+ if (!Loop) return Error_NoError;
+
+ l = Loop->GetLoopLength();
+ F = NULL;
+
+ for (i=0;i<l;i++) {
+ CIFGetString ( hetID,Loop,CIFTAG_ID,i,sizeof(hetID),
+ pstr("---") );
+ k = AddHetName ( hetID );
+ Loop->GetString ( hetCompound[k]->comment,CIFTAG_NAME,i,true );
+ RC = Loop->GetInteger ( hetCompound[k]->compNum,
+ CIFTAG_NDB_COMPONENT_NO,i,true );
+ if (RC) hetCompound[i]->compNum = MinInt4;
+ Loop->GetString ( hetCompound[k]->Formula,CIFTAG_FORMULA,i,true );
+ RC = Loop->GetString ( F,CIFTAG_NDB_SYNONYMS,i,true );
+ if ((!RC) && F ) {
+ p1 = &(F[0]);
+ while (*p1) {
+ if (*p1=='\n') *p1 = ' ';
+ p1++;
+ }
+ p1 = &(F[0]);
+ do {
+ p2 = strchr ( p1,';' );
+ if (p2) {
+ c = *p2;
+ *p2 = char(0);
+ }
+ strcpy_css ( L,p1 );
+ hetCompound[i]->AddKeyWord ( L,true );
+ if (p2) {
+ *p2 = c;
+ p1 = p2+1;
+ }
+ } while (p2);
+ }
+ hetCompound[i]->wc = ' ';
+ }
+
+ // CIF->DeleteLoop ( CIFCAT_CHEM_COMP );
+
+ if (F) delete[] F;
+
+ return Error_NoError;
+
+ }
+
+ void HetCompounds::Copy ( PHetCompounds HetCompounds ) {
+ int i;
+ FreeMemory();
+ nHets = HetCompounds->nHets;
+ if (nHets>0) {
+ hetCompound = new PHetCompound[nHets];
+ for (i=0;i<nHets;i++) {
+ hetCompound[i] = new HetCompound ( "" );
+ hetCompound[i]->Copy ( HetCompounds->hetCompound[i] );
+ }
+ }
+ }
+
+ void HetCompounds::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &nHets );
+ for (i=0;i<nHets;i++)
+ hetCompound[i]->write ( f );
+ }
+
+ void HetCompounds::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ FreeMemory();
+ f.ReadByte ( &Version );
+ f.ReadInt ( &nHets );
+ if (nHets>0) {
+ hetCompound = new PHetCompound[nHets];
+ for (i=0;i<nHets;i++) {
+ hetCompound[i] = new HetCompound ( "---" );
+ hetCompound[i]->read ( f );
+ }
+ }
+ }
+
+ MakeStreamFunctions(HetCompounds)
+
+
+
+ // ==================== SSContainer =========================
+
+ PContainerClass SSContainer::MakeContainerClass ( int ClassID ) {
+ switch (ClassID) {
+ default :
+ case ClassID_Template : return
+ ClassContainer::MakeContainerClass(ClassID);
+ case ClassID_Helix : return new Helix();
+ case ClassID_Turn : return new Turn ();
+ }
+ }
+
+ MakeStreamFunctions(SSContainer)
+
+
+ // ================ Helix ===================
+
+ Helix::Helix() : ContainerClass() {
+ InitHelix();
+ }
+
+ Helix::Helix ( cpstr S ) : ContainerClass() {
+ InitHelix();
+ ConvertPDBASCII ( S );
+ }
+
+ Helix::Helix ( io::RPStream Object ) : ContainerClass(Object) {
+ InitHelix();
+ }
+
+ Helix::~Helix() {
+ if (comment) delete[] comment;
+ }
+
+ void Helix::InitHelix() {
+
+ serNum = 0; // serial number
+ strcpy ( helixID ,"---" ); // helix ID
+ strcpy ( initResName,"---" ); // name of the helix's initial residue
+ strcpy ( initChainID,"" ); // chain ID for the chain
+ // containing the helix
+ initSeqNum = 0; // sequence number of the initial
+ // residue
+ strcpy ( initICode ,"" ); // insertion code of the initial
+ // residue
+ strcpy ( endResName ,"---" ); // name of the helix's terminal residue
+ strcpy ( endChainID ,"" ); // chain ID for the chain
+ // containing the helix
+ endSeqNum = 0; // sequence number of the terminal
+ // residue
+ strcpy ( endICode ,"" ); // insertion code of the terminal
+ // residue
+ helixClass = 0; // helix class
+ comment = NULL; // comment about the helix
+ length = 0; // length of the helix
+
+ }
+
+ void Helix::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+ // makes the ASCII PDB OBSLTE line number N
+ // from the class' data
+ strcpy ( S,"HELIX" );
+ PadSpaces ( S,80 );
+ PutInteger ( &(S[7]) ,serNum ,3 );
+ strcpy_n1 ( &(S[11]),helixID ,3 );
+ strcpy_n1 ( &(S[15]),initResName,3 );
+ if (initChainID[0]) S[19] = initChainID[0];
+ PutIntIns ( &(S[21]),initSeqNum ,4,initICode );
+ strcpy_n1 ( &(S[27]),endResName ,3 );
+ if (endChainID[0]) S[31] = endChainID[0];
+ PutIntIns ( &(S[33]),endSeqNum ,4,endICode );
+ PutInteger ( &(S[38]),helixClass ,2 );
+ if (comment)
+ strcpy_n ( &(S[40]),comment ,30 );
+ PutInteger ( &(S[71]),length ,5 );
+ }
+
+ void AddStructConfTags ( mmcif::PLoop Loop ) {
+ Loop->AddLoopTag ( CIFTAG_CONF_TYPE_ID );
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_PDB_ID );
+ Loop->AddLoopTag ( CIFTAG_BEG_LABEL_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_BEG_LABEL_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_BEG_LABEL_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB );
+ Loop->AddLoopTag ( CIFTAG_END_LABEL_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_END_LABEL_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_END_LABEL_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_END_LABEL_INS_CODE_PDB );
+ Loop->AddLoopTag ( CIFTAG_NDB_HELIX_CLASS_PDB );
+ Loop->AddLoopTag ( CIFTAG_DETAILS );
+ Loop->AddLoopTag ( CIFTAG_NDB_LENGTH );
+ }
+
+ #define HelixTypeID "HELX_P"
+
+ void Helix::MakeCIF ( mmcif::PData CIF, int N ) {
+ UNUSED_ARGUMENT(N);
+ mmcif::PLoop Loop;
+ int RC;
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_CONF,Loop );
+ if (RC!=mmcif::CIFRC_Ok)
+ // the category was (re)created, provide tags
+ AddStructConfTags ( Loop );
+ Loop->AddString ( pstr(HelixTypeID) );
+ Loop->AddInteger ( serNum );
+ Loop->AddString ( helixID );
+ Loop->AddString ( initResName );
+ Loop->AddString ( initChainID );
+ Loop->AddInteger ( initSeqNum );
+ Loop->AddString ( initICode,true );
+ Loop->AddString ( endResName );
+ Loop->AddString ( endChainID );
+ Loop->AddInteger ( endSeqNum );
+ Loop->AddString ( endICode ,true );
+ Loop->AddInteger ( helixClass );
+ Loop->AddString ( comment );
+ Loop->AddInteger ( length );
+ }
+
+ ERROR_CODE Helix::ConvertPDBASCII ( cpstr S ) {
+ char L[100];
+ GetInteger ( serNum ,&(S[7]) ,3 );
+ strcpy_ncss ( helixID ,&(S[11]),3 );
+ strcpy_ncss ( initResName,&(S[15]),3 );
+ strcpy_ncss ( initChainID,&(S[19]),1 );
+ GetIntIns ( initSeqNum,initICode,&(S[21]),4 );
+ strcpy_ncss ( endResName ,&(S[27]),3 );
+ strcpy_ncss ( endChainID ,&(S[31]),1 );
+ GetIntIns ( endSeqNum ,endICode ,&(S[33]),4 );
+ GetInteger ( helixClass ,&(S[38]),2 );
+ strcpy_ncss ( L ,&(S[40]),30 );
+ CreateCopy ( comment ,L );
+ GetInteger ( length ,&(S[71]),5 );
+ return Error_NoError;
+ }
+
+ ERROR_CODE Helix::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ int RC,l;
+ pstr F;
+ bool Done;
+ ERROR_CODE rc;
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONF );
+ if (!Loop) {
+ n = -1; // signal to finish processing of this structure
+ return Error_EmptyCIF;
+ }
+
+ l = Loop->GetLoopLength();
+ Done = n>=l;
+ while (!Done) {
+ F = Loop->GetString ( CIFTAG_CONF_TYPE_ID,n,RC );
+ if ((!RC) && F) Done = (strcmp(F,HelixTypeID)==0);
+ else Done = false;
+ if (!Done) {
+ n++;
+ Done = n>=l;
+ }
+ }
+
+ if (n>=l) {
+ n = -1; // finish processing of Helix
+ return Error_EmptyCIF;
+ }
+
+ Loop->DeleteField ( CIFTAG_CONF_TYPE_ID,n );
+
+ rc = CIFGetInteger ( serNum,Loop,CIFTAG_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( helixID ,Loop,CIFTAG_PDB_ID,
+ n,sizeof(helixID),pstr(" ") );
+
+ CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
+ n,sizeof(initResName),pstr(" ") );
+ CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
+ n,sizeof(initChainID),pstr("") );
+ CIFGetString ( initICode ,Loop,CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
+ n,sizeof(initICode),pstr("") );
+ if (CIFGetInteger(initSeqNum,Loop,CIFTAG_BEG_LABEL_SEQ_ID,n))
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
+ n,sizeof(endResName),pstr(" ") );
+ CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
+ n,sizeof(endChainID),pstr("") );
+ CIFGetString ( endICode ,Loop,CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
+ n,sizeof(endICode),pstr("") );
+ rc = CIFGetInteger(endSeqNum,Loop,CIFTAG_END_LABEL_SEQ_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ rc = CIFGetInteger(helixClass,Loop,CIFTAG_NDB_HELIX_CLASS_PDB,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CreateCopy ( comment,Loop->GetString(CIFTAG_DETAILS,n,RC));
+ Loop->DeleteField ( CIFTAG_DETAILS,n );
+ rc = CIFGetInteger ( length,Loop,CIFTAG_NDB_LENGTH,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+ void Helix::Copy ( PContainerClass Helix ) {
+ serNum = PHelix(Helix)->serNum;
+ initSeqNum = PHelix(Helix)->initSeqNum;
+ endSeqNum = PHelix(Helix)->endSeqNum;
+ helixClass = PHelix(Helix)->helixClass;
+ length = PHelix(Helix)->length;
+ strcpy ( helixID ,PHelix(Helix)->helixID );
+ strcpy ( initResName,PHelix(Helix)->initResName );
+ strcpy ( initChainID,PHelix(Helix)->initChainID );
+ strcpy ( initICode ,PHelix(Helix)->initICode );
+ strcpy ( endResName ,PHelix(Helix)->endResName );
+ strcpy ( endChainID ,PHelix(Helix)->endChainID );
+ strcpy ( endICode ,PHelix(Helix)->endICode );
+ CreateCopy ( comment,PHelix(Helix)->comment );
+ }
+
+ void Helix::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &serNum );
+ f.WriteInt ( &initSeqNum );
+ f.WriteInt ( &endSeqNum );
+ f.WriteInt ( &helixClass );
+ f.WriteInt ( &length );
+ f.WriteTerLine ( helixID ,false );
+ f.WriteTerLine ( initResName,false );
+ f.WriteTerLine ( initChainID,false );
+ f.WriteTerLine ( initICode ,false );
+ f.WriteTerLine ( endResName ,false );
+ f.WriteTerLine ( endChainID ,false );
+ f.WriteTerLine ( endICode ,false );
+ f.CreateWrite ( comment );
+ }
+
+ void Helix::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &serNum );
+ f.ReadInt ( &initSeqNum );
+ f.ReadInt ( &endSeqNum );
+ f.ReadInt ( &helixClass );
+ f.ReadInt ( &length );
+ f.ReadTerLine ( helixID ,false );
+ f.ReadTerLine ( initResName,false );
+ f.ReadTerLine ( initChainID,false );
+ f.ReadTerLine ( initICode ,false );
+ f.ReadTerLine ( endResName ,false );
+ f.ReadTerLine ( endChainID ,false );
+ f.ReadTerLine ( endICode ,false );
+ f.CreateRead ( comment );
+ }
+
+ MakeStreamFunctions(Helix)
+
+
+
+ // ================ Strand =====================
+
+ Strand::Strand () : io::Stream() {
+ InitStrand();
+ }
+
+ Strand::Strand ( io::RPStream Object ) : io::Stream(Object) {
+ InitStrand();
+ }
+
+ Strand::~Strand() {
+ }
+
+ void Strand::InitStrand() {
+ initSeqNum = MinInt4;
+ endSeqNum = MinInt4;
+ sense = 0;
+ curResSeq = MinInt4;
+ prevResSeq = MinInt4;
+ strandNo = 0;
+ strcpy ( sheetID ,"sheet_0" );
+ strcpy ( initResName," " );
+ strcpy ( initChainID,"" );
+ strcpy ( initICode ,"" );
+ strcpy ( endResName ," " );
+ strcpy ( endChainID ,"" );
+ strcpy ( endICode ,"" );
+ strcpy ( curAtom ," " );
+ strcpy ( curResName ," " );
+ strcpy ( curChainID ,"" );
+ strcpy ( curICode ,"" );
+ strcpy ( prevAtom ," " );
+ strcpy ( prevResName," " );
+ strcpy ( prevChainID,"" );
+ strcpy ( prevICode ,"" );
+ }
+
+ void Strand::PDBASCIIDump ( pstr S ) {
+ // Finishes making the ASCII PDB SHEET line number N
+ // from the class' data. Making is initiated by Sheet.
+
+ strcpy_n1 ( &(S[17]),initResName,3 );
+ if (initChainID[0]) S[21] = initChainID[0];
+ PutIntIns ( &(S[22]),initSeqNum ,4,initICode );
+
+ strcpy_n1 ( &(S[28]),endResName ,3 );
+ if (endChainID[0]) S[32] = endChainID[0];
+ PutIntIns ( &(S[33]),endSeqNum ,4,endICode );
+
+ PutInteger ( &(S[38]),sense ,2 );
+
+ strcpy_n1 ( &(S[41]),curAtom ,4 );
+ strcpy_n1 ( &(S[45]),curResName ,3 );
+ if (curChainID[0]) S[49] = curChainID[0];
+ PutIntIns ( &(S[50]),curResSeq ,4,curICode );
+
+ strcpy_n1 ( &(S[56]),prevAtom ,4 );
+ strcpy_n1 ( &(S[60]),prevResName,3 );
+ if (prevChainID[0]) S[64] = prevChainID[0];
+ PutIntIns ( &(S[65]),prevResSeq ,4,prevICode );
+
+ }
+
+
+ void Strand::MakeCIF ( mmcif::PData CIF ) {
+ mmcif::PLoop Loop;
+ int RC;
+
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_RANGE,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_SHEET_ID );
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_BEG_LABEL_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_BEG_LABEL_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_BEG_LABEL_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB );
+ Loop->AddLoopTag ( CIFTAG_END_LABEL_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_END_LABEL_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_END_LABEL_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_END_LABEL_INS_CODE_PDB );
+ }
+ Loop->AddString ( sheetID );
+ Loop->AddInteger ( strandNo );
+ Loop->AddString ( initResName );
+ Loop->AddString ( initChainID );
+ Loop->AddInteger ( initSeqNum );
+ Loop->AddString ( initICode,true );
+ Loop->AddString ( endResName );
+ Loop->AddString ( endChainID );
+ Loop->AddInteger ( endSeqNum );
+ Loop->AddString ( endICode ,true );
+
+ }
+
+
+ ERROR_CODE Strand::ConvertPDBASCII ( cpstr S ) {
+
+ GetInteger ( strandNo ,&(S[7]) ,3 );
+ strcpy_ncss ( sheetID ,&(S[11]) ,3 );
+
+ strcpy_ncss ( initResName,&(S[17]) ,3 );
+ strcpy_ncss ( initChainID,&(S[21]) ,1 );
+ GetIntIns ( initSeqNum ,initICode,&(S[22]),4 );
+
+ strcpy_ncss ( endResName ,&(S[28]) ,3 );
+ strcpy_ncss ( endChainID ,&(S[32]) ,1 );
+ GetIntIns ( endSeqNum ,endICode ,&(S[33]),4 );
+
+ GetInteger ( sense ,&(S[38]) ,2 );
+
+ GetString ( curAtom ,&(S[41]) ,4 );
+ strcpy_ncss ( curResName ,&(S[45]) ,3 );
+ strcpy_ncss ( curChainID ,&(S[49]) ,1 );
+ GetIntIns ( curResSeq ,curICode ,&(S[50]),4 );
+
+ GetString ( prevAtom ,&(S[56]) ,4 );
+ strcpy_ncss ( prevResName,&(S[60]) ,3 );
+ strcpy_ncss ( prevChainID,&(S[64]) ,1 );
+ GetIntIns ( prevResSeq ,prevICode,&(S[65]),4 );
+
+ return Error_NoError;
+
+ }
+
+ int Strand::GetCIF ( mmcif::PData CIF, cpstr sheet_id ) {
+ mmcif::PLoop Loop;
+ int RC,l,i,sNo;
+ pstr F;
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_RANGE );
+ if (Loop) {
+ l = Loop->GetLoopLength();
+ i = 0;
+ while (i<l) {
+ F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+ if (F && (!RC)) {
+ if (!strcmp(F,sheet_id)) {
+ strcpy ( sheetID,sheet_id );
+ if (CIFGetInteger(sNo,Loop,CIFTAG_ID,i)) return i;
+ if (sNo==strandNo) {
+ CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
+ i,sizeof(initResName),pstr(" ") );
+ CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
+ i,sizeof(initChainID),pstr("") );
+ CIFGetString ( initICode,Loop,
+ CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
+ i,sizeof(initICode),pstr("") );
+ if (CIFGetInteger(initSeqNum,Loop,
+ CIFTAG_BEG_LABEL_SEQ_ID,i))
+ return i;
+ CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
+ i,sizeof(endResName),pstr(" ") );
+ CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
+ i,sizeof(endChainID),pstr("") );
+ CIFGetString ( endICode ,Loop,
+ CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
+ i,sizeof(endICode),pstr("") );
+ if (CIFGetInteger(endSeqNum,Loop,
+ CIFTAG_END_LABEL_SEQ_ID,i))
+ return i;
+ Loop->DeleteRow ( i );
+ i = l+100; // break the loop
+ }
+ }
+ }
+ i++;
+ }
+ }
+
+ return 0;
+
+ }
+
+ void Strand::Copy ( PStrand Strand ) {
+ initSeqNum = Strand->initSeqNum;
+ endSeqNum = Strand->endSeqNum;
+ sense = Strand->sense;
+ curResSeq = Strand->curResSeq;
+ prevResSeq = Strand->prevResSeq;
+ strcpy ( initResName,Strand->initResName );
+ strcpy ( initChainID,Strand->initChainID );
+ strcpy ( initICode ,Strand->initICode );
+ strcpy ( endResName ,Strand->endResName );
+ strcpy ( endChainID ,Strand->endChainID );
+ strcpy ( endICode ,Strand->endICode );
+ strcpy ( curAtom ,Strand->curAtom );
+ strcpy ( curResName ,Strand->curResName );
+ strcpy ( curChainID ,Strand->curChainID );
+ strcpy ( curICode ,Strand->curICode );
+ strcpy ( prevAtom ,Strand->prevAtom );
+ strcpy ( prevResName,Strand->prevResName );
+ strcpy ( prevChainID,Strand->prevChainID );
+ strcpy ( prevICode ,Strand->prevICode );
+ }
+
+ void Strand::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &initSeqNum );
+ f.WriteInt ( &endSeqNum );
+ f.WriteInt ( &sense );
+ f.WriteInt ( &curResSeq );
+ f.WriteInt ( &prevResSeq );
+ f.WriteTerLine ( initResName,false );
+ f.WriteTerLine ( initChainID,false );
+ f.WriteTerLine ( initICode ,false );
+ f.WriteTerLine ( endResName ,false );
+ f.WriteTerLine ( endChainID ,false );
+ f.WriteTerLine ( endICode ,false );
+ f.WriteTerLine ( curAtom ,false );
+ f.WriteTerLine ( curResName ,false );
+ f.WriteTerLine ( curChainID ,false );
+ f.WriteTerLine ( curICode ,false );
+ f.WriteTerLine ( prevAtom ,false );
+ f.WriteTerLine ( prevResName,false );
+ f.WriteTerLine ( prevChainID,false );
+ f.WriteTerLine ( prevICode ,false );
+ }
+
+ void Strand::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &initSeqNum );
+ f.ReadInt ( &endSeqNum );
+ f.ReadInt ( &sense );
+ f.ReadInt ( &curResSeq );
+ f.ReadInt ( &prevResSeq );
+ f.ReadTerLine ( initResName,false );
+ f.ReadTerLine ( initChainID,false );
+ f.ReadTerLine ( initICode ,false );
+ f.ReadTerLine ( endResName ,false );
+ f.ReadTerLine ( endChainID ,false );
+ f.ReadTerLine ( endICode ,false );
+ f.ReadTerLine ( curAtom ,false );
+ f.ReadTerLine ( curResName ,false );
+ f.ReadTerLine ( curChainID ,false );
+ f.ReadTerLine ( curICode ,false );
+ f.ReadTerLine ( prevAtom ,false );
+ f.ReadTerLine ( prevResName,false );
+ f.ReadTerLine ( prevChainID,false );
+ f.ReadTerLine ( prevICode ,false );
+ }
+
+ MakeStreamFunctions(Strand)
+
+
+
+
+ // ================ Sheet ===================
+
+ Sheet::Sheet() : io::Stream() {
+ InitSheet();
+ }
+
+ Sheet::Sheet ( io::RPStream Object ) : io::Stream(Object) {
+ InitSheet();
+ }
+
+ Sheet::~Sheet() {
+ FreeMemory();
+ }
+
+ void Sheet::InitSheet() {
+ nStrands = 0;
+ sheetID[0] = char(0);
+ strand = NULL;
+ }
+
+ void Sheet::FreeMemory() {
+ int i;
+ if (strand) {
+ for (i=0;i<nStrands;i++)
+ if (strand[i]) delete strand[i];
+ delete[] strand;
+ strand = NULL;
+ }
+ nStrands = 0;
+ sheetID[0] = char(0);
+ }
+
+ void Sheet::PDBASCIIDump ( io::RFile f ) {
+ char S[100];
+ int i;
+ if (strand)
+ for (i=0;i<nStrands;i++)
+ if (strand[i]) {
+ strcpy ( S,"SHEET" );
+ PadSpaces ( S,80 );
+ PutInteger ( &(S[7]) ,i+1 ,3 );
+ strcpy_n1 ( &(S[11]),sheetID ,3 );
+ PutInteger ( &(S[14]),nStrands,2 );
+ strand[i]->PDBASCIIDump ( S );
+ f.WriteLine ( S );
+ }
+ }
+
+ void Sheet::OrderSheet() {
+ int i,k;
+ PPStrand strand1;
+ k = 0;
+ for (i=0;i<nStrands;i++)
+ if (strand[i]) k++;
+ if (k<nStrands) {
+ strand1 = new PStrand[k];
+ k = 0;
+ for (i=0;i<nStrands;i++)
+ if (strand[i]) strand1[k++] = strand[i];
+ if (strand) delete[] strand;
+ strand = strand1;
+ nStrands = k;
+ }
+ }
+
+ void Sheet::MakeCIF ( mmcif::PData CIF ) {
+ mmcif::PLoop Loop;
+ int RC;
+ int i;
+ bool isSense;
+
+ OrderSheet();
+
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_SHEET_ID );
+ Loop->AddLoopTag ( CIFTAG_NUMBER_STRANDS );
+ }
+ Loop->AddString ( sheetID );
+ Loop->AddInteger ( nStrands );
+
+ for (i=0;i<nStrands;i++) {
+ strand[i]->MakeCIF ( CIF );
+ if (strand[i]->sense!=0) isSense = true;
+ }
+
+ if (nStrands>1) {
+
+ if (isSense) {
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_ORDER,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_SHEET_ID );
+ Loop->AddLoopTag ( CIFTAG_RANGE_ID_1 );
+ Loop->AddLoopTag ( CIFTAG_RANGE_ID_2 );
+ Loop->AddLoopTag ( CIFTAG_SENSE );
+ }
+ for (i=1;i<nStrands;i++) {
+ Loop->AddString ( sheetID );
+ Loop->AddInteger ( strand[i-1]->strandNo );
+ Loop->AddInteger ( strand[i] ->strandNo );
+ if (strand[i]->sense>0)
+ Loop->AddString ( pstr("parallel") );
+ else Loop->AddString ( pstr("anti-parallel") );
+ }
+ }
+
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_HBOND,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_SHEET_ID );
+ Loop->AddLoopTag ( CIFTAG_RANGE_ID_1 );
+ Loop->AddLoopTag ( CIFTAG_RANGE_ID_2 );
+ Loop->AddLoopTag ( CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE );
+ Loop->AddLoopTag ( CIFTAG_RANGE_1_END_LABEL_ATOM_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_RANGE_1_END_LABEL_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE );
+ }
+ for (i=1;i<nStrands;i++) {
+ Loop->AddString ( sheetID );
+ Loop->AddInteger ( strand[i-1]->strandNo );
+ Loop->AddInteger ( strand[i]->strandNo );
+ Loop->AddString ( strand[i]->curAtom );
+ Loop->AddString ( strand[i]->curResName );
+ Loop->AddString ( strand[i]->curChainID );
+ Loop->AddInteger ( strand[i]->curResSeq );
+ Loop->AddString ( strand[i]->curICode ,true );
+ Loop->AddString ( strand[i]->prevAtom );
+ Loop->AddString ( strand[i]->prevResName );
+ Loop->AddString ( strand[i]->prevChainID );
+ Loop->AddInteger ( strand[i]->prevResSeq );
+ Loop->AddString ( strand[i]->prevICode,true );
+ }
+ }
+
+ }
+
+
+ ERROR_CODE Sheet::ConvertPDBASCII ( cpstr S ) {
+ int i,k,ns;
+ SheetID SID;
+ PPStrand strand1;
+
+ GetInteger ( k ,&(S[7]) ,3 );
+ strcpy_ncss ( SID,&(S[11]),3 );
+ GetInteger ( ns ,&(S[14]),2 );
+
+ // if (!SID[0]) return Error_NoSheetID;
+ if (!sheetID[0]) strcpy ( sheetID,SID );
+ else if (strcmp(sheetID,SID))
+ return Error_WrongSheetID;
+
+ if (k<=0) return Error_WrongStrandNo;
+
+ ns = IMax(k,ns);
+ if (!strand) {
+ strand = new PStrand[ns];
+ for (i=0;i<ns;i++)
+ strand[i] = NULL;
+ } else if (ns>nStrands) {
+ strand1 = new PStrand[ns];
+ for (i=0;i<nStrands;i++)
+ strand1[i] = strand[i];
+ for (i=nStrands;i<ns;i++)
+ strand1[i] = NULL;
+ if (strand) delete[] strand;
+ strand = strand1;
+ }
+ nStrands = ns;
+
+ k--;
+ if (!strand[k]) strand[k] = new Strand();
+
+ return strand[k]->ConvertPDBASCII ( S );
+
+ }
+
+ void Sheet::TryStrand ( int strand_no ) {
+ int i,k;
+ PPStrand strand1;
+ k = -1;
+ for (i=0;(i<nStrands) && (k<0);i++)
+ if (strand[i])
+ if (strand[i]->strandNo==strand_no) k = i;
+ if (k<0) {
+ strand1 = new PStrand[nStrands+1];
+ for (i=0;i<nStrands;i++)
+ strand1[i] = strand[i];
+ if (strand) delete[] strand;
+ strand = strand1;
+ strand[nStrands] = new Strand();
+ strand[nStrands]->strandNo = strand_no;
+ nStrands++;
+ }
+ }
+
+
+ void Sheet::CIFFindStrands ( mmcif::PData CIF, cpstr Category ) {
+ // just look for all strands mentioned for the sheet
+ mmcif::PLoop Loop;
+ pstr F;
+ int RC,i,l,sNo;
+ Loop = CIF->GetLoop ( Category );
+ if (Loop) {
+ l = Loop->GetLoopLength();
+ for (i=0;i<l;i++) {
+ F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+ if (F && (!RC)) {
+ if (!strcmp(F,sheetID)) {
+ if (!Loop->GetInteger(sNo,CIFTAG_ID,i))
+ TryStrand ( sNo );
+ if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))
+ TryStrand ( sNo );
+ if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_2,i))
+ TryStrand ( sNo );
+ }
+ }
+ }
+ }
+ }
+
+ int Sheet::GetStrand ( int strand_no ) {
+ int i;
+ for (i=0;i<nStrands;i++)
+ if (strand[i]) {
+ if (strand[i]->strandNo==strand_no)
+ return i;
+ }
+ return -1;
+ }
+
+ int Sheet::GetCIF ( mmcif::PData CIF ) {
+ mmcif::PLoop Loop;
+ int i,ns,l,k,k2,RC,sNo;
+ pstr F;
+ ivector pair;
+ bool Ok;
+
+ pair = NULL;
+
+ // First find all strands and create
+ // the corresponding classes. The CIF fields
+ // are not removed at this stage.
+
+ CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_ORDER );
+ CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_RANGE );
+ CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_HBOND );
+
+ // Check number of strands
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET );
+ if (Loop) {
+ l = Loop->GetLoopLength();
+ i = 0;
+ while (i<l) {
+ F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+ if (F && (!RC)) {
+ if (!strcmp(F,sheetID)) {
+ RC = CIFGetInteger1 ( ns,Loop,CIFTAG_NUMBER_STRANDS,i );
+ if ((!RC) && (ns!=nStrands))
+ return Error_WrongNumberOfStrands;
+ Loop->DeleteRow ( i );
+ i = l+100; // break loop
+ }
+ }
+ i++;
+ }
+ }
+
+ // Read each strand
+ RC = 0;
+ for (i=0;(i<nStrands) && (!RC);i++)
+ RC = strand[i]->GetCIF ( CIF,sheetID );
+
+ if (RC) return RC;
+
+ if (nStrands>1) {
+
+ GetVectorMemory ( pair,nStrands,0 );
+ for (i=0;i<nStrands;i++)
+ pair[i] = -1;
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_ORDER );
+ if (Loop) {
+ Ok = true;
+ l = Loop->GetLoopLength();
+ for (i=0;(i<l) && Ok;i++) {
+ F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+ if (F && (!RC)) {
+ if (!strcmp(F,sheetID)) {
+ if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i)) {
+ k = GetStrand ( sNo );
+ if ((k>=0) &&
+ (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_2,i))) {
+ pair[k] = GetStrand ( sNo );
+ if (pair[k]>=0) {
+ F = Loop->GetString ( CIFTAG_SENSE,i,RC );
+ if (F && (!RC)) {
+ if (!strcasecmp(F,"anti-parallel"))
+ strand[pair[k]]->sense = -1;
+ else if (!strcasecmp(F,"parallel"))
+ strand[pair[k]]->sense = 1;
+ }
+ Loop->DeleteRow ( i );
+ } else
+ Ok = false;
+ } else
+ Ok = false;
+ } else
+ Ok = false;
+ }
+ }
+ }
+ if (!Ok) {
+ FreeVectorMemory ( pair,0 );
+ return Error_WrongSheetOrder;
+ }
+ }
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_HBOND );
+ if (Loop) {
+ Ok = true;
+ l = Loop->GetLoopLength();
+ for (i=0;(i<l) && Ok;i++) {
+ F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+ if (F && (!RC)) {
+ if (!strcmp(F,sheetID)) {
+ if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i)) {
+ k = GetStrand ( sNo );
+ if ((k>=0) &&
+ (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))) {
+ k2 = GetStrand ( sNo );
+ if (k2>=0) {
+ if (pair[k]==k2) {
+ CIFGetString ( strand[k2]->curAtom,Loop,
+ CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID,
+ i,sizeof(strand[k2]->curAtom),
+ pstr(" ") );
+ CIFGetString ( strand[k2]->curResName,Loop,
+ CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID,
+ i,sizeof(strand[k2]->curResName),
+ pstr(" ") );
+ CIFGetString ( strand[k2]->curChainID,Loop,
+ CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID,
+ i,sizeof(strand[k2]->curChainID),
+ pstr(" ") );
+ if (CIFGetInteger(strand[k2]->curResSeq,Loop,
+ CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID,i)) {
+ FreeVectorMemory ( pair,0 );
+ return i;
+ }
+ CIFGetString ( strand[k2]->curICode,Loop,
+ CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE,
+ i,sizeof(strand[k2]->curICode),
+ pstr(" ") );
+ CIFGetString ( strand[k2]->prevAtom,Loop,
+ CIFTAG_RANGE_1_END_LABEL_ATOM_ID,
+ i,sizeof(strand[k2]->prevAtom),
+ pstr(" ") );
+ CIFGetString ( strand[k2]->prevResName,Loop,
+ CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID,
+ i,sizeof(strand[k2]->prevResName),
+ pstr(" ") );
+ CIFGetString ( strand[k2]->prevChainID,Loop,
+ CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID,
+ i,sizeof(strand[k2]->prevChainID),
+ pstr(" ") );
+ if (CIFGetInteger(strand[k2]->prevResSeq,Loop,
+ CIFTAG_RANGE_1_END_LABEL_SEQ_ID,i)) {
+ FreeVectorMemory ( pair,0 );
+ return i;
+ }
+ CIFGetString ( strand[k2]->prevICode,Loop,
+ CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE,
+ i,sizeof(strand[k2]->prevICode),
+ pstr(" ") );
+ Loop->DeleteRow ( i );
+ } else
+ Ok = false;
+ } else
+ Ok = false;
+ } else
+ Ok = false;
+ } else
+ Ok = false;
+ }
+ }
+ }
+ if (!Ok) {
+ FreeVectorMemory ( pair,0 );
+ return Error_HBondInconsistency;
+ }
+ }
+ }
+
+ FreeVectorMemory ( pair,0 );
+
+ return 0;
+
+ }
+
+
+ void Sheet::Copy ( PSheet Sheet ) {
+ int i;
+ FreeMemory();
+ nStrands = Sheet->nStrands;
+ if (nStrands>0) {
+ strand = new PStrand[nStrands];
+ for (i=0;i<nStrands;i++)
+ if (Sheet->strand[i]) {
+ strand[i] = new Strand();
+ strand[i]->Copy ( Sheet->strand[i] );
+ } else
+ strand[i] = NULL;
+ }
+ strcpy ( sheetID,Sheet->sheetID );
+ }
+
+ void Sheet::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &nStrands );
+ for (i=0;i<nStrands;i++)
+ StreamWrite ( f,strand[i] );
+ f.WriteTerLine ( sheetID,false );
+ }
+
+ void Sheet::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ FreeMemory();
+ f.ReadByte ( &Version );
+ f.ReadInt ( &nStrands );
+ if (nStrands>0) {
+ strand = new PStrand[nStrands];
+ for (i=0;i<nStrands;i++) {
+ strand[i] = NULL;
+ StreamRead ( f,strand[i] );
+ }
+ }
+ f.ReadTerLine ( sheetID,false );
+ }
+
+ MakeStreamFunctions(Sheet)
+
+
+
+ // ==================== Sheets ============================
+
+
+ Sheets::Sheets() : io::Stream() {
+ InitSheets();
+ }
+
+
+ Sheets::Sheets ( io::RPStream Object ) : io::Stream ( Object ) {
+ InitSheets();
+ }
+
+
+ Sheets::~Sheets() {
+ FreeMemory();
+ }
+
+
+ void Sheets::InitSheets() {
+ nSheets = 0;
+ sheet = NULL;
+ }
+
+
+ void Sheets::FreeMemory() {
+ int i;
+ if (sheet) {
+ for (i=0;i<nSheets;i++)
+ if (sheet[i]) delete sheet[i];
+ delete[] sheet;
+ sheet = NULL;
+ }
+ nSheets = 0;
+ }
+
+
+ void Sheets::PDBASCIIDump ( io::RFile f ) {
+ int i;
+ if (sheet)
+ for (i=0;i<nSheets;i++)
+ if (sheet[i]) sheet[i]->PDBASCIIDump ( f );
+ }
+
+
+ void Sheets::MakeCIF ( mmcif::PData CIF ) {
+ int i;
+ if (sheet)
+ for (i=0;i<nSheets;i++)
+ if (sheet[i]) sheet[i]->MakeCIF ( CIF );
+ }
+
+
+ ERROR_CODE Sheets::ConvertPDBASCII ( cpstr S ) {
+ PPSheet sheet1;
+ SheetID sheetID;
+ int i,k;
+ strcpy_ncss ( sheetID,&(S[11]),3 );
+ // if (!sheetID[0]) return Error_NoSheetID;
+ k = -1;
+ for (i=0;i<nSheets;i++)
+ if (sheet[i]) {
+ if (!strcmp(sheetID,sheet[i]->sheetID)) {
+ k = i;
+ break;
+ }
+ }
+ if (k<0) {
+ sheet1 = new PSheet[nSheets+1];
+ for (i=0;i<nSheets;i++)
+ sheet1[i] = sheet[i];
+ if (sheet) delete[] sheet;
+ sheet = sheet1;
+ sheet[nSheets] = new Sheet();
+ k = nSheets;
+ nSheets++;
+ }
+ return sheet[k]->ConvertPDBASCII ( S );
+ }
+
+
+ void Sheets::CIFFindSheets ( mmcif::PData CIF, cpstr Category ) {
+ mmcif::PLoop Loop;
+ int RC,i,j,k,l;
+ pstr F;
+ PPSheet sheet1;
+ Loop = CIF->GetLoop ( Category );
+ if (Loop) {
+ l = Loop->GetLoopLength();
+ for (i=0;i<l;i++) {
+ F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+ if (F && (!RC)) {
+ k = -1;
+ j = 0;
+ while ((j<nSheets) && (k<0)) {
+ if (sheet[j]) {
+ if (!strcmp(F,sheet[j]->sheetID)) k = j;
+ }
+ j++;
+ }
+ if (k<0) {
+ sheet1 = new PSheet[nSheets+1];
+ for (i=0;i<nSheets;i++)
+ sheet1[i] = sheet[i];
+ if (sheet) delete[] sheet;
+ sheet = sheet1;
+ sheet[nSheets] = new Sheet();
+ strcpy ( sheet[nSheets]->sheetID,F );
+ nSheets++;
+ }
+ }
+ }
+ }
+ }
+
+ int Sheets::GetCIF ( mmcif::PData CIF ) {
+ int i,RC;
+
+ FreeMemory();
+
+ // First find all sheet names and create
+ // the corresponding classes. The CIF fields
+ // are not removed at this stage.
+
+ CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET );
+ CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_ORDER );
+ CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_RANGE );
+ CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_HBOND );
+
+ // Read each sheet
+ i = 0;
+ RC = 0;
+ while ((i<nSheets) && (!RC)) {
+ RC = sheet[i]->GetCIF ( CIF );
+ i++;
+ }
+
+ return RC;
+
+ }
+
+
+ void Sheets::Copy ( PSheets Sheets ) {
+ int i;
+ FreeMemory();
+ if (Sheets->nSheets>0) {
+ nSheets = Sheets->nSheets;
+ sheet = new PSheet[nSheets];
+ for (i=0;i<nSheets;i++)
+ if (Sheets->sheet[i]) {
+ sheet[i] = new Sheet();
+ sheet[i]->Copy ( Sheets->sheet[i] );
+ } else
+ sheet[i] = NULL;
+ }
+ }
+
+
+ void Sheets::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &nSheets );
+ for (i=0;i<nSheets;i++)
+ StreamWrite ( f,sheet[i] );
+ }
+
+
+ void Sheets::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ FreeMemory();
+ f.ReadByte ( &Version );
+ f.ReadInt ( &nSheets );
+ if (nSheets>0) {
+ sheet = new PSheet[nSheets];
+ for (i=0;i<nSheets;i++) {
+ sheet[i] = NULL;
+ StreamRead ( f,sheet[i] );
+ }
+ }
+ }
+
+
+ MakeStreamFunctions(Sheets)
+
+
+
+ // ================ Turn ===================
+
+ Turn::Turn() : ContainerClass() {
+ InitTurn();
+ }
+
+ Turn::Turn ( cpstr S ) : ContainerClass() {
+ InitTurn();
+ ConvertPDBASCII ( S );
+ }
+
+ Turn::Turn ( io::RPStream Object ) : ContainerClass(Object) {
+ InitTurn();
+ }
+
+ Turn::~Turn() {
+ if (comment) delete[] comment;
+ }
+
+ void Turn::InitTurn() {
+ serNum = 0; // serial number
+ strcpy ( turnID ,"---" ); // turn ID
+ strcpy ( initResName,"---" ); // name of the turn's initial residue
+ strcpy ( initChainID," " ); // chain ID for the chain
+ // containing the turn
+ initSeqNum = 0; // sequence number of the initial
+ // residue
+ strcpy ( initICode ," " ); // insertion code of the initial
+ // residue
+ strcpy ( endResName ,"---" ); // name of the turn's terminal residue
+ strcpy ( endChainID ," " ); // chain ID for the chain
+ // containing the turn
+ endSeqNum = 0; // sequence number of the terminal
+ // residue
+ strcpy ( endICode ," " ); // insertion code of the terminal
+ // residue
+ comment = NULL; // comment about the helix
+ }
+
+ void Turn::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+ // makes the ASCII PDB OBSLTE line number N
+ // from the class' data
+ strcpy ( S,"TURN" );
+ PadSpaces ( S,80 );
+ PutInteger ( &(S[7]) ,serNum ,3 );
+ strcpy_n1 ( &(S[11]),turnID ,3 );
+ strcpy_n1 ( &(S[15]),initResName,3 );
+ strcpy_n1 ( &(S[19]),initChainID,1 );
+ PutIntIns ( &(S[20]),initSeqNum ,4,initICode );
+ strcpy_n1 ( &(S[26]),endResName ,3 );
+ strcpy_n1 ( &(S[30]),endChainID ,1 );
+ PutIntIns ( &(S[31]),endSeqNum ,4,endICode );
+ if (comment)
+ strcpy_n ( &(S[40]),comment ,30 );
+ }
+
+
+ #define TurnTypeID "TURN_P"
+
+ void Turn::MakeCIF ( mmcif::PData CIF, int N ) {
+ UNUSED_ARGUMENT(N);
+ mmcif::PLoop Loop;
+ int RC;
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_CONF,Loop );
+ if (RC!=mmcif::CIFRC_Ok)
+ // the category was (re)created, provide tags
+ AddStructConfTags ( Loop );
+ Loop->AddString ( pstr(TurnTypeID) );
+ Loop->AddInteger ( serNum );
+ Loop->AddString ( turnID );
+ Loop->AddString ( initResName );
+ Loop->AddString ( initChainID );
+ Loop->AddInteger ( initSeqNum );
+ Loop->AddString ( initICode,true );
+ Loop->AddString ( endResName );
+ Loop->AddString ( endChainID );
+ Loop->AddInteger ( endSeqNum );
+ Loop->AddString ( endICode ,true );
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+ Loop->AddString ( comment );
+ Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+ }
+
+ ERROR_CODE Turn::ConvertPDBASCII ( cpstr S ) {
+ char L[100];
+ GetInteger ( serNum ,&(S[7]) ,3 );
+ strcpy_ncss ( turnID ,&(S[11]),3 );
+ strcpy_ncss ( initResName,&(S[15]),3 );
+ strcpy_ncss ( initChainID,&(S[19]),1 );
+ GetIntIns ( initSeqNum,initICode,&(S[20]),4 );
+ strcpy_ncss ( endResName ,&(S[26]),3 );
+ strcpy_ncss ( endChainID ,&(S[30]),1 );
+ GetIntIns ( endSeqNum ,endICode ,&(S[31]),4 );
+ strcpy_ncss ( L ,&(S[40]),30 );
+ CreateCopy ( comment ,L );
+ return Error_NoError;
+ }
+
+ ERROR_CODE Turn::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ int RC,l;
+ pstr F;
+ bool Done;
+ ERROR_CODE rc;
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONF );
+ if (!Loop) {
+ n = -1; // signal to finish processing of this structure
+ return Error_EmptyCIF;
+ }
+
+ l = Loop->GetLoopLength();
+ Done = n>=l;
+ while (!Done) {
+ F = Loop->GetString ( CIFTAG_CONF_TYPE_ID,n,RC );
+ if ((!RC) && F) Done = (strcmp(F,TurnTypeID)==0);
+ else Done = false;
+ if (!Done) {
+ n++;
+ Done = n>=l;
+ }
+ }
+
+ if (n>=l) {
+ n = -1; // finish processing of Turn
+ return Error_EmptyCIF;
+ }
+
+ Loop->DeleteField ( CIFTAG_CONF_TYPE_ID,n );
+
+ rc = CIFGetInteger ( serNum,Loop,CIFTAG_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( turnID,Loop,CIFTAG_PDB_ID,n,
+ sizeof(turnID),pstr(" ") );
+
+ CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
+ n,sizeof(initResName),pstr(" ") );
+ CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
+ n,sizeof(initChainID),pstr(" ") );
+ CIFGetString ( initICode ,Loop,CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
+ n,sizeof(initICode),pstr(" ") );
+ rc = CIFGetInteger ( initSeqNum,Loop,CIFTAG_BEG_LABEL_SEQ_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
+ n,sizeof(endResName),pstr(" ") );
+ CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
+ n,sizeof(endChainID),pstr(" ") );
+ CIFGetString ( endICode ,Loop,CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
+ n,sizeof(endICode),pstr(" ") );
+ rc = CIFGetInteger ( endSeqNum,Loop,CIFTAG_END_LABEL_SEQ_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CreateCopy ( comment,Loop->GetString(CIFTAG_DETAILS,n,RC));
+ Loop->DeleteField ( CIFTAG_DETAILS,n );
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+ void Turn::Copy ( PContainerClass Turn ) {
+ serNum = PTurn(Turn)->serNum;
+ initSeqNum = PTurn(Turn)->initSeqNum;
+ endSeqNum = PTurn(Turn)->endSeqNum;
+ strcpy ( turnID ,PTurn(Turn)->turnID );
+ strcpy ( initResName,PTurn(Turn)->initResName );
+ strcpy ( initChainID,PTurn(Turn)->initChainID );
+ strcpy ( initICode ,PTurn(Turn)->initICode );
+ strcpy ( endResName ,PTurn(Turn)->endResName );
+ strcpy ( endChainID ,PTurn(Turn)->endChainID );
+ strcpy ( endICode ,PTurn(Turn)->endICode );
+ CreateCopy ( comment,PTurn(Turn)->comment );
+ }
+
+ void Turn::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &serNum );
+ f.WriteInt ( &initSeqNum );
+ f.WriteInt ( &endSeqNum );
+ f.WriteTerLine ( turnID ,false );
+ f.WriteTerLine ( initResName,false );
+ f.WriteTerLine ( initChainID,false );
+ f.WriteTerLine ( initICode ,false );
+ f.WriteTerLine ( endResName ,false );
+ f.WriteTerLine ( endChainID ,false );
+ f.WriteTerLine ( endICode ,false );
+ f.CreateWrite ( comment );
+ }
+
+ void Turn::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &serNum );
+ f.ReadInt ( &initSeqNum );
+ f.ReadInt ( &endSeqNum );
+ f.ReadTerLine ( turnID ,false );
+ f.ReadTerLine ( initResName,false );
+ f.ReadTerLine ( initChainID,false );
+ f.ReadTerLine ( initICode ,false );
+ f.ReadTerLine ( endResName ,false );
+ f.ReadTerLine ( endChainID ,false );
+ f.ReadTerLine ( endICode ,false );
+ f.CreateRead ( comment );
+ }
+
+ MakeStreamFunctions(Turn)
+
+
+ // =================== LinkContainer ========================
+
+ PContainerClass LinkContainer::MakeContainerClass ( int ClassID ) {
+ switch (ClassID) {
+ default :
+ case ClassID_Template : return
+ ClassContainer::MakeContainerClass(ClassID);
+ case ClassID_Link : return new Link();
+ }
+ }
+
+ MakeStreamFunctions(LinkContainer)
+
+
+
+ // ======================== Link ===========================
+
+ Link::Link() : ContainerClass() {
+ InitLink();
+ }
+
+ Link::Link ( cpstr S ) : ContainerClass() {
+ InitLink();
+ ConvertPDBASCII ( S );
+ }
+
+ Link::Link ( io::RPStream Object ) : ContainerClass(Object) {
+ InitLink();
+ }
+
+ Link::~Link() {}
+
+ void Link::InitLink() {
+ strcpy ( atName1 ,"----" ); // name of 1st linked atom
+ strcpy ( aloc1 ," " ); // alternative location of 1st atom
+ strcpy ( resName1,"---" ); // residue name of 1st linked atom
+ strcpy ( chainID1," " ); // chain ID of 1st linked atom
+ seqNum1 = 0; // sequence number of 1st linked atom
+ strcpy ( insCode1," " ); // insertion code of 1st linked atom
+ strcpy ( atName2 ,"----" ); // name of 2nd linked atom
+ strcpy ( aloc2 ," " ); // alternative location of 2nd atom
+ strcpy ( resName2,"---" ); // residue name of 2nd linked atom
+ strcpy ( chainID2," " ); // chain ID of 2nd linked atom
+ seqNum2 = 0; // sequence number of 2nd linked atom
+ strcpy ( insCode2," " ); // insertion code of 2nd linked atom
+ s1 = 1; // sym id of 1st atom
+ i1 = 5;
+ j1 = 5;
+ k1 = 5;
+ s2 = 1; // sym id of 2nd atom
+ i2 = 5;
+ j2 = 5;
+ k2 = 5;
+ }
+
+
+ void Link::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+ // makes the ASCII PDB OBSLTE line number N
+ // from the class' data
+
+ strcpy ( S,"LINK" );
+ PadSpaces ( S,80 );
+
+ strcpy_n1 ( &(S[12]),atName1 ,4 );
+ strcpy_n1 ( &(S[16]),aloc1 ,1 );
+ strcpy_n1 ( &(S[17]),resName1,3 );
+ strcpy_n1 ( &(S[21]),chainID1,1 );
+ PutIntIns ( &(S[22]),seqNum1 ,4,insCode1 );
+
+ strcpy_n1 ( &(S[42]),atName2 ,4 );
+ strcpy_n1 ( &(S[46]),aloc2 ,1 );
+ strcpy_n1 ( &(S[47]),resName2,3 );
+ strcpy_n1 ( &(S[51]),chainID2,1 );
+ PutIntIns ( &(S[52]),seqNum2 ,4,insCode2 );
+
+ PutInteger ( &(S[59]),s1,3 );
+ PutInteger ( &(S[62]),i1,1 );
+ PutInteger ( &(S[63]),j1,1 );
+ PutInteger ( &(S[64]),k1,1 );
+
+ PutInteger ( &(S[66]),s2,3 );
+ PutInteger ( &(S[69]),i2,1 );
+ PutInteger ( &(S[70]),j2,1 );
+ PutInteger ( &(S[71]),k2,1 );
+
+ }
+
+
+ #define LinkTypeID "LINK"
+
+ void AddStructConnTags ( mmcif::PLoop Loop ) {
+
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID );
+
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ATOM_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE );
+
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ATOM_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE );
+
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_SYMMETRY );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_SYMMETRY );
+
+ }
+
+
+ void Link::MakeCIF ( mmcif::PData CIF, int N ) {
+ UNUSED_ARGUMENT(N);
+ mmcif::PLoop Loop;
+ char S[100];
+ int RC;
+
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_CONN,Loop );
+ if (RC!=mmcif::CIFRC_Ok) // the category was (re)created, provide tags
+ AddStructConnTags ( Loop );
+
+ Loop->AddString ( "1" ); // should be a counter
+ Loop->AddString ( pstr(LinkTypeID) );
+
+ Loop->AddString ( atName1 );
+ Loop->AddString ( aloc1 );
+ Loop->AddString ( resName1 );
+ Loop->AddString ( chainID1 );
+ Loop->AddInteger ( seqNum1 );
+ Loop->AddString ( insCode1 );
+
+ Loop->AddString ( atName2 );
+ Loop->AddString ( aloc2 );
+ Loop->AddString ( resName2 );
+ Loop->AddString ( chainID2 );
+ Loop->AddInteger ( seqNum2 );
+ Loop->AddString ( insCode2 );
+
+ sprintf ( S,"%i%i%i%i",s1,i1,j1,k1 );
+ Loop->AddString ( S );
+ sprintf ( S,"%i%i%i%i",s2,i2,j2,k2 );
+ Loop->AddString ( S );
+
+ }
+
+ ERROR_CODE Link::ConvertPDBASCII ( cpstr S ) {
+
+ GetString ( atName1 ,&(S[12]),4 );
+ strcpy_ncss ( aloc1 ,&(S[16]),1 );
+ strcpy_ncss ( resName1,&(S[17]),3 );
+ strcpy_ncss ( chainID1,&(S[21]),1 );
+ GetIntIns ( seqNum1,insCode1,&(S[22]),4 );
+
+ GetString ( atName2 ,&(S[42]),4 );
+ strcpy_ncss ( aloc2 ,&(S[46]),1 );
+ strcpy_ncss ( resName2,&(S[47]),3 );
+ strcpy_ncss ( chainID2,&(S[51]),1 );
+ GetIntIns ( seqNum2,insCode2,&(S[52]),4 );
+
+ GetInteger ( s1,&(S[59]),3 );
+ GetInteger ( i1,&(S[62]),1 );
+ GetInteger ( j1,&(S[63]),1 );
+ GetInteger ( k1,&(S[64]),1 );
+
+ GetInteger ( s2,&(S[66]),3 );
+ GetInteger ( i2,&(S[69]),1 );
+ GetInteger ( j2,&(S[70]),1 );
+ GetInteger ( k2,&(S[71]),1 );
+
+ return Error_NoError;
+
+ }
+
+ ERROR_CODE Link::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ pstr F;
+ char S[100];
+ int RC,l;
+ bool Done;
+ ERROR_CODE rc;
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
+ if (!Loop) {
+ n = -1; // signal to finish processing of this structure
+ return Error_EmptyCIF;
+ }
+
+ l = Loop->GetLoopLength();
+ Done = (n>=l);
+ while (!Done) {
+ F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,n,RC );
+ if ((!RC) && F) Done = (strcmp(F,LinkTypeID)==0);
+ else Done = false;
+ if (!Done) {
+ n++;
+ Done = (n>=l);
+ }
+ }
+
+ if (n>=l) {
+ n = -1; // finish processing of Turn
+ return Error_EmptyCIF;
+ }
+
+ Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,n );
+
+ // CIFGetInteger ( l,Loop,CIFTAG_ID,n );
+
+ CIFGetString ( atName1,Loop,CIFTAG_CONN_PTNR1_AUTH_ATOM_ID,n,
+ sizeof(atName1),pstr(" ") );
+ CIFGetString ( aloc1,Loop,CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID,n,
+ sizeof(aloc1),pstr(" ") );
+ CIFGetString ( resName1,Loop,CIFTAG_CONN_PTNR1_AUTH_COMP_ID,n,
+ sizeof(resName1),pstr(" ") );
+ CIFGetString ( chainID1,Loop,CIFTAG_CONN_PTNR1_AUTH_ASYM_ID,n,
+ sizeof(chainID1),pstr(" ") );
+ rc = CIFGetInteger ( seqNum1,Loop,CIFTAG_CONN_PTNR1_AUTH_SEQ_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( insCode1,Loop,CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE,
+ n,sizeof(insCode1),pstr(" ") );
+
+ CIFGetString ( atName2,Loop,CIFTAG_CONN_PTNR2_AUTH_ATOM_ID,n,
+ sizeof(atName2),pstr(" ") );
+ CIFGetString ( aloc2,Loop,CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID,n,
+ sizeof(aloc2),pstr(" ") );
+ CIFGetString ( resName2,Loop,CIFTAG_CONN_PTNR2_AUTH_COMP_ID,n,
+ sizeof(resName2),pstr(" ") );
+ CIFGetString ( chainID2,Loop,CIFTAG_CONN_PTNR2_AUTH_ASYM_ID,n,
+ sizeof(chainID2),pstr(" ") );
+ rc = CIFGetInteger ( seqNum2,Loop,CIFTAG_CONN_PTNR2_AUTH_SEQ_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( insCode2,Loop,CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE,
+ n,sizeof(insCode2),pstr(" ") );
+
+ CIFGetString ( S,Loop,CIFTAG_CONN_PTNR1_SYMMETRY,n,
+ sizeof(S),pstr("") );
+ if (S[0]) {
+ l = strlen(S)-1;
+ k1 = int(S[l--]) - int('0');
+ j1 = int(S[l--]) - int('0');
+ i1 = int(S[l--]) - int('0');
+ S[l] = char(0);
+ s1 = atoi(S);
+ }
+
+ CIFGetString ( S,Loop,CIFTAG_CONN_PTNR2_SYMMETRY,n,
+ sizeof(S),pstr("") );
+ if (S[0]) {
+ l = strlen(S)-1;
+ k2 = int(S[l--]) - int('0');
+ j2 = int(S[l--]) - int('0');
+ i2 = int(S[l--]) - int('0');
+ S[l] = char(0);
+ s2 = atoi(S);
+ }
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+ void Link::Copy ( PContainerClass Link ) {
+
+ strcpy ( atName1 ,PLink(Link)->atName1 );
+ strcpy ( aloc1 ,PLink(Link)->aloc1 );
+ strcpy ( resName1,PLink(Link)->resName1 );
+ strcpy ( chainID1,PLink(Link)->chainID1 );
+ seqNum1 = PLink(Link)->seqNum1;
+ strcpy ( insCode1,PLink(Link)->insCode1 );
+
+ strcpy ( atName2 ,PLink(Link)->atName2 );
+ strcpy ( aloc2 ,PLink(Link)->aloc2 );
+ strcpy ( resName2,PLink(Link)->resName2 );
+ strcpy ( chainID2,PLink(Link)->chainID2 );
+ seqNum2 = PLink(Link)->seqNum2;
+ strcpy ( insCode2,PLink(Link)->insCode2 );
+
+ s1 = PLink(Link)->s1;
+ i1 = PLink(Link)->i1;
+ j1 = PLink(Link)->j1;
+ k1 = PLink(Link)->k1;
+
+ s2 = PLink(Link)->s2;
+ i2 = PLink(Link)->i2;
+ j2 = PLink(Link)->j2;
+ k2 = PLink(Link)->k2;
+
+ }
+
+ void Link::write ( io::RFile f ) {
+ byte Version=1;
+
+ f.WriteByte ( &Version );
+
+ f.WriteTerLine ( atName1 ,false );
+ f.WriteTerLine ( aloc1 ,false );
+ f.WriteTerLine ( resName1,false );
+ f.WriteTerLine ( chainID1,false );
+ f.WriteInt ( &seqNum1 );
+ f.WriteTerLine ( insCode1,false );
+
+ f.WriteTerLine ( atName2 ,false );
+ f.WriteTerLine ( aloc2 ,false );
+ f.WriteTerLine ( resName2,false );
+ f.WriteTerLine ( chainID2,false );
+ f.WriteInt ( &seqNum2 );
+ f.WriteTerLine ( insCode2,false );
+
+ f.WriteInt ( &s1 );
+ f.WriteInt ( &i1 );
+ f.WriteInt ( &j1 );
+ f.WriteInt ( &k1 );
+
+ f.WriteInt ( &s2 );
+ f.WriteInt ( &i2 );
+ f.WriteInt ( &j2 );
+ f.WriteInt ( &k2 );
+
+ }
+
+ void Link::read ( io::RFile f ) {
+ byte Version;
+
+ f.ReadByte ( &Version );
+
+ f.ReadTerLine ( atName1 ,false );
+ f.ReadTerLine ( aloc1 ,false );
+ f.ReadTerLine ( resName1,false );
+ f.ReadTerLine ( chainID1,false );
+ f.ReadInt ( &seqNum1 );
+ f.ReadTerLine ( insCode1,false );
+
+ f.ReadTerLine ( atName2 ,false );
+ f.ReadTerLine ( aloc2 ,false );
+ f.ReadTerLine ( resName2,false );
+ f.ReadTerLine ( chainID2,false );
+ f.ReadInt ( &seqNum2 );
+ f.ReadTerLine ( insCode2,false );
+
+ f.ReadInt ( &s1 );
+ f.ReadInt ( &i1 );
+ f.ReadInt ( &j1 );
+ f.ReadInt ( &k1 );
+
+ f.ReadInt ( &s2 );
+ f.ReadInt ( &i2 );
+ f.ReadInt ( &j2 );
+ f.ReadInt ( &k2 );
+
+ }
+
+ MakeStreamFunctions(Link)
+
+
+ // =================== LinkRContainer =======================
+
+ PContainerClass LinkRContainer::MakeContainerClass ( int ClassID ) {
+ switch (ClassID) {
+ default :
+ case ClassID_Template : return
+ ClassContainer::MakeContainerClass(ClassID);
+ case ClassID_LinkR : return new LinkR();
+ }
+ }
+
+ MakeStreamFunctions(LinkRContainer)
+
+
+ // ======================== LinkR ===========================
+
+ LinkR::LinkR() : ContainerClass() {
+ InitLinkR();
+ }
+
+ LinkR::LinkR ( cpstr S ) : ContainerClass() {
+ InitLinkR();
+ ConvertPDBASCII ( S );
+ }
+
+ LinkR::LinkR ( io::RPStream Object ) : ContainerClass(Object) {
+ InitLinkR();
+ }
+
+ LinkR::~LinkR() {}
+
+ void LinkR::InitLinkR() {
+ strcpy ( linkRID ,"----" ); // link name
+ strcpy ( atName1 ,"----" ); // name of 1st linked atom
+ strcpy ( aloc1 ," " ); // alternative location of 1st atom
+ strcpy ( resName1,"---" ); // residue name of 1st linked atom
+ strcpy ( chainID1," " ); // chain ID of 1st linked atom
+ seqNum1 = 0; // sequence number of 1st linked atom
+ strcpy ( insCode1," " ); // insertion code of 1st linked atom
+ strcpy ( atName2 ,"----" ); // name of 2nd linked atom
+ strcpy ( aloc2 ," " ); // alternative location of 2nd atom
+ strcpy ( resName2,"---" ); // residue name of 2nd linked atom
+ strcpy ( chainID2," " ); // chain ID of 2nd linked atom
+ seqNum2 = 0; // sequence number of 2nd linked atom
+ strcpy ( insCode2," " ); // insertion code of 2nd linked atom
+ dist = 0.0; // link distance
+ }
+
+ /*
+ LINK LYS A 27 PLP A 255 PLPLYS
+ LINK MAN S 3 MAN S 4 BETA1-4
+ LINK C6 BBEN B 1 O1 BMAF S 2 BEN-MAF
+ LINK OE2 AGLU A 320 C1 AMAF S 2 GLU-MAF
+ LINK OE2 GLU A 67 1.895 ZN ZN R 5 GLU-ZN
+ LINK NE2 HIS A 71 2.055 ZN ZN R 5 HIS-ZN
+ LINK O ARG A 69 2.240 NA NA R 9 ARG-NA
+ 012345678901234567890123456789012345678901234567890123456789012345678901234567890
+ 1 2 3 4 5 6 7
+ */
+
+ void LinkR::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+ // makes the ASCII PDB OBSLTE line number N
+ // from the class' data
+
+ strcpy ( S,"LINKR" );
+ PadSpaces ( S,80 );
+
+ strcpy_n1 ( &(S[12]),atName1 ,4 );
+ strcpy_n1 ( &(S[16]),aloc1 ,1 );
+ strcpy_n1 ( &(S[17]),resName1,3 );
+ strcpy_n1 ( &(S[21]),chainID1,1 );
+ PutIntIns ( &(S[22]),seqNum1 ,4,insCode1 );
+
+ if (dist>0.0)
+ PutRealF ( &(S[32]),dist,7,3 );
+
+ strcpy_n1 ( &(S[42]),atName2 ,4 );
+ strcpy_n1 ( &(S[46]),aloc2 ,1 );
+ strcpy_n1 ( &(S[47]),resName2,3 );
+ strcpy_n1 ( &(S[51]),chainID2,1 );
+ PutIntIns ( &(S[52]),seqNum2 ,4,insCode2 );
+
+ strcpy_ns ( &(S[72]),linkRID,8 );
+
+ }
+
+
+ #define LinkRTypeID "LINKR"
+
+ void AddStructConnLinkRTags ( mmcif::PLoop Loop ) {
+
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID );
+
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ATOM_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE );
+
+ Loop->AddLoopTag ( CIFTAG_CONN_DIST );
+
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ATOM_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_COMP_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ASYM_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_SEQ_ID );
+ Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE );
+
+ Loop->AddLoopTag ( CIFTAG_CONN_NAME );
+
+ }
+
+ void LinkR::MakeCIF ( mmcif::PData CIF, int N ) {
+ UNUSED_ARGUMENT(N);
+ mmcif::PLoop Loop;
+ int RC;
+
+ RC = CIF->AddLoop ( CIFCAT_STRUCT_LINKR,Loop );
+ if (RC!=mmcif::CIFRC_Ok) // the category was (re)created, provide tags
+ AddStructConnLinkRTags ( Loop );
+
+ Loop->AddString ( "1" ); // should be a counter
+ Loop->AddString ( pstr(LinkTypeID) );
+
+ Loop->AddString ( atName1 );
+ Loop->AddString ( aloc1 );
+ Loop->AddString ( resName1 );
+ Loop->AddString ( chainID1 );
+ Loop->AddInteger ( seqNum1 );
+ Loop->AddString ( insCode1 );
+
+ Loop->AddReal ( dist );
+
+ Loop->AddString ( atName2 );
+ Loop->AddString ( aloc2 );
+ Loop->AddString ( resName2 );
+ Loop->AddString ( chainID2 );
+ Loop->AddInteger ( seqNum2 );
+ Loop->AddString ( insCode2 );
+
+ Loop->AddString ( linkRID );
+
+ }
+
+ ERROR_CODE LinkR::ConvertPDBASCII ( cpstr S ) {
+
+ GetString ( atName1 ,&(S[12]),4 );
+ strcpy_ncss ( aloc1 ,&(S[16]),1 );
+ strcpy_ncss ( resName1,&(S[17]),3 );
+ strcpy_ncss ( chainID1,&(S[21]),1 );
+ GetIntIns ( seqNum1,insCode1,&(S[22]),4 );
+
+ if (!GetReal(dist,&(S[32]),7)) dist = 0.0;
+
+ GetString ( atName2 ,&(S[42]),4 );
+ strcpy_ncss ( aloc2 ,&(S[46]),1 );
+ strcpy_ncss ( resName2,&(S[47]),3 );
+ strcpy_ncss ( chainID2,&(S[51]),1 );
+ GetIntIns ( seqNum2,insCode2,&(S[52]),4 );
+
+ strcpy_ncss ( linkRID,&(S[72]),8 );
+
+ return Error_NoError ;
+
+ }
+
+ ERROR_CODE LinkR::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ pstr F;
+ int RC,l;
+ bool Done;
+ ERROR_CODE rc;
+
+ Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
+ if (!Loop) {
+ n = -1; // signal to finish processing of this structure
+ return Error_EmptyCIF;
+ }
+
+ l = Loop->GetLoopLength();
+ Done = (n>=l);
+ while (!Done) {
+ F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,n,RC );
+ if ((!RC) && F) Done = (strcmp(F,LinkTypeID)==0);
+ else Done = false;
+ if (!Done) {
+ n++;
+ Done = (n>=l);
+ }
+ }
+
+ if (n>=l) {
+ n = -1; // finish processing of Turn
+ return Error_EmptyCIF;
+ }
+
+ Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,n );
+
+ // CIFGetInteger ( l,Loop,CIFTAG_ID,n );
+
+ CIFGetString ( atName1,Loop,CIFTAG_CONN_PTNR1_AUTH_ATOM_ID,n,
+ sizeof(atName1),pstr(" ") );
+ CIFGetString ( aloc1,Loop,CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID,n,
+ sizeof(aloc1),pstr(" ") );
+ CIFGetString ( resName1,Loop,CIFTAG_CONN_PTNR1_AUTH_COMP_ID,n,
+ sizeof(resName1),pstr(" ") );
+ CIFGetString ( chainID1,Loop,CIFTAG_CONN_PTNR1_AUTH_ASYM_ID,n,
+ sizeof(chainID1),pstr(" ") );
+ rc = CIFGetInteger ( seqNum1,Loop,CIFTAG_CONN_PTNR1_AUTH_SEQ_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( insCode1,Loop,CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE,
+ n,sizeof(insCode1),pstr(" ") );
+
+ rc = CIFGetReal ( dist,Loop,CIFTAG_CONN_DIST,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( atName2,Loop,CIFTAG_CONN_PTNR2_AUTH_ATOM_ID,n,
+ sizeof(atName2),pstr(" ") );
+ CIFGetString ( aloc2,Loop,CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID,n,
+ sizeof(aloc2),pstr(" ") );
+ CIFGetString ( resName2,Loop,CIFTAG_CONN_PTNR2_AUTH_COMP_ID,n,
+ sizeof(resName2),pstr(" ") );
+ CIFGetString ( chainID2,Loop,CIFTAG_CONN_PTNR2_AUTH_ASYM_ID,n,
+ sizeof(chainID2),pstr(" ") );
+ rc = CIFGetInteger ( seqNum2,Loop,CIFTAG_CONN_PTNR2_AUTH_SEQ_ID,n );
+ if (rc==Error_NoData) return Error_EmptyCIF;
+ if (rc!=Error_NoError) return rc;
+
+ CIFGetString ( insCode2,Loop,CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE,
+ n,sizeof(insCode2),pstr(" ") );
+
+ CIFGetString ( linkRID,Loop,CIFTAG_CONN_NAME,n,
+ sizeof(linkRID),pstr(" ") );
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+ void LinkR::Copy ( PContainerClass LinkR ) {
+
+ strcpy ( atName1 ,PLinkR(LinkR)->atName1 );
+ strcpy ( aloc1 ,PLinkR(LinkR)->aloc1 );
+ strcpy ( resName1,PLinkR(LinkR)->resName1 );
+ strcpy ( chainID1,PLinkR(LinkR)->chainID1 );
+ seqNum1 = PLinkR(LinkR)->seqNum1;
+ strcpy ( insCode1,PLinkR(LinkR)->insCode1 );
+
+ dist = PLinkR(LinkR)->dist;
+
+ strcpy ( atName2 ,PLinkR(LinkR)->atName2 );
+ strcpy ( aloc2 ,PLinkR(LinkR)->aloc2 );
+ strcpy ( resName2,PLinkR(LinkR)->resName2 );
+ strcpy ( chainID2,PLinkR(LinkR)->chainID2 );
+ seqNum2 = PLinkR(LinkR)->seqNum2;
+ strcpy ( insCode2,PLinkR(LinkR)->insCode2 );
+
+ strcpy ( linkRID,PLinkR(LinkR)->linkRID );
+
+ }
+
+ void LinkR::write ( io::RFile f ) {
+ byte Version=1;
+
+ f.WriteByte ( &Version );
+
+ f.WriteTerLine ( atName1 ,false );
+ f.WriteTerLine ( aloc1 ,false );
+ f.WriteTerLine ( resName1,false );
+ f.WriteTerLine ( chainID1,false );
+ f.WriteInt ( &seqNum1 );
+ f.WriteTerLine ( insCode1,false );
+
+ f.WriteReal ( &dist );
+
+ f.WriteTerLine ( atName2 ,false );
+ f.WriteTerLine ( aloc2 ,false );
+ f.WriteTerLine ( resName2,false );
+ f.WriteTerLine ( chainID2,false );
+ f.WriteInt ( &seqNum2 );
+ f.WriteTerLine ( insCode2,false );
+
+ f.WriteTerLine ( linkRID,false );
+
+ }
+
+ void LinkR::read ( io::RFile f ) {
+ byte Version;
+
+ f.ReadByte ( &Version );
+
+ f.ReadTerLine ( atName1 ,false );
+ f.ReadTerLine ( aloc1 ,false );
+ f.ReadTerLine ( resName1,false );
+ f.ReadTerLine ( chainID1,false );
+ f.ReadInt ( &seqNum1 );
+ f.ReadTerLine ( insCode1,false );
+
+ f.ReadReal ( &dist );
+
+ f.ReadTerLine ( atName2 ,false );
+ f.ReadTerLine ( aloc2 ,false );
+ f.ReadTerLine ( resName2,false );
+ f.ReadTerLine ( chainID2,false );
+ f.ReadInt ( &seqNum2 );
+ f.ReadTerLine ( insCode2,false );
+
+ f.ReadTerLine ( linkRID,false );
+
+ }
+
+ MakeStreamFunctions(LinkR)
+
+
+ // =================== CisPepContainer ======================
+
+ PContainerClass CisPepContainer::MakeContainerClass ( int ClassID ) {
+ switch (ClassID) {
+ default :
+ case ClassID_Template : return
+ ClassContainer::MakeContainerClass(ClassID);
+ case ClassID_CisPep : return new CisPep();
+ }
+ }
+
+ MakeStreamFunctions(CisPepContainer)
+
+
+ // ======================== CisPep ==========================
+
+ CisPep::CisPep() : ContainerClass() {
+ InitCisPep();
+ }
+
+ CisPep::CisPep ( cpstr S ) : ContainerClass() {
+ InitCisPep();
+ ConvertPDBASCII ( S );
+ }
+
+ CisPep::CisPep ( io::RPStream Object ) : ContainerClass(Object) {
+ InitCisPep();
+ }
+
+ CisPep::~CisPep() {}
+
+ void CisPep::InitCisPep() {
+ serNum = 1; // record serial number
+ strcpy ( pep1 ,"---" ); // residue name
+ strcpy ( chainID1," " ); // chain identifier 1
+ seqNum1 = 0; // residue sequence number 1
+ strcpy ( icode1 ," " ); // insertion code 1
+ strcpy ( pep2 ,"---" ); // residue name 2
+ strcpy ( chainID2," " ); // chain identifier 2
+ seqNum2 = 0; // residue sequence number 2
+ strcpy ( icode2 ," " ); // insertion code 2
+ modNum = 0; // model number
+ measure = 0.0; // measure of the angle in degrees.
+ }
+
+ void CisPep::PDBASCIIDump ( pstr S, int N ) {
+ UNUSED_ARGUMENT(N);
+
+ strcpy ( S,"CISPEP" );
+ PadSpaces ( S,80 );
+
+ PutInteger ( &(S[7]),serNum,3 );
+
+ strcpy_n1 ( &(S[11]),pep1 ,3 );
+ strcpy_n1 ( &(S[15]),chainID1,1 );
+ PutIntIns ( &(S[17]),seqNum1 ,4,icode1 );
+
+ strcpy_n1 ( &(S[25]),pep2 ,3 );
+ strcpy_n1 ( &(S[29]),chainID2,1 );
+ PutIntIns ( &(S[31]),seqNum2 ,4,icode1 );
+
+ PutInteger ( &(S[43]),modNum,3 );
+ PutRealF ( &(S[53]),measure,6,2 );
+
+ }
+
+
+ ERROR_CODE CisPep::ConvertPDBASCII ( cpstr S ) {
+
+ GetInteger ( serNum ,&(S[7]) ,3 );
+
+ strcpy_ncss ( pep1 ,&(S[11]),3 );
+ strcpy_ncss ( chainID1,&(S[15]),1 );
+ GetIntIns ( seqNum1,icode1,&(S[17]),4 );
+
+ strcpy_ncss ( pep2 ,&(S[25]),3 );
+ strcpy_ncss ( chainID2,&(S[29]),1 );
+ GetIntIns ( seqNum2,icode2,&(S[31]),4 );
+
+ GetInteger ( modNum ,&(S[43]),3 );
+ GetReal ( measure ,&(S[53]),6 );
+
+ return Error_NoError;
+
+ }
+
+
+ void CisPep::Copy ( PContainerClass CisPep ) {
+
+ serNum = PCisPep(CisPep)->serNum;
+
+ strcpy ( pep1 ,PCisPep(CisPep)->pep1 );
+ strcpy ( chainID1,PCisPep(CisPep)->chainID1 );
+ seqNum1 = PCisPep(CisPep)->seqNum1;
+ strcpy ( icode1 ,PCisPep(CisPep)->icode1 );
+
+ strcpy ( pep2 ,PCisPep(CisPep)->pep2 );
+ strcpy ( chainID2,PCisPep(CisPep)->chainID2 );
+ seqNum2 = PCisPep(CisPep)->seqNum2;
+ strcpy ( icode2 ,PCisPep(CisPep)->icode2 );
+
+ modNum = PCisPep(CisPep)->modNum;
+ measure = PCisPep(CisPep)->measure;
+
+ }
+
+ void CisPep::write ( io::RFile f ) {
+ byte Version=1;
+
+ f.WriteByte ( &Version );
+
+ f.WriteInt ( &serNum );
+
+ f.WriteTerLine ( pep1 ,false );
+ f.WriteTerLine ( chainID1,false );
+ f.WriteInt ( &seqNum1 );
+ f.WriteTerLine ( icode1 ,false );
+
+ f.WriteTerLine ( pep2 ,false );
+ f.WriteTerLine ( chainID2,false );
+ f.WriteInt ( &seqNum2 );
+ f.WriteTerLine ( icode2 ,false );
+
+ f.WriteInt ( &modNum );
+ f.WriteReal ( &measure );
+
+ }
+
+ void CisPep::read ( io::RFile f ) {
+ byte Version;
+
+ f.ReadByte ( &Version );
+
+ f.ReadInt ( &serNum );
+
+ f.ReadTerLine ( pep1 ,false );
+ f.ReadTerLine ( chainID1,false );
+ f.ReadInt ( &seqNum1 );
+ f.ReadTerLine ( icode1 ,false );
+
+ f.ReadTerLine ( pep2 ,false );
+ f.ReadTerLine ( chainID2,false );
+ f.ReadInt ( &seqNum2 );
+ f.ReadTerLine ( icode2 ,false );
+
+ f.ReadInt ( &modNum );
+ f.ReadReal ( &measure );
+
+ }
+
+ MakeStreamFunctions(CisPep)
+
+
+
+ // ===================== Model =======================
+
+ Model::Model() : ProModel() {
+ InitModel();
+ }
+
+ Model::Model ( PManager MMDBM, int serialNum ) : ProModel() {
+ InitModel();
+ manager = MMDBM;
+ serNum = serialNum;
+ }
+
+ Model::Model ( io::RPStream Object ) : ProModel(Object) {
+ InitModel();
+ }
+
+ void Model::InitModel() {
+ serNum = 0;
+ nChains = 0;
+ nChainsAlloc = 0;
+ chain = NULL;
+ manager = NULL;
+ Exclude = true;
+ }
+
+ Model::~Model() {
+ FreeMemory();
+ if (manager) manager->_ExcludeModel ( serNum );
+ }
+
+ void Model::FreeMemory() {
+
+ DeleteAllChains();
+ if (chain) delete[] chain;
+ chain = NULL;
+ nChains = 0;
+ nChainsAlloc = 0;
+
+ RemoveSecStructure();
+ RemoveHetInfo ();
+ RemoveLinks ();
+ RemoveLinkRs ();
+ RemoveCisPeps ();
+
+ }
+
+
+ void Model::SetMMDBManager ( PManager MMDBM, int serialNum ) {
+ manager = MMDBM;
+ serNum = serialNum;
+ }
+
+ void Model::CheckInAtoms() {
+ int i;
+ if (manager)
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->CheckInAtoms();
+ }
+
+
+ int Model::GetNumberOfAtoms ( bool countTers ) {
+ // returns number of atoms in the model
+ int i,na;
+ na = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) na += chain[i]->GetNumberOfAtoms ( countTers );
+ return na;
+ }
+
+ int Model::GetNumberOfResidues() {
+ // returns number of residues in the model
+ PChain chn;
+ int ic,ir,nr;
+ nr = 0;
+ for (ic=0;ic<nChains;ic++) {
+ chn = chain[ic];
+ if (chn)
+ for (ir=0;ir<chn->nResidues;ir++)
+ if (chn->residue[ir]) nr++;
+ }
+ return nr;
+ }
+
+
+ // ---------------- Extracting chains --------------------------
+
+ int Model::GetNumberOfChains() {
+ return nChains;
+ }
+
+ PChain Model::GetChain ( int chainNo ) {
+ if ((0<=chainNo) && (chainNo<nChains))
+ return chain[chainNo];
+ else return NULL;
+ }
+
+
+ void Model::ExpandChainArray ( int nOfChains ) {
+ PPChain chain1;
+ int i;
+ if (nOfChains>=nChainsAlloc) {
+ nChainsAlloc = nOfChains+10;
+ chain1 = new PChain[nChainsAlloc];
+ for (i=0;i<nChains;i++)
+ chain1[i] = chain[i];
+ for (i=nChains;i<nChainsAlloc;i++)
+ chain1[i] = NULL;
+ if (chain) delete[] chain;
+ chain = chain1;
+ }
+ }
+
+ PChain Model::GetChainCreate ( const ChainID chID,
+ bool enforceUniqueChainID ) {
+ // Returns pointer on chain, whose identifier is
+ // given in chID. If such a chain is absent in the
+ // model, it is created.
+ PChain chn;
+ ChainID chainID;
+ int i,k;
+
+ // check if such a chain is already in the model
+ chn = NULL;
+ if (enforceUniqueChainID) {
+ k = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) {
+ // here we check only first letter as it is kept in all
+ // derived names
+ if (chID[0]==chain[i]->chainID[0]) {
+ chn = chain[i];
+ if (chn->GetNumberOfResidues()>0) k++;
+ }
+ }
+ if (k) sprintf ( chainID,"%s%i",chID,k-1 );
+ else if (!chn) strcpy ( chainID,chID ); // chain is absent
+ else return chn; // the only empty chain
+ } else {
+ if (chID[0]) {
+ for (i=0;(i<nChains) && (!chn);i++)
+ if (chain[i]) {
+ if (!strcmp(chID,chain[i]->chainID))
+ chn = chain[i]; // it is there; just return the pointer
+ }
+ } else {
+ for (i=0;(i<nChains) && (!chn);i++)
+ if (chain[i]) {
+ if (!chain[i]->chainID[0])
+ chn = chain[i]; // it is there; just return the pointer
+ }
+ }
+ if (chn) return chn;
+ strcpy ( chainID,chID );
+ }
+
+ ExpandChainArray ( nChains );
+
+ // create new chain
+ chain[nChains] = newChain();
+ chain[nChains]->SetChain ( chainID );
+ chain[nChains]->SetModel ( this );
+ nChains++;
+
+ return chain[nChains-1];
+
+ }
+
+ PChain Model::CreateChain ( const ChainID chID ) {
+ // CreateChain() creates a new chain with chain ID regardless
+ // the presence of same-ID chains in the model. This function
+ // was introduced only for compatibility with older CCP4
+ // applications and using it in any new developments should be
+ // strictly discouraged.
+
+ ExpandChainArray ( nChains );
+
+ // create new chain
+ chain[nChains] = newChain();
+ chain[nChains]->SetChain ( chID );
+ chain[nChains]->SetModel ( this );
+ nChains++;
+
+ return chain[nChains-1];
+
+ }
+
+
+ void Model::GetChainTable ( PPChain & chainTable,
+ int & NumberOfChains ) {
+ chainTable = chain;
+ NumberOfChains = nChains;
+ }
+
+ bool Model::GetNewChainID ( ChainID chID, int length ) {
+ int i,k;
+ bool found;
+
+ memset ( chID,0,sizeof(ChainID) );
+ chID[0] = 'A';
+
+ do {
+ found = false;
+ for (i=0;(i<nChains) && (!found);i++)
+ if (chain[i])
+ found = (!strcmp(chID,chain[i]->chainID));
+ if (found) {
+ k = 0;
+ while (k<length)
+ if (!chID[k]) {
+ chID[k] = 'A';
+ break;
+ } else if (chID[k]<'Z') {
+ chID[k]++;
+ break;
+ } else {
+ chID[k] = 'A';
+ k++;
+ }
+ } else
+ k = 0;
+ } while (found && (k<length));
+
+ if (found) {
+ k = strlen(chID);
+ while (k<length)
+ chID[k++] = 'A';
+ }
+
+ return (!found);
+
+ }
+
+
+ PChain Model::GetChain ( const ChainID chID ) {
+ // Returns pointer on chain, whose identifier is
+ // given in chID. If such a chain is absent in the
+ // model, returns NULL.
+ int i;
+ bool isChainID;
+ if (chID) isChainID = (chID[0]!=char(0));
+ else isChainID = false;
+ if (isChainID) {
+ for (i=0;i<nChains;i++)
+ if (chain[i]) {
+ if (!strcmp(chID,chain[i]->chainID))
+ return chain[i]; // it is there; just return the pointer
+ }
+ } else {
+ for (i=0;i<nChains;i++)
+ if (chain[i]) {
+ if (!chain[i]->chainID[0])
+ return chain[i]; // it is there; just return the pointer
+ }
+ }
+ return NULL;
+ }
+
+
+ // ------------------ Deleting chains --------------------------
+
+ int Model::DeleteChain ( int chainNo ) {
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo]) {
+ Exclude = false;
+ delete chain[chainNo];
+ chain[chainNo] = NULL;
+ Exclude = true;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ int Model::DeleteChain ( const ChainID chID ) {
+ int i;
+ if (chID[0]) {
+ for (i=0;i<nChains;i++)
+ if (chain[i]) {
+ if (!strcmp(chID,chain[i]->chainID)) {
+ Exclude = false;
+ delete chain[i];
+ chain[i] = NULL;
+ Exclude = true;
+ return 1;
+ }
+ }
+ } else {
+ for (i=0;i<nChains;i++)
+ if (chain[i]) {
+ if (!chain[i]->chainID[0]) {
+ Exclude = false;
+ delete chain[i];
+ chain[i] = NULL;
+ Exclude = true;
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+
+
+ int Model::DeleteAllChains() {
+ int i,k;
+ Exclude = false;
+ k = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) {
+ delete chain[i];
+ chain[i] = NULL;
+ k++;
+ }
+ nChains = 0;
+ Exclude = true;
+ return k;
+ }
+
+ int Model::DeleteSolventChains() {
+ int i,k;
+ Exclude = false;
+ k = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) {
+ if (chain[i]->isSolventChain()) {
+ delete chain[i];
+ chain[i] = NULL;
+ k++;
+ }
+ }
+ Exclude = true;
+ return k;
+ }
+
+ void Model::TrimChainTable() {
+ int i,j;
+ Exclude = false;
+ j = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) {
+ if (chain[i]->nResidues>0) {
+ if (j<i) {
+ chain[j] = chain[i];
+ chain[i] = NULL;
+ }
+ j++;
+ } else {
+ delete chain[i];
+ chain[i] = NULL;
+ }
+ }
+ nChains = j;
+ Exclude = true;
+ }
+
+
+ int Model::GetNumberOfResidues ( const ChainID chainID ) {
+ PChain chn;
+ chn = GetChain ( chainID );
+ if (chn) return chn->nResidues;
+ return 0;
+ }
+
+ int Model::GetNumberOfResidues ( int chainNo ) {
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo])
+ return chain[chainNo]->nResidues;
+ }
+ return 0;
+ }
+
+ PResidue Model::GetResidue ( const ChainID chainID, int seqNo,
+ const InsCode insCode ) {
+ PChain chn;
+ chn = GetChain ( chainID );
+ if (chn)
+ return chn->GetResidue ( seqNo,insCode );
+ return NULL;
+ }
+
+ PResidue Model::GetResidue ( const ChainID chainID, int resNo ) {
+ PChain chn;
+ chn = GetChain ( chainID );
+ if (chn) {
+ if ((0<=resNo) && (resNo<chn->nResidues))
+ return chn->residue[resNo];
+ }
+ return NULL;
+ }
+
+ PResidue Model::GetResidue ( int chainNo, int seqNo,
+ const InsCode insCode ) {
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo])
+ return chain[chainNo]->GetResidue ( seqNo,insCode );
+ }
+ return NULL;
+ }
+
+ PResidue Model::GetResidue ( int chainNo, int resNo ) {
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo]) {
+ if ((0<=resNo) && (resNo<chain[chainNo]->nResidues))
+ return chain[chainNo]->residue[resNo];
+ }
+ }
+ return NULL;
+ }
+
+ int Model::GetResidueNo ( const ChainID chainID, int seqNo,
+ const InsCode insCode ) {
+ PChain chn;
+ chn = GetChain ( chainID );
+ if (chn)
+ return chn->GetResidueNo ( seqNo,insCode );
+ return -2;
+ }
+
+ int Model::GetResidueNo ( int chainNo, int seqNo,
+ const InsCode insCode ) {
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo])
+ return chain[chainNo]->GetResidueNo ( seqNo,insCode );
+ }
+ return -2;
+ }
+
+
+ void Model::GetResidueTable ( PPResidue & resTable,
+ int & NumberOfResidues ) {
+ // resTable has to be NULL or it will be reallocated. The application
+ // is responsible for deallocating the resTable (but not of its
+ // residues!). This does not apply to other GetResidueTable
+ // functions.
+ PPChain chn;
+ PPResidue res;
+ int i,j,k,nChns,nResidues;
+
+ if (resTable) {
+ delete[] resTable;
+ resTable = NULL;
+ }
+
+ NumberOfResidues = 0;
+ GetChainTable ( chn,nChns );
+ for (i=0;i<nChns;i++)
+ if (chn[i]) {
+ chn[i]->GetResidueTable ( res,nResidues );
+ NumberOfResidues += nResidues;
+ }
+
+ if (NumberOfResidues>0) {
+ resTable = new PResidue[NumberOfResidues];
+ k = 0;
+ GetChainTable ( chn,nChns );
+ for (i=0;i<nChns;i++)
+ if (chn[i]) {
+ chn[i]->GetResidueTable ( res,nResidues );
+ for (j=0;j<nResidues;j++)
+ if (res[j]) resTable[k++] = res[j];
+ }
+ NumberOfResidues = k;
+ }
+
+ }
+
+ void Model::GetResidueTable ( const ChainID chainID,
+ PPResidue & resTable,
+ int & NumberOfResidues ) {
+ PChain chn;
+ resTable = NULL;
+ NumberOfResidues = 0;
+ chn = GetChain ( chainID );
+ if (chn) {
+ resTable = chn->residue;
+ NumberOfResidues = chn->nResidues;
+ }
+ }
+
+ void Model::GetResidueTable ( int chainNo, PPResidue & resTable,
+ int & NumberOfResidues ) {
+ resTable = NULL;
+ NumberOfResidues = 0;
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo]) {
+ resTable = chain[chainNo]->residue;
+ NumberOfResidues = chain[chainNo]->nResidues;
+ }
+ }
+ }
+
+
+ int Model::DeleteResidue ( const ChainID chainID, int seqNo,
+ const InsCode insCode ) {
+ PChain chn;
+ chn = GetChain ( chainID );
+ if (chn) return chn->DeleteResidue ( seqNo,insCode );
+ return 0;
+ }
+
+ int Model::DeleteResidue ( const ChainID chainID, int resNo ) {
+ PChain chn;
+ chn = GetChain ( chainID );
+ if (chn) return chn->DeleteResidue ( resNo );
+ return 0;
+ }
+
+ int Model::DeleteResidue ( int chainNo, int seqNo,
+ const InsCode insCode ) {
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo])
+ return chain[chainNo]->DeleteResidue ( seqNo,insCode );
+ }
+ return 0;
+ }
+
+ int Model::DeleteResidue ( int chainNo, int resNo ) {
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo])
+ return chain[chainNo]->DeleteResidue ( resNo );
+ }
+ return 0;
+ }
+
+ int Model::DeleteAllResidues ( const ChainID chainID ) {
+ PChain chn;
+ chn = GetChain ( chainID );
+ if (chn) return chn->DeleteAllResidues();
+ return 0;
+ }
+
+ int Model::DeleteAllResidues ( int chainNo ) {
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo])
+ return chain[chainNo]->DeleteAllResidues();
+ }
+ return 0;
+ }
+
+ int Model::DeleteAllResidues() {
+ int i,k;
+ k = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ k += chain[i]->DeleteAllResidues();
+ return k;
+ }
+
+
+ int Model::DeleteSolvent() {
+ int i,k;
+ Exclude = false;
+ k = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) {
+ k += chain[i]->DeleteSolvent();
+ chain[i]->TrimResidueTable();
+ if (chain[i]->nResidues<=0) {
+ delete chain[i];
+ chain[i] = NULL;
+ }
+ }
+ Exclude = true;
+ return k;
+ }
+
+
+ int Model::AddResidue ( const ChainID chainID, PResidue res ) {
+ PChain chn;
+ chn = GetChain ( chainID );
+ if (chn) return chn->AddResidue ( res );
+ return 0;
+ }
+
+ int Model::AddResidue ( int chainNo, PResidue res ) {
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ if (chain[chainNo])
+ return chain[chainNo]->AddResidue ( res );
+ }
+ return 0;
+ }
+
+
+ int Model::_ExcludeChain ( const ChainID chainID ) {
+ // _ExcludeChain(..) excludes (but does not dispose!) a chain
+ // from the model. Returns 1 if the model gets empty and 0 otherwise.
+ int i,k;
+
+ if (!Exclude) return 0;
+
+ // find the chain
+ k = -1;
+ for (i=0;(i<nChains) && (k<0);i++)
+ if (!strcmp(chainID,chain[i]->chainID))
+ k = i;
+
+ if (k>=0) {
+ for (i=k+1;i<nChains;i++)
+ chain[i-1] = chain[i];
+ nChains--;
+ chain[nChains] = NULL;
+ }
+
+ if (nChains<=0) return 1;
+ else return 0;
+
+ }
+
+
+ // -------------------- Sort chains ----------------------------
+
+ DefineClass(QSortChains)
+
+ class QSortChains : public QuickSort {
+ public :
+ QSortChains() : QuickSort() { sKey = 0; }
+ int Compare ( int i, int j );
+ void Swap ( int i, int j );
+ void Sort ( PPChain chain, int nChains, int sortKey );
+ private :
+ int sKey;
+ };
+
+ int QSortChains::Compare ( int i, int j ) {
+ int diff;
+
+ diff = strcmp ( (PPChain(data))[i]->GetChainID(),
+ (PPChain(data))[j]->GetChainID() );
+ if (diff>0) diff = 1;
+ if (diff<0) diff = -1;
+
+ if (sKey==SORT_CHAIN_ChainID_Desc) return -diff;
+
+ return diff;
+
+ }
+
+ void QSortChains::Swap ( int i, int j ) {
+ PChain chn;
+ chn = ((PPChain)data)[i];
+ ((PPChain)data)[i] = ((PPChain)data)[j];
+ ((PPChain)data)[j] = chn;
+ }
+
+ void QSortChains::Sort ( PPChain chain, int nChains, int sortKey ) {
+ sKey = sortKey;
+ QuickSort::Sort ( &(chain[0]),nChains );
+ }
+
+ void Model::SortChains ( int sortKey ) {
+ QSortChains SC;
+ TrimChainTable();
+ SC.Sort ( chain,nChains,sortKey );
+ }
+
+
+ // -------------------- Extracting atoms -----------------------
+
+
+ int Model::GetNumberOfAtoms ( const ChainID chainID, int seqNo,
+ const InsCode insCode ) {
+ PChain chn;
+ PResidue res;
+ chn = GetChain ( chainID );
+ if (chn) {
+ res = chn->GetResidue ( seqNo,insCode );
+ if (res) return res->nAtoms;
+ }
+ return 0;
+ }
+
+ int Model::GetNumberOfAtoms ( int chainNo, int seqNo,
+ const InsCode insCode ) {
+ PChain chn;
+ PResidue res;
+ chn = GetChain ( chainNo );
+ if (chn) {
+ res = chn->GetResidue ( seqNo,insCode );
+ if (res) return res->nAtoms;
+ }
+ return 0;
+ }
+
+ int Model::GetNumberOfAtoms ( const ChainID chainID, int resNo ) {
+ PChain chn;
+ PResidue res;
+ chn = GetChain ( chainID );
+ if (chn) {
+ if ((0<=resNo) && (resNo<chn->nResidues)) {
+ res = chn->residue[resNo];
+ if (res) return res->nAtoms;
+ }
+ }
+ return 0;
+ }
+
+ int Model::GetNumberOfAtoms ( int chainNo, int resNo ) {
+ PChain chn;
+ PResidue res;
+ if ((0<=chainNo) && (chainNo<nChains)) {
+ chn = chain[chainNo];
+ if (chn) {
+ if ((0<=resNo) && (resNo<chn->nResidues)) {
+ res = chn->residue[resNo];
+ if (res) return res->nAtoms;
+ }
+ }
+ }
+ return 0;
+ }
+
+ PAtom Model::GetAtom ( const ChainID chID,
+ int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc
+ ) {
+ PChain chn;
+ PResidue res;
+ chn = GetChain ( chID );
+ if (chn) {
+ res = chn->GetResidue ( seqNo,insCode );
+ if (res)
+ return res->GetAtom ( aname,elmnt,aloc );
+ }
+ return NULL;
+ }
+
+ PAtom Model::GetAtom ( const ChainID chID, int seqNo,
+ const InsCode insCode, int atomNo ) {
+ PChain chn;
+ PResidue res;
+ chn = GetChain ( chID );
+ if (chn) {
+ res = chn->GetResidue ( seqNo,insCode );
+ if (res) {
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ return res->atom[atomNo];
+ }
+ }
+ return NULL;
+ }
+
+ PAtom Model::GetAtom ( const ChainID chID,
+ int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ PChain chn;
+ PResidue res;
+ chn = GetChain ( chID );
+ if (chn) {
+ if ((0<=resNo) && (resNo<chn->nResidues)) {
+ res = chn->residue[resNo];
+ if (res)
+ return res->GetAtom ( aname,elmnt,aloc );
+ }
+ }
+ return NULL;
+ }
+
+ PAtom Model::GetAtom ( const ChainID chID, int resNo, int atomNo ) {
+ PChain chn;
+ PResidue res;
+ chn = GetChain ( chID );
+ if (chn) {
+ if ((0<=resNo) && (resNo<chn->nResidues)) {
+ res = chn->residue[resNo];
+ if (res) {
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ return res->atom[atomNo];
+ }
+ }
+ }
+ return NULL;
+ }
+
+ PAtom Model::GetAtom ( int chNo, int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ PResidue res;
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo]) {
+ res = chain[chNo]->GetResidue ( seqNo,insCode );
+ if (res)
+ return res->GetAtom ( aname,elmnt,aloc );
+ }
+ }
+ return NULL;
+ }
+
+ PAtom Model::GetAtom ( int chNo, int seqNo, const InsCode insCode,
+ int atomNo ) {
+ PResidue res;
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo]) {
+ res = chain[chNo]->GetResidue ( seqNo,insCode );
+ if (res) {
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ return res->atom[atomNo];
+ }
+ }
+ }
+ return NULL;
+ }
+
+ PAtom Model::GetAtom ( int chNo, int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ PResidue res;
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo]) {
+ if ((0<=resNo) && (resNo<chain[chNo]->nResidues)) {
+ res = chain[chNo]->residue[resNo];
+ if (res)
+ return res->GetAtom ( aname,elmnt,aloc );
+ }
+ }
+ }
+ return NULL;
+ }
+
+ PAtom Model::GetAtom ( int chNo, int resNo, int atomNo ) {
+ PResidue res;
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo]) {
+ if ((0<=resNo) && (resNo<chain[chNo]->nResidues)) {
+ res = chain[chNo]->residue[resNo];
+ if (res) {
+ if ((0<=atomNo) && (atomNo<res->nAtoms))
+ return res->atom[atomNo];
+ }
+ }
+ }
+ }
+ return NULL;
+ }
+
+
+ void Model::GetAtomTable ( const ChainID chainID, int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ res = GetResidue ( chainID,seqNo,insCode );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+
+ void Model::GetAtomTable ( int chainNo, int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ res = GetResidue ( chainNo,seqNo,insCode );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+
+ void Model::GetAtomTable ( const ChainID chainID, int resNo,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ res = GetResidue ( chainID,resNo );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+
+ void Model::GetAtomTable ( int chainNo, int resNo,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ res = GetResidue ( chainNo,resNo );
+ if (res) {
+ atomTable = res->atom;
+ NumberOfAtoms = res->nAtoms;
+ }
+ }
+
+
+ void Model::GetAtomTable1 ( const ChainID chainID, int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ res = GetResidue ( chainID,seqNo,insCode );
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void Model::GetAtomTable1 ( int chainNo, int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ res = GetResidue ( chainNo,seqNo,insCode );
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void Model::GetAtomTable1 ( const ChainID chainID, int resNo,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ res = GetResidue ( chainID,resNo );
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+ void Model::GetAtomTable1 ( int chainNo, int resNo,
+ PPAtom & atomTable,
+ int & NumberOfAtoms ) {
+ PResidue res;
+ res = GetResidue ( chainNo,resNo );
+ if (res)
+ res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+ else {
+ if (atomTable) delete[] atomTable;
+ atomTable = NULL;
+ NumberOfAtoms = 0;
+ }
+ }
+
+
+
+ int Model::DeleteAtom ( const ChainID chID,
+ int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc
+ ) {
+ PChain chn;
+ chn = GetChain ( chID );
+ if (chn)
+ return chn->DeleteAtom ( seqNo,insCode,aname,elmnt,aloc );
+ return 0;
+ }
+
+ int Model::DeleteAtom ( const ChainID chID, int seqNo,
+ const InsCode insCode, int atomNo ) {
+ PChain chn;
+ chn = GetChain ( chID );
+ if (chn) return chn->DeleteAtom ( seqNo,insCode,atomNo );
+ return 0;
+ }
+
+ int Model::DeleteAtom ( const ChainID chID,
+ int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ PChain chn;
+ chn = GetChain ( chID );
+ if (chn) return chn->DeleteAtom ( resNo,aname,elmnt,aloc );
+ return 0;
+ }
+
+ int Model::DeleteAtom ( const ChainID chID, int resNo, int atomNo ) {
+ PChain chn;
+ chn = GetChain ( chID );
+ if (chn) return chn->DeleteAtom ( resNo,atomNo );
+ return 0;
+ }
+
+ int Model::DeleteAtom ( int chNo, int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo])
+ return chain[chNo]->DeleteAtom ( seqNo,insCode,aname,
+ elmnt,aloc );
+ }
+ return 0;
+ }
+
+ int Model::DeleteAtom ( int chNo, int seqNo, const InsCode insCode,
+ int atomNo ) {
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo])
+ return chain[chNo]->DeleteAtom ( seqNo,insCode,atomNo );
+ }
+ return 0;
+ }
+
+ int Model::DeleteAtom ( int chNo, int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc ) {
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo])
+ return chain[chNo]->DeleteAtom ( resNo,aname,elmnt,aloc );
+ }
+ return 0;
+ }
+
+ int Model::DeleteAtom ( int chNo, int resNo, int atomNo ) {
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo])
+ return chain[chNo]->DeleteAtom ( resNo,atomNo );
+ }
+ return 0;
+ }
+
+ int Model::DeleteAllAtoms ( const ChainID chID, int seqNo,
+ const InsCode insCode ) {
+ PChain chn;
+ chn = GetChain ( chID );
+ if (chn) return chn->DeleteAllAtoms ( seqNo,insCode );
+ return 0;
+ }
+
+ int Model::DeleteAllAtoms ( const ChainID chID, int resNo ) {
+ PChain chn;
+ chn = GetChain ( chID );
+ if (chn) return chn->DeleteAllAtoms ( resNo );
+ return 0;
+ }
+
+ int Model::DeleteAllAtoms ( const ChainID chID ) {
+ PChain chn;
+ chn = GetChain ( chID );
+ if (chn) return chn->DeleteAllAtoms();
+ return 0;
+ }
+
+ int Model::DeleteAllAtoms ( int chNo, int seqNo,
+ const InsCode insCode ) {
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo])
+ return chain[chNo]->DeleteAllAtoms ( seqNo,insCode );
+ }
+ return 0;
+ }
+
+ int Model::DeleteAllAtoms ( int chNo, int resNo ) {
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo])
+ return chain[chNo]->DeleteAllAtoms ( resNo );
+ }
+ return 0;
+ }
+
+ int Model::DeleteAllAtoms ( int chNo ) {
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo])
+ return chain[chNo]->DeleteAllAtoms();
+ }
+ return 0;
+ }
+
+ int Model::DeleteAllAtoms() {
+ int i,k;
+ k = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) k += chain[i]->DeleteAllAtoms();
+ return k;
+ }
+
+ int Model::DeleteAltLocs() {
+ // This function leaves only alternative location with maximal
+ // occupancy, if those are equal or unspecified, the one with
+ // "least" alternative location indicator.
+ // The function returns the number of deleted. All tables remain
+ // untrimmed, so that explicit trimming or calling FinishStructEdit()
+ // is required.
+ int i,n;
+
+ n = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) n += chain[i]->DeleteAltLocs();
+
+ return n;
+
+ }
+
+
+ int Model::AddAtom ( const ChainID chID, int seqNo,
+ const InsCode insCode,
+ PAtom atom ) {
+ PChain chn;
+ chn = GetChain ( chID );
+ if (chn) return chn->AddAtom ( seqNo,insCode,atom );
+ return 0;
+ }
+
+ int Model::AddAtom ( const ChainID chID, int resNo, PAtom atom ) {
+ PChain chn;
+ chn = GetChain ( chID );
+ if (chn) return chn->AddAtom ( resNo,atom );
+ return 0;
+ }
+
+ int Model::AddAtom ( int chNo, int seqNo, const InsCode insCode,
+ PAtom atom ) {
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo])
+ return chain[chNo]->AddAtom ( seqNo,insCode,atom );
+ }
+ return 0;
+ }
+
+ int Model::AddAtom ( int chNo, int resNo, PAtom atom ) {
+ if ((0<=chNo) && (chNo<nChains)) {
+ if (chain[chNo])
+ return chain[chNo]->AddAtom ( resNo,atom );
+ }
+ return 0;
+ }
+
+
+
+ void Model::GetAtomStatistics ( RAtomStat AS ) {
+ AS.Init();
+ CalAtomStatistics ( AS );
+ AS.Finish();
+ }
+
+ void Model::CalAtomStatistics ( RAtomStat AS ) {
+ int i;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) chain[i]->CalAtomStatistics ( AS );
+ }
+
+
+
+ ERROR_CODE Model::ConvertPDBString ( pstr PDBString ) {
+ // Interprets PDB records DBREF, SEQADV, SEQRES, MODRES.
+ // Returns zero if the line was converted, otherwise returns a
+ // non-negative value of Error_XXXX.
+ // PDBString must be not shorter than 81 characters.
+ ChainID chainID;
+ PChain chn;
+ PHelix helix;
+ PTurn turn;
+ PLink link;
+ PLinkR linkR;
+ PCisPep cispep;
+ ERROR_CODE RC;
+
+ // pad input line with spaces, if necessary
+ PadSpaces ( PDBString,80 );
+
+ chainID[0] = char(0);
+ chainID[1] = char(0);
+
+ if (!strncmp(PDBString,"DBREF ",6)) {
+
+ if (PDBString[12]!=' ') chainID[0] = PDBString[12];
+ chn = GetChainCreate ( chainID,false );
+ return chn->ConvertDBREF ( PDBString );
+
+ } else if (!strncmp(PDBString,"SEQADV",6)) {
+
+ if (PDBString[16]!=' ') chainID[0] = PDBString[16];
+ chn = GetChainCreate ( chainID,false );
+ return chn->ConvertSEQADV ( PDBString );
+
+ } else if (!strncmp(PDBString,"SEQRES",6)) {
+
+ if (PDBString[11]!=' ') chainID[0] = PDBString[11];
+ chn = GetChainCreate ( chainID,false );
+ return chn->ConvertSEQRES ( PDBString );
+
+ } else if (!strncmp(PDBString,"MODRES",6)) {
+
+ if (PDBString[16]!=' ') chainID[0] = PDBString[16];
+ chn = GetChainCreate ( chainID,false );
+ return chn->ConvertMODRES ( PDBString );
+
+ } else if (!strncmp(PDBString,"HET ",6)) {
+
+ if (PDBString[12]!=' ') chainID[0] = PDBString[12];
+ chn = GetChainCreate ( chainID,false );
+ return chn->ConvertHET ( PDBString );
+
+ } else if (!strncmp(PDBString,"HETNAM",6)) {
+
+ hetCompounds.ConvertHETNAM ( PDBString );
+ return Error_NoError;
+
+ } else if (!strncmp(PDBString,"HETSYN",6)) {
+
+ hetCompounds.ConvertHETSYN ( PDBString );
+ return Error_NoError;
+
+ } else if (!strncmp(PDBString,"FORMUL",6)) {
+
+ hetCompounds.ConvertFORMUL ( PDBString );
+ return Error_NoError;
+
+ } else if (!strncmp(PDBString,"HELIX ",6)) {
+
+ helix = new Helix();
+ RC = helix->ConvertPDBASCII(PDBString);
+ if (RC==0) helices.AddData ( helix );
+ else delete helix;
+ return RC;
+
+ } else if (!strncmp(PDBString,"SHEET ",6)) {
+
+ return sheets.ConvertPDBASCII ( PDBString );
+
+ } else if (!strncmp(PDBString,"TURN ",6)) {
+
+ turn = new Turn();
+ RC = turn->ConvertPDBASCII(PDBString);
+ if (RC==0) turns.AddData ( turn );
+ else delete turn;
+ return RC;
+
+ } else if (!strncmp(PDBString,"LINK ",6)) {
+
+ link = new Link();
+ RC = link->ConvertPDBASCII(PDBString);
+ if (RC==0) links.AddData ( link );
+ else delete link;
+ return RC;
+
+
+ } else if (!strncmp(PDBString,"LINKR ",6)) {
+
+ linkR = new LinkR();
+ RC = linkR->ConvertPDBASCII(PDBString);
+ if (RC==0) linkRs.AddData ( linkR );
+ else delete linkR;
+ return RC;
+
+ } else if (!strncmp(PDBString,"CISPEP",6)) {
+
+ cispep = new CisPep();
+ RC = cispep->ConvertPDBASCII(PDBString);
+ if (RC==0) cisPeps.AddData ( cispep );
+ else delete cispep;
+ return RC;
+
+ } else
+ return Error_WrongSection;
+
+ }
+
+
+ void Model::PDBASCIIDumpPS ( io::RFile f ) {
+ int i;
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->DBRef.PDBASCIIDump ( f );
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->seqAdv.PDBASCIIDump ( f );
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->seqRes.PDBASCIIDump ( f );
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->modRes.PDBASCIIDump ( f );
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->Het.PDBASCIIDump ( f );
+
+ hetCompounds.PDBASCIIDump ( f );
+ helices .PDBASCIIDump ( f );
+ sheets .PDBASCIIDump ( f );
+ turns .PDBASCIIDump ( f );
+ links .PDBASCIIDump ( f );
+ linkRs .PDBASCIIDump ( f );
+
+ }
+
+ void Model::PDBASCIIDumpCP ( io::RFile f ) {
+ cisPeps.PDBASCIIDump ( f );
+ }
+
+ void Model::PDBASCIIDump ( io::RFile f ) {
+ char S[100];
+ int i;
+ bool singleModel = true;
+
+ if (manager)
+ singleModel = (manager->nModels<=1);
+
+ if (!singleModel) {
+ strcpy ( S,"MODEL " );
+ PadSpaces ( S,80 );
+ PutInteger ( &(S[10]),serNum,4 );
+ f.WriteLine ( S );
+ }
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->PDBASCIIAtomDump ( f );
+
+ if (!singleModel) {
+ strcpy ( S,"ENDMDL" );
+ PadSpaces ( S,80 );
+ f.WriteLine ( S );
+ }
+
+ }
+
+
+ void Model::MakeAtomCIF ( mmcif::PData CIF ) {
+ int i;
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->MakeAtomCIF ( CIF );
+ }
+
+
+ void Model::MakePSCIF ( mmcif::PData CIF ) {
+ int i;
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->DBRef.MakeCIF ( CIF );
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->seqAdv.MakeCIF ( CIF );
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->seqRes.MakeCIF ( CIF );
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->modRes.MakeCIF ( CIF );
+
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ chain[i]->Het.MakeCIF ( CIF );
+
+ hetCompounds.MakeCIF ( CIF );
+ helices .MakeCIF ( CIF );
+ sheets .MakeCIF ( CIF );
+ turns .MakeCIF ( CIF );
+ links .MakeCIF ( CIF );
+ linkRs .MakeCIF ( CIF );
+
+ }
+
+ ERROR_CODE Model::GetCIFPSClass ( mmcif::PData CIF, int ClassID ) {
+ ChainContainer PSClass;
+ PChainContainer Dest;
+ ERROR_CODE RC;
+ cpstr chainID;
+ PChain chn;
+ PSClass.SetChain ( NULL );
+ RC = PSClass.GetCIF ( CIF,ClassID );
+ if (RC!=Error_NoError) return RC;
+ chainID = PSClass.Get1stChainID();
+ while (chainID) {
+ chn = GetChainCreate ( chainID,false );
+ switch (ClassID) {
+ case ClassID_DBReference : Dest = &(chn->DBRef); break;
+ case ClassID_SeqAdv : Dest = &(chn->seqAdv); break;
+ case ClassID_ModRes : Dest = &(chn->modRes); break;
+ case ClassID_Het : Dest = &(chn->Het); break;
+ default : Dest = NULL;
+ }
+ if (Dest) {
+ PSClass.MoveByChainID ( chainID,Dest );
+ Dest->SetChain ( chn );
+ } else
+ printf ( " **** PROGRAM ERROR: wrong call to"
+ " Model::GetCIFPSClass(..)\n" );
+ chainID = PSClass.Get1stChainID();
+ }
+ return Error_NoError;
+ }
+
+ ERROR_CODE Model::GetCIF ( mmcif::PData CIF ) {
+ SeqRes seqRes;
+ ERROR_CODE RC;
+ PChain chn;
+
+ RC = GetCIFPSClass ( CIF,ClassID_DBReference );
+ if (RC!=Error_NoError) return RC;
+
+ RC = GetCIFPSClass ( CIF,ClassID_SeqAdv );
+ if (RC!=Error_NoError) return RC;
+
+ RC = seqRes.GetCIF ( CIF );
+ while (RC==Error_NoError) {
+ chn = GetChainCreate ( seqRes.chainID,false );
+ chn->seqRes.Copy ( &seqRes );
+ RC = seqRes.GetCIF ( CIF );
+ }
+
+ RC = GetCIFPSClass ( CIF,ClassID_ModRes );
+ if (RC!=Error_NoError) return RC;
+
+ RC = GetCIFPSClass ( CIF,ClassID_Het );
+ if (RC!=Error_NoError) return RC;
+
+ hetCompounds.GetCIF ( CIF );
+ helices .GetCIF ( CIF,ClassID_Helix );
+ sheets .GetCIF ( CIF );
+ turns .GetCIF ( CIF,ClassID_Turn );
+ links .GetCIF ( CIF,ClassID_Link );
+ linkRs .GetCIF ( CIF,ClassID_LinkR );
+
+ return RC;
+
+ }
+
+ cpstr Model::GetEntryID() {
+ if (manager) return manager->title.idCode;
+ else return pstr("");
+ }
+
+ void Model::SetEntryID ( const IDCode idCode ) {
+ if (manager)
+ manager->SetEntryID ( idCode );
+ }
+
+ int Model::GetNumberOfAllAtoms() {
+ if (manager) return manager->nAtoms;
+ else return 0;
+ }
+
+ int Model::GetSerNum() {
+ return serNum;
+ }
+
+ PAtom * Model::GetAllAtoms() {
+ if (manager) return manager->atom;
+ else return NULL;
+ }
+
+
+ cpstr Model::GetModelID ( pstr modelID ) {
+ modelID[0] = char(0);
+ sprintf ( modelID,"/%i",serNum );
+ return modelID;
+ }
+
+ int Model::GetNumberOfModels() {
+ if (manager) return manager->nModels;
+ else return 0;
+ }
+
+
+ void Model::Copy ( PModel model ) {
+ // modify both Model::_copy and Model::Copy methods simultaneously!
+ int i;
+
+ FreeMemory();
+
+ if (model) {
+
+ serNum = model->serNum;
+ nChains = model->nChains;
+ nChainsAlloc = nChains;
+ if (nChains>0) {
+ chain = new PChain[nChainsAlloc];
+ for (i=0;i<nChains;i++) {
+ if (model->chain[i]) {
+ chain[i] = newChain();
+ chain[i]->SetModel ( this );
+ chain[i]->Copy ( model->chain[i] );
+ } else
+ chain[i] = NULL;
+ }
+ }
+
+ hetCompounds.Copy ( &(model->hetCompounds) );
+ helices .Copy ( &(model->helices) );
+ sheets .Copy ( &(model->sheets) );
+ turns .Copy ( &(model->turns) );
+ links .Copy ( &(model->links) );
+ linkRs .Copy ( &(model->linkRs) );
+ cisPeps .Copy ( &(model->cisPeps) );
+
+ }
+
+ }
+
+ void Model::CopyHets ( PModel model ) {
+ if (model) hetCompounds.Copy ( &(model->hetCompounds) );
+ }
+
+ void Model::CopySecStructure ( PModel model ) {
+ if (model) {
+ helices.Copy ( &(model->helices) );
+ sheets .Copy ( &(model->sheets) );
+ turns .Copy ( &(model->turns) );
+ }
+ }
+
+ void Model::CopyLinks ( PModel model ) {
+ if (model)links.Copy ( &(model->links) );
+ }
+
+ void Model::CopyLinkRs ( PModel model ) {
+ if (model) linkRs.Copy ( &(model->linkRs) );
+ }
+
+ void Model::CopyCisPeps ( PModel model ) {
+ if (model) cisPeps.Copy ( &(model->cisPeps) );
+ }
+
+ void Model::_copy ( PModel model ) {
+ // modify both Model::_copy and Model::Copy methods simultaneously!
+ int i;
+
+ FreeMemory();
+
+ if (model) {
+
+ serNum = model->serNum;
+ nChains = model->nChains;
+ nChainsAlloc = nChains;
+ if (nChains>0) {
+ chain = new PChain[nChainsAlloc];
+ for (i=0;i<nChains;i++) {
+ if (model->chain[i]) {
+ chain[i] = newChain();
+ chain[i]->SetModel ( this );
+ chain[i]->_copy ( model->chain[i] );
+ } else
+ chain[i] = NULL;
+ }
+ }
+
+ hetCompounds.Copy ( &(model->hetCompounds) );
+ helices .Copy ( &(model->helices) );
+ sheets .Copy ( &(model->sheets) );
+ turns .Copy ( &(model->turns) );
+ links .Copy ( &(model->links) );
+ linkRs .Copy ( &(model->linkRs) );
+ cisPeps .Copy ( &(model->cisPeps) );
+
+ }
+
+ }
+
+
+ void Model::_copy ( PModel model, PPAtom atom, int & atom_index ) {
+ // modify both Model::_copy and Model::Copy methods simultaneously!
+ //
+ // _copy(PModel,PPAtom,int&) does copy atoms into array 'atom'
+ // starting from position atom_index. 'atom' should be able to
+ // accept all new atoms - no checks on the length of 'atom'
+ // is being made. This function should not be used in applications.
+ int i;
+
+ FreeMemory();
+
+ if (model) {
+
+ serNum = model->serNum;
+ nChains = model->nChains;
+ nChainsAlloc = nChains;
+ if (nChains>0) {
+ chain = new PChain[nChainsAlloc];
+ for (i=0;i<nChains;i++) {
+ if (model->chain[i]) {
+ chain[i] = newChain();
+ chain[i]->SetModel ( this );
+ chain[i]->_copy ( model->chain[i],atom,atom_index );
+ } else
+ chain[i] = NULL;
+ }
+ }
+
+ hetCompounds.Copy ( &(model->hetCompounds) );
+ helices .Copy ( &(model->helices) );
+ sheets .Copy ( &(model->sheets) );
+ turns .Copy ( &(model->turns) );
+ links .Copy ( &(model->links) );
+ linkRs .Copy ( &(model->linkRs) );
+
+ }
+
+ }
+
+
+ int Model::AddChain ( PChain chn ) {
+ // modify both Model::Copy methods simultaneously!
+ //
+ // Copy(PModel,PPAtom,int&) copies atoms into array 'atom'
+ // starting from position atom_index. 'atom' should be able to
+ // accept all new atoms - no checks on the length of 'atom'
+ // is being made. This function should not be used in applications.
+ PModel model1;
+ int i;
+
+ for (i=0;i<nChains;i++)
+ if (chain[i]==chn) return -i; // this chain is already there
+
+ if (chn) {
+
+ // get space for new chain
+ ExpandChainArray ( nChains );
+
+ if (chn->GetCoordHierarchy()) {
+ // The chain is associated with a coordinate hierarchy. It should
+ // remain there, therefore we physically copy all its residues
+ // and atoms.
+ chain[nChains] = newChain();
+ chain[nChains]->SetModel ( this );
+ if (manager) {
+ // get space for new atoms
+ manager->AddAtomArray ( chn->GetNumberOfAtoms(true) );
+ chain[nChains]->_copy ( chn,manager->atom,manager->nAtoms );
+ } else {
+ for (i=0;i<chn->nResidues;i++)
+ chain[nChains]->AddResidue ( chn->residue[i] );
+ }
+ } else {
+ // The chain is not associated with a coordinate hierarchy. Such
+ // unregistered objects are simply taken over, i.e. moved into
+ // the new destination (model).
+ chain[nChains] = chn;
+ // remove chain from its model:
+ model1 = chn->GetModel();
+ if (model1)
+ for (i=0;i<model1->nChains;i++)
+ if (model1->chain[i]==chn) {
+ model1->chain[i] = NULL;
+ break;
+ }
+ chain[nChains]->SetModel ( this );
+ if (manager)
+ chain[nChains]->CheckInAtoms();
+ }
+
+ nChains++;
+
+ }
+
+ return nChains;
+
+ }
+
+
+ void Model::MoveChain ( PChain & m_chain, PPAtom m_atom,
+ PPAtom atom, int & atom_index,
+ int chain_ext ) {
+ // MoveChain(..) adds chain m_chain on the top Chain array.
+ // The pointer on chain is then set to NULL (m_chain=NULL).
+ // If chain_ext is greater than 0, the moved chain will be
+ // forcefully renamed; the new name is composed as the previous
+ // one + underscore + chain_ext (e.g. A_1). If thus generated
+ // name duplicates any of existing chain IDs, or if chain_ext
+ // was set to 0 and there is a duplication of chain IDs, the
+ // name is again modified as above, with the extension number
+ // generated automatically (this may result in IDs like
+ // A_1_10).
+ // m_atom must give pointer to the Atom array, from which
+ // the atoms belonging to m_chain, are moved to Atom array
+ // given by 'atom', starting from poisition 'atom_index'.
+ // 'atom_index' is then automatically updated to the next
+ // free position in 'atom'.
+ // Note1: the moved atoms will occupy a continuous range
+ // in 'atom' array; no checks on whether the corresponding
+ // cells are occupied or not, are performed.
+ // Note2: the 'atom_index' is numbered from 0 on, i.e.
+ // it is equal to atom[atom_index]->index-1; atom[]->index
+ // is assigned automatically.
+ ChainID chainID;
+ int i,j,k,Ok;
+ PPChain chain1;
+ PResidue crRes;
+
+ if (!m_chain) return;
+
+ // modify chain ID with the extension given
+ if (chain_ext>0)
+ sprintf ( chainID,"%s_%i",m_chain->chainID,chain_ext );
+ else strcpy ( chainID,m_chain->chainID );
+
+ // Choose the chain ID. If a chain with such ID is
+ // already present in the model, it will be assigned
+ // a new ID 'ID_n', where 'ID' stands for the original
+ // chain ID and 'n' is the minimum (integer) number
+ // chosen such that 'name_n' represents a new chain ID
+ // (in the model).
+ k = 0;
+ do {
+ Ok = true;
+ for (i=0;(i<nChains) && (Ok);i++)
+ if (chain[i])
+ if (!strcmp(chainID,chain[i]->chainID)) Ok = false;
+ if (!Ok) {
+ k++;
+ if (chain_ext>0)
+ sprintf ( chainID,"%s_%i_%i",m_chain->chainID,
+ chain_ext,k );
+ else sprintf ( chainID,"%s_%i",m_chain->chainID,k );
+ }
+ } while (!Ok);
+
+ // add chain on the top of Chain array.
+ strcpy ( m_chain->chainID,chainID );
+ if (nChains>=nChainsAlloc) {
+ nChainsAlloc = nChains+10;
+ chain1 = new PChain[nChainsAlloc];
+ k = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) chain1[k++] = chain[i];
+ for (i=k;i<nChainsAlloc;i++)
+ chain1[i] = NULL;
+ if (chain) delete[] chain;
+ chain = chain1;
+ }
+ chain[nChains] = m_chain;
+ chain[nChains]->SetModel ( this );
+ nChains++;
+
+ // Move all atoms of the chain. While residues belong
+ // atoms belong to the chain's manager class. Therefore
+ // they should be moved from one manager to another.
+ for (i=0;i<m_chain->nResidues;i++) {
+ crRes = m_chain->residue[i];
+ if (crRes)
+ for (j=0;j<crRes->nAtoms;j++)
+ if (crRes->atom[j]) {
+ k = crRes->atom[j]->index-1;
+ atom[atom_index] = m_atom[k];
+ atom[atom_index]->index = atom_index+1;
+ atom_index++;
+ m_atom[k] = NULL; // moved!
+ }
+ }
+
+ m_chain = NULL; // moved!
+
+ }
+
+ void Model::GetAIndexRange ( int & i1, int & i2 ) {
+ PChain chn;
+ PResidue res;
+ int ic,ir,ia;
+ i1 = MaxInt4;
+ i2 = MinInt4;
+ for (ic=0;ic<nChains;ic++) {
+ chn = chain[ic];
+ if (chn) {
+ for (ir=0;ir<chn->nResidues;ir++) {
+ res = chn->residue[ir];
+ if (res) {
+ for (ia=0;ia<res->nAtoms;ia++)
+ if (res->atom[ia]) {
+ if (res->atom[ia]->index<i1) i1 = res->atom[ia]->index;
+ if (res->atom[ia]->index>i2) i2 = res->atom[ia]->index;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+
+ void Model::MaskAtoms ( PMask Mask ) {
+ int i;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) chain[i]->MaskAtoms ( Mask );
+ }
+
+ void Model::MaskResidues ( PMask Mask ) {
+ int i;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) chain[i]->MaskResidues ( Mask );
+ }
+
+ void Model::MaskChains ( PMask Mask ) {
+ int i;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) chain[i]->SetMask ( Mask );
+ }
+
+ void Model::UnmaskAtoms ( PMask Mask ) {
+ int i;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) chain[i]->UnmaskAtoms ( Mask );
+ }
+
+ void Model::UnmaskResidues ( PMask Mask ) {
+ int i;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) chain[i]->UnmaskResidues ( Mask );
+ }
+
+ void Model::UnmaskChains ( PMask Mask ) {
+ int i;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) chain[i]->RemoveMask ( Mask );
+ }
+
+
+ // ------ Getting Secondary Structure Elements
+
+ int Model::GetNumberOfHelices() {
+ return helices.Length();
+ }
+
+ int Model::GetNumberOfSheets() {
+ return sheets.nSheets;
+ }
+
+ PHelix Model::GetHelix ( int serialNum ) {
+ return (PHelix)helices.GetContainerClass ( serialNum-1 );
+ }
+
+ void Model::GetSheetID ( int serialNum, SheetID sheetID ) {
+ if ((1<=serialNum) && (serialNum<=sheets.nSheets)) {
+ if (sheets.sheet[serialNum-1]) {
+ strcpy ( sheetID,sheets.sheet[serialNum-1]->sheetID );
+ return;
+ }
+ }
+ sheetID[0] = char(0);
+ }
+
+ PSheet Model::GetSheet ( int serialNum ) {
+ if ((1<=serialNum) && (serialNum<=sheets.nSheets))
+ return sheets.sheet[serialNum-1];
+ else return NULL;
+ }
+
+ PSheet Model::GetSheet ( const SheetID sheetID ) {
+ int i;
+ for (i=0;i<sheets.nSheets;i++)
+ if (sheets.sheet[i]) {
+ if (!strcmp(sheets.sheet[i]->sheetID,sheetID))
+ return sheets.sheet[i];
+ }
+ return NULL;
+ }
+
+ int Model::GetNumberOfStrands ( int sheetSerNum ) {
+ if ((1<=sheetSerNum) && (sheetSerNum<=sheets.nSheets)) {
+ if (sheets.sheet[sheetSerNum-1])
+ return sheets.sheet[sheetSerNum-1]->nStrands;
+ }
+ return 0;
+ }
+
+ int Model::GetNumberOfStrands ( const SheetID sheetID ) {
+ int i;
+ for (i=0;i<sheets.nSheets;i++)
+ if (sheets.sheet[i]) {
+ if (!strcmp(sheets.sheet[i]->sheetID,sheetID))
+ return sheets.sheet[i]->nStrands;
+ }
+ return 0;
+ }
+
+ PStrand Model::GetStrand ( int sheetSerNum, int strandSerNum ) {
+ PSheet sheet;
+ if ((1<=sheetSerNum) && (sheetSerNum<=sheets.nSheets)) {
+ sheet = sheets.sheet[sheetSerNum-1];
+ if (sheet) {
+ if ((1<=strandSerNum) && (strandSerNum<=sheet->nStrands))
+ return sheet->strand[strandSerNum-1];
+ }
+ }
+ return NULL;
+ }
+
+ PStrand Model::GetStrand ( const SheetID sheetID,
+ int strandSerNum ) {
+ int i;
+ PSheet sheet;
+ for (i=0;i<sheets.nSheets;i++)
+ if (sheets.sheet[i]) {
+ if (!strcmp(sheets.sheet[i]->sheetID,sheetID)) {
+ sheet = sheets.sheet[i];
+ if (sheet) {
+ if ((1<=strandSerNum) && (strandSerNum<=sheet->nStrands))
+ return sheet->strand[strandSerNum-1];
+ }
+ }
+ }
+ return NULL;
+ }
+
+ void Model::RemoveSecStructure() {
+ helices.FreeContainer();
+ sheets .FreeMemory ();
+ turns .FreeContainer();
+ }
+
+ void Model::RemoveHetInfo() {
+ hetCompounds.FreeMemory();
+ }
+
+
+ int Model::GetNumberOfLinks() {
+ return links.Length();
+ }
+
+ PLink Model::GetLink ( int serialNum ) {
+ return (PLink)links.GetContainerClass ( serialNum-1 );
+ }
+
+ void Model::RemoveLinks() {
+ links.FreeContainer();
+ }
+
+ void Model::AddLink ( PLink link ) {
+ links.AddData ( link );
+ }
+
+
+ int Model::GetNumberOfLinkRs() {
+ return linkRs.Length();
+ }
+
+ PLinkR Model::GetLinkR ( int serialNum ) {
+ return (PLinkR)linkRs.GetContainerClass ( serialNum-1 );
+ }
+
+ void Model::RemoveLinkRs() {
+ linkRs.FreeContainer();
+ }
+
+ void Model::AddLinkR ( PLinkR linkR ) {
+ linkRs.AddData ( linkR );
+ }
+
+
+
+ int Model::GetNumberOfCisPeps() {
+ return cisPeps.Length();
+ }
+
+ PCisPep Model::GetCisPep ( int CisPepNum ) {
+ return (PCisPep)cisPeps.GetContainerClass ( CisPepNum-1 );
+ }
+
+ void Model::RemoveCisPeps() {
+ cisPeps.FreeContainer();
+ }
+
+ void Model::AddCisPep ( PCisPep cisPep ) {
+ cisPeps.AddData ( cisPep );
+ }
+
+
+ void Model::ApplyTransform ( mat44 & TMatrix ) {
+ // transforms all coordinates by multiplying with matrix TMatrix
+ int i;
+ for (i=0;i<nChains;i++)
+ if (chain[i]) chain[i]->ApplyTransform ( TMatrix );
+ }
+
+ bool Model::isInSelection ( int selHnd ) {
+ PMask mask;
+ if (manager) {
+ mask = PRoot(manager)->GetSelMask ( selHnd );
+ if (mask) return CheckMask ( mask );
+ }
+ return false;
+ }
+
+
+
+ // ------- user-defined data handlers
+
+ int Model::PutUDData ( int UDDhandle, int iudd ) {
+ if (UDDhandle & UDRF_MODEL)
+ return UDData::putUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Model::PutUDData ( int UDDhandle, realtype rudd ) {
+ if (UDDhandle & UDRF_MODEL)
+ return UDData::putUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Model::PutUDData ( int UDDhandle, cpstr sudd ) {
+ if (UDDhandle & UDRF_MODEL)
+ return UDData::putUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Model::GetUDData ( int UDDhandle, int & iudd ) {
+ if (UDDhandle & UDRF_MODEL)
+ return UDData::getUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Model::GetUDData ( int UDDhandle, realtype & rudd ) {
+ if (UDDhandle & UDRF_MODEL)
+ return UDData::getUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Model::GetUDData ( int UDDhandle, pstr sudd, int maxLen ) {
+ if (UDDhandle & UDRF_MODEL)
+ return UDData::getUDData ( UDDhandle,sudd,maxLen );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Model::GetUDData ( int UDDhandle, pstr & sudd ) {
+ if (UDDhandle & UDRF_MODEL)
+ return UDData::getUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+
+ // ------- calculation of Secondary Structure
+
+
+ int Model::CalcSecStructure ( bool flagBulge, int aminoSelHnd ) {
+ // This function is contributed by Liz Potterton, University of York
+ //------------------------------------------------------------------
+ // Define a secondary structure type of each amino acid residue in the
+ // structure.
+ // Procedure:
+ // Find all amino acids
+ // Find all pairs of amino acids which have inter-Ca distance < 10.0A
+ // Test for hydrogen bonds between the main chain N and O of the close
+ // residues and store the information in the hbonds matrix
+ // Analyse the info in hbonds matrix to assign secondary structure to
+ // secstr vector
+ PPResidue Res;
+ PPAtom Ca;
+ PChain chn;
+ PContact contact;
+ imatrix hbonds;
+ PPAtom * hbond_atoms;
+ int nres, ncontacts;
+ int ir1,ir2, irdif;
+ int i,j,k,l;
+
+ // 1a. Get protein residues from selection handle
+
+ if (aminoSelHnd>=0) {
+
+ manager->GetSelIndex(aminoSelHnd,Res,nres);
+ // printf ( " nres %3i " ,nres );
+ if (nres<=0) return SSERC_noResidues;
+
+ } else {
+
+ // 1b. Get all protein residues
+
+ nres = 0;
+ for (i=0;i<nChains;i++)
+ if (chain[i])
+ nres += chain[i]->nResidues;
+
+ if (nres<=0) return SSERC_noResidues;
+
+ Res = new PResidue[nres];
+ nres = 0;
+ for (i=0;i<nChains;i++) {
+ chn = chain[i];
+ if (chn) {
+ k = chn->nResidues;
+ for (j=0;j<k;j++)
+ Res[nres++] = chn->residue[j];
+ }
+ }
+
+
+ if (nres<=0) {
+ delete[] Res;
+ return SSERC_noResidues;
+ }
+
+ }
+
+ // 2. Get C-alphas of all aminoacids
+
+ Ca = new PAtom[nres];
+ k = 0;
+ for (i=0;i<nres;i++)
+ if (Res[i]) {
+ if (aminoSelHnd>=0 || Res[i]->isAminoacid()) {
+ Ca[i] = Res[i]->GetAtom("CA", " C", "*");
+ k++;
+ } else
+ Ca[i] = NULL;
+ Res[i]->SSE = SSE_None;
+ } else
+ Ca[i] = NULL;
+
+ if (k<=0) {
+ delete[] Res;
+ delete[] Ca;
+ return SSERC_noAminoacids;
+ }
+
+
+ // 3. Find all close Calphas - i.e. find the contacts between
+ // the two equivalent sets of Ca atoms
+
+ contact = NULL;
+ ncontacts = 0;
+ manager->SeekContacts ( Ca,nres, Ca,nres, 2.0,10.0, 2,
+ contact,ncontacts,0 );
+ if (ncontacts<=0) {
+ delete[] Res;
+ delete[] Ca;
+ if (contact) delete[] contact;
+ return SSERC_noSSE;
+ }
+
+
+ // 4. Get and initialize memory for analysing the SSE
+
+ GetMatrixMemory ( hbonds,nres,3,0,0 );
+ hbond_atoms = new PPAtom[nres];
+ for (i=0;i<nres;i++) {
+ hbond_atoms[i] = new PAtom[6];
+ for (j=0;j<6;j++) hbond_atoms[i][j] = NULL;
+ for (j=0;j<3;j++) hbonds [i][j] = 0;
+ }
+
+
+ // 5. Loop over all close (in space) residues - excluding those
+ // that are close in sequence
+
+ for (i=0;i<ncontacts;i++) {
+ ir1 = contact[i].id2;
+ ir2 = contact[i].id1;
+ irdif = ir1 - ir2;
+ if (irdif>2) {
+ // test if there is donor Hbond from residue ir1
+ if (Res[ir1]->isMainchainHBond(Res[ir2])) {
+ k = 0;
+ while ((hbonds[ir1][k]!=0) && (k<2)) k++;
+ hbonds [ir1][k] = -irdif;
+ hbond_atoms[ir1][k] = Res[ir1]->GetAtom ( "N" );
+ hbond_atoms[ir1][k+3] = Res[ir2]->GetAtom ( "O" );
+ }
+ // test if there is donor Hbond from residue ir2
+ if (Res[ir2]->isMainchainHBond(Res[ir1])) {
+ k = 0;
+ while ((hbonds[ir2][k]!=0) && (k<2)) k++;
+ hbonds [ir2][k] = irdif;
+ hbond_atoms[ir2][k] = Res[ir2]->GetAtom ( "N" );
+ hbond_atoms[ir2][k+3] = Res[ir1]->GetAtom ( "O" );
+ }
+ }
+ }
+
+ // 6. Assign the turns - if there is bifurcated bond then the 4-turn
+ // takes precedence - read the paper to make sense of this
+
+ for (i=0;i<nres;i++) {
+ k = 0;
+ while ((k<=2) && (hbonds[i][k]!=0)) {
+ if (hbonds[i][k]==-5) {
+ Res[i-1]->SSE = SSE_5Turn;
+ Res[i-2]->SSE = SSE_5Turn;
+ Res[i-3]->SSE = SSE_5Turn;
+ Res[i-4]->SSE = SSE_5Turn;
+ }
+ if (hbonds[i][k]==-3) {
+ Res[i-1]->SSE = SSE_3Turn;
+ Res[i-2]->SSE = SSE_3Turn;
+ }
+ k++;
+ }
+ }
+ for (i=0;i<nres;i++) {
+ k = 0;
+ while ((k<=2) && (hbonds[i][k]!=0)) {
+ if (hbonds[i][k]==-4) {
+ Res[i-1]->SSE = SSE_4Turn;
+ Res[i-2]->SSE = SSE_4Turn;
+ Res[i-3]->SSE = SSE_4Turn;
+ }
+ k++;
+ }
+ }
+
+
+ // 7. Look for consecutive 4-turns which make alpha helix
+
+ for (i=1;i<nres-3;i++) {
+ if (((Res[i ]->SSE==SSE_Helix) || (Res[i ]->SSE==SSE_4Turn)) &&
+ ((Res[i+1]->SSE==SSE_Helix) || (Res[i+1]->SSE==SSE_4Turn)) &&
+ ((Res[i+2]->SSE==SSE_Helix) || (Res[i+2]->SSE==SSE_4Turn)) &&
+ ((Res[i+3]->SSE==SSE_Helix) || (Res[i+3]->SSE==SSE_4Turn)))
+ for (j=i;j<=i+3;j++) Res[j]->SSE = SSE_Helix;
+ }
+
+ for (i=0;i<nres;i++) {
+
+ k = 0;
+ while ((k<=2) && (hbonds[i][k]!=0)) {
+
+ irdif = hbonds[i][k];
+ // Test for 'close' hbond
+ j = i + irdif;
+ l = 0;
+ while ((l<=2) && (hbonds[j][l]!=0)) {
+ // Antiparallel strands
+ if (hbonds[j][l]==-irdif) {
+ Res[i]->SSE = SSE_Strand;
+ Res[j]->SSE = SSE_Strand;
+ }
+ // Parallel strand
+ if (hbonds[j][l]==-irdif-2) {
+ Res[i-1]->SSE = SSE_Strand;
+ Res[j ]->SSE = SSE_Strand;
+ }
+ // Parallel beta bulge
+ if (hbonds[j][l]==-irdif-3) {
+ if (flagBulge) {
+ if (Res[i-1]->SSE==SSE_None) Res[i-1]->SSE = SSE_Bulge;
+ if (Res[i-2]->SSE==SSE_None) Res[i-2]->SSE = SSE_Bulge;
+ if (Res[j ]->SSE==SSE_None) Res[j ]->SSE = SSE_Bulge;
+ } else {
+ if (Res[i-1]->SSE==SSE_None) Res[i-1]->SSE = SSE_Strand;
+ if (Res[i-2]->SSE==SSE_None) Res[i-2]->SSE = SSE_Strand;
+ if (Res[j ]->SSE==SSE_None) Res[j ]->SSE = SSE_Strand;
+ }
+ }
+ l++;
+ }
+ // Test for 'wide' hbond
+ j = i + hbonds[i][k] + 2;
+ if (j<nres) {
+ l = 0;
+ while ((l<=2) && (hbonds[j][l]!=0)) {
+ // Antiaprallel strands
+ if (hbonds[j][l]==-irdif-4) {
+ Res[i-1]->SSE = SSE_Strand;
+ Res[j-1]->SSE = SSE_Strand;
+ }
+ // Parallel strands
+ if (hbonds[j][l]==-irdif-2) {
+ Res[i ]->SSE = SSE_Strand;
+ Res[j-1]->SSE = SSE_Strand;
+ }
+ l++;
+ }
+ }
+
+ // test for anti-parallel B-bulge between 'close' hbonds
+ j = i + hbonds[i][k] - 1;
+ if (j>=0) {
+ l = 0;
+ while ((l<=2) && (hbonds[j][l]!=0)) {
+ if (hbonds[j][l]==-irdif+1) {
+ if (flagBulge) {
+ if (Res[i ]->SSE==SSE_None) Res[i ]->SSE = SSE_Bulge;
+ if (Res[j+1]->SSE==SSE_None) Res[j+1]->SSE = SSE_Bulge;
+ if (Res[j ]->SSE==SSE_None) Res[j ]->SSE = SSE_Bulge;
+ } else {
+ if (Res[i ]->SSE==SSE_None) Res[i ]->SSE = SSE_Strand;
+ if (Res[j+1]->SSE==SSE_None) Res[j+1]->SSE = SSE_Strand;
+ if (Res[j ]->SSE==SSE_None) Res[j ]->SSE = SSE_Strand;
+ }
+ }
+ l++;
+ }
+ }
+
+ // test for anti-parallel B-bulge between 'wide' hbonds
+ j = i + hbonds[i][k] + 3;
+ if (j<nres) {
+ l = 0;
+ while ((l<=2) && (hbonds[j][l]!=0)) {
+ if ((hbonds[j][l]==-irdif+5) && (i>0)) {
+ if (flagBulge) {
+ if (Res[i-1]->SSE==SSE_None) Res[i-1]->SSE = SSE_Bulge;
+ if (Res[j-1]->SSE==SSE_None) Res[j-1]->SSE = SSE_Bulge;
+ if (Res[j-2]->SSE==SSE_None) Res[j-2]->SSE = SSE_Bulge;
+ } else {
+ if (Res[i-1]->SSE==SSE_None) Res[i-1]->SSE = SSE_Strand;
+ if (Res[j-1]->SSE==SSE_None) Res[j-1]->SSE = SSE_Strand;
+ if (Res[j-2]->SSE==SSE_None) Res[j-2]->SSE = SSE_Strand;
+ }
+ } else if (hbonds[j][l]==-irdif-3) {
+ // and bulge in parallel strand
+ if (flagBulge) {
+ if (Res[i ]->SSE==SSE_None) Res[i ]->SSE = SSE_Bulge;
+ if (Res[j-1]->SSE==SSE_None) Res[j-1]->SSE = SSE_Bulge;
+ if (Res[j-2]->SSE==SSE_None) Res[j-2]->SSE = SSE_Bulge;
+ }
+ else {
+ if (Res[i ]->SSE==SSE_None) Res[i ]->SSE = SSE_Strand;
+ if (Res[j-1]->SSE==SSE_None) Res[j-1]->SSE = SSE_Strand;
+ if (Res[j-2]->SSE==SSE_None) Res[j-2]->SSE = SSE_Strand;
+ }
+ }
+ l++;
+ }
+ }
+ k++;
+
+ } // Finish looping over Hbonds for residue (k loop)
+
+ } // Finish looping over residues ( i loop)
+
+
+ // 8. Free memory
+
+ if (hbond_atoms) {
+ for (i=0;i<nres;i++)
+ if (hbond_atoms[i]) delete[] hbond_atoms[i];
+ delete[] hbond_atoms;
+ }
+ FreeMatrixMemory ( hbonds,nres,0,0 );
+ if (contact) delete[] contact;
+ if (Res && aminoSelHnd<0) delete[] Res;
+ if (Ca) delete[] Ca;
+
+ return SSERC_Ok;
+
+ }
+
+
+ // ------- streaming
+
+ void Model::write ( io::RFile f ) {
+ int i,k;
+ byte Version=3;
+
+ f.WriteByte ( &Version );
+
+ ProModel::write ( f );
+
+ f.WriteInt ( &serNum );
+ f.WriteInt ( &nChains );
+
+ for (i=0;i<nChains;i++) {
+ if (chain[i]) k = 1;
+ else k = 0;
+ f.WriteInt ( &k );
+ if (chain[i]) chain[i]->write ( f );
+ }
+
+ hetCompounds.write ( f );
+ helices .write ( f );
+ sheets .write ( f );
+ turns .write ( f );
+ links .write ( f );
+ linkRs .write ( f );
+
+ }
+
+ void Model::read ( io::RFile f ) {
+ int i,k;
+ byte Version;
+
+ FreeMemory();
+
+ f.ReadByte ( &Version );
+
+ ProModel::read ( f );
+
+ f.ReadInt ( &serNum );
+ f.ReadInt ( &nChains );
+ nChainsAlloc = nChains;
+ if (nChains>0) {
+ chain = new PChain[nChainsAlloc];
+ for (i=0;i<nChains;i++) {
+ f.ReadInt ( &k );
+ if (k) {
+ chain[i] = newChain();
+ chain[i]->SetModel ( this );
+ chain[i]->read ( f );
+ }
+ }
+ }
+
+ hetCompounds.read ( f );
+ helices .read ( f );
+ sheets .read ( f );
+ turns .read ( f );
+ if (Version>1) links .read ( f );
+ if (Version>2) linkRs.read ( f );
+
+ }
+
+ MakeFactoryFunctions(Model)
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_model.h b/mmdb2/mmdb_model.h
new file mode 100644
index 0000000..3e184a9
--- /dev/null
+++ b/mmdb2/mmdb_model.h
@@ -0,0 +1,1073 @@
+// $Id: mmdb_model.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Model <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::HetCompound ( description of het compounds )
+// ~~~~~~~~~ mmdb::HetCompounds (HETNAM, HETSYN, FORMULA records)
+// mmdb::SSContainer (container for helixes and turns)
+// mmdb::Helix ( helix info )
+// mmdb::Strand ( strand info )
+// mmdb::Sheet ( sheet info )
+// mmdb::Sheets ( container for sheets )
+// mmdb::Turn ( turn info )
+// mmdb::LinkContainer ( container for link data )
+// mmdb::Link ( link data )
+// mmdb::LinkRContainer ( container for refmac link )
+// mmdb::LinkR ( link data )
+// mmdb::CisPepContainer ( container for CisPep data )
+// mmdb::CisPep ( CisPep data )
+// mmdb::Model ( PDB model )
+//
+// Copyright (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Model__
+#define __MMDB_Model__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_utils.h"
+#include "mmdb_chain.h"
+#include "mmdb_defs.h"
+
+namespace mmdb {
+
+ // ==================== HetCompound =======================
+
+ DefineClass(HetCompound);
+ DefineStreamFunctions(HetCompound);
+
+ class HetCompound : public io::Stream {
+
+ public :
+
+ ResName hetID; // Het identifiers, right-justified
+ pstr comment;
+ int nSynonyms;
+ psvector hetSynonym; // synonyms
+ int compNum; // component number
+ char wc; // '*' for water, otherwise space
+ pstr Formula; // formulas
+
+ HetCompound ( cpstr HetName );
+ HetCompound ( io::RPStream Object );
+ ~HetCompound();
+
+ void AddKeyWord ( cpstr W, bool Closed );
+ void HETNAM_PDBDump ( io::RFile f );
+ void HETSYN_PDBDump ( io::RFile f );
+ void FORMUL_PDBDump ( io::RFile f );
+
+ void FormComString ( pstr & F );
+ void FormSynString ( pstr & F );
+ void FormForString ( pstr & F );
+
+ void Copy ( PHetCompound hetCompound );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitHetCompound ( cpstr HetName );
+ void FreeMemory ();
+
+ };
+
+
+ // ==================== SSContainer ======================
+
+ DefineClass(SSContainer);
+ DefineStreamFunctions(SSContainer);
+
+ class SSContainer : public ClassContainer {
+
+ public :
+
+ SSContainer () : ClassContainer() {}
+ SSContainer ( io::RPStream Object )
+ : ClassContainer ( Object ) {}
+ ~SSContainer () {}
+
+ PContainerClass MakeContainerClass ( int ClassID );
+
+ };
+
+
+ // ==================== Helix ============================
+
+ DefineClass(Helix);
+ DefineStreamFunctions(Helix);
+
+ class Helix : public ContainerClass {
+
+ public :
+ int serNum; // serial number
+ HelixID helixID; // helix ID
+ ResName initResName; // name of the helix's initial residue
+ ChainID initChainID; // chain ID for the chain containing the helix
+ int initSeqNum; // sequence number of the initial residue
+ InsCode initICode; // insertion code of the initial residue
+ ResName endResName; // name of the helix's terminal residue
+ ChainID endChainID; // chain ID for the chain containing the helix
+ int endSeqNum; // sequence number of the terminal residue
+ InsCode endICode; // insertion code of the terminal residue
+ int helixClass; // helix class
+ pstr comment; // comment about the helix
+ int length; // length of the helix
+
+ Helix ();
+ Helix ( cpstr S );
+ Helix ( io::RPStream Object );
+ ~Helix();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_Helix; }
+
+ void Copy ( PContainerClass Helix );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitHelix();
+
+ };
+
+
+
+ // ==================== Strand ============================
+
+ DefineClass(Strand);
+ DefineStreamFunctions(Strand);
+
+ class Strand : public io::Stream {
+
+ public :
+
+ StrandID sheetID; // sheet ID
+ int strandNo; // strand number
+ ResName initResName; // name of the strand's initial residue
+ ChainID initChainID; // chain ID of initial residue in the strand
+ int initSeqNum; // sequence number of the initial residue
+ InsCode initICode; // insertion code of the initial residue
+ ResName endResName; // name of the strand's terminal residue
+ ChainID endChainID; // chain ID of terminal residue in the strand
+ int endSeqNum; // sequence number of the terminal residue
+ InsCode endICode; // insertion code of the terminal residue
+ int sense; // sense of strand with respect to previous
+ // strand
+ AtomName curAtom; // registration; atom name in current strand
+ ResName curResName; // registration; residue name in current
+ // strand
+ ChainID curChainID; // registration; chain ID in current strand
+ int curResSeq; // registration; res-e seq numb in current
+ // strand
+ InsCode curICode; // registration; ins code in current strand
+ AtomName prevAtom; // registration; atom name in previous strand
+ ResName prevResName; // registration; residue name in previous
+ // strand
+ ChainID prevChainID; // registration; chain ID in previous strand
+ int prevResSeq; // registration; res-e seq numb in previous
+ // strand
+ InsCode prevICode; // registration; ins code in previous strand
+
+ Strand ();
+ Strand ( io::RPStream Object );
+ ~Strand();
+
+ void PDBASCIIDump ( pstr S );
+ void MakeCIF ( mmcif::PData CIF );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ int GetCIF ( mmcif::PData CIF, cpstr sheet_id );
+
+ void Copy ( PStrand Strand );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitStrand();
+
+ };
+
+
+ // ==================== Sheet ============================
+
+ DefineClass(Sheet);
+ DefineStreamFunctions(Sheet);
+
+ class Sheet : public io::Stream {
+
+ public :
+ SheetID sheetID; // sheet ID
+ int nStrands; // number of strands in the sheet
+ PPStrand strand; // array of strands
+
+ Sheet ();
+ Sheet ( io::RPStream Object );
+ ~Sheet();
+
+ void FreeMemory();
+ void OrderSheet();
+
+ void PDBASCIIDump ( io::RFile f );
+ void MakeCIF ( mmcif::PData CIF );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ int GetCIF ( mmcif::PData CIF );
+
+ void Copy ( PSheet sheet );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ void InitSheet ();
+ void CIFFindStrands ( mmcif::PData CIF, cpstr Category );
+ void TryStrand ( int strand_no );
+ int GetStrand ( int strand_no );
+
+ };
+
+
+ // ==================== Sheets ============================
+
+ DefineClass(Sheets);
+ DefineStreamFunctions(Sheets);
+
+ class Sheets : public io::Stream {
+
+ public :
+ int nSheets;
+ PPSheet sheet;
+
+ Sheets ();
+ Sheets ( io::RPStream Object );
+ ~Sheets();
+
+ void FreeMemory();
+
+ void PDBASCIIDump ( io::RFile f );
+ void MakeCIF ( mmcif::PData CIF );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ int GetCIF ( mmcif::PData CIF );
+
+ void Copy ( PSheets Sheets );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ void InitSheets ();
+ void CIFFindSheets ( mmcif::PData CIF, cpstr Category );
+
+ };
+
+
+ // ==================== Turn ============================
+
+ DefineClass(Turn);
+ DefineStreamFunctions(Turn);
+
+ class Turn : public ContainerClass {
+
+ public :
+ int serNum; // serial number
+ TurnID turnID; // turn ID
+ ResName initResName; // name of the turn's initial residue
+ ChainID initChainID; // chain ID for the chain containing the turn
+ int initSeqNum; // sequence number of the initial residue
+ InsCode initICode; // insertion code of the initial residue
+ ResName endResName; // name of the turn's terminal residue
+ ChainID endChainID; // chain ID for the chain containing the turn
+ int endSeqNum; // sequence number of the terminal residue
+ InsCode endICode; // insertion code of the terminal residue
+ pstr comment; // comment about the helix
+
+ Turn ();
+ Turn ( cpstr S );
+ Turn ( io::RPStream Object );
+ ~Turn();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_Turn; }
+
+ void Copy ( PContainerClass turn );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitTurn();
+
+ };
+
+
+
+ // ==================== HetCompounds =======================
+
+ DefineClass(HetCompounds);
+ DefineStreamFunctions(HetCompounds);
+
+ class HetCompounds : public io::Stream {
+
+ public :
+
+ int nHets;
+ PPHetCompound hetCompound;
+
+ HetCompounds ();
+ HetCompounds ( io::RPStream Object );
+ ~HetCompounds();
+
+ void FreeMemory ();
+
+ void PDBASCIIDump ( io::RFile f );
+ void ConvertHETNAM ( cpstr S );
+ void ConvertHETSYN ( cpstr S );
+ void ConvertFORMUL ( cpstr S );
+
+ void MakeCIF ( mmcif::PData CIF );
+ ERROR_CODE GetCIF ( mmcif::PData CIF );
+
+ void Copy ( PHetCompounds hetCompounds );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ bool Closed;
+
+ void InitHetCompounds();
+ int AddHetName ( cpstr H );
+
+ };
+
+
+ // =================== LinkContainer =====================
+
+ DefineClass(LinkContainer);
+ DefineStreamFunctions(LinkContainer);
+
+ class LinkContainer : public ClassContainer {
+
+ public :
+
+ LinkContainer () : ClassContainer() {}
+ LinkContainer ( io::RPStream Object )
+ : ClassContainer ( Object ) {}
+ ~LinkContainer () {}
+
+ PContainerClass MakeContainerClass ( int ClassID );
+
+ };
+
+
+ // ==================== Link ============================
+
+ DefineClass(Link);
+ DefineStreamFunctions(Link);
+
+ class Link : public ContainerClass {
+
+ public :
+ AtomName atName1; // name of 1st linked atom
+ AltLoc aloc1; // alternative location of 1st linked atom
+ ResName resName1; // residue name of 1st linked atom
+ ChainID chainID1; // chain ID of 1st linked atom
+ int seqNum1; // sequence number of 1st linked atom
+ InsCode insCode1; // insertion code of 1st linked atom
+ AtomName atName2; // name of 2nd linked atom
+ AltLoc aloc2; // alternative location of 2nd linked atom
+ ResName resName2; // residue name of 2nd linked atom
+ ChainID chainID2; // chain ID of 2nd linked atom
+ int seqNum2; // sequence number of 2nd linked atom
+ InsCode insCode2; // insertion code of 2nd linked atom
+ int s1,i1,j1,k1; // sym id of 1st atom
+ int s2,i2,j2,k2; // sym id of 2nd atom
+
+ Link ();
+ Link ( cpstr S );
+ Link ( io::RPStream Object );
+ ~Link();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_Link; }
+
+ void Copy ( PContainerClass link );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitLink();
+
+ };
+
+ // =================== LinkRContainer ====================
+
+ DefineClass(LinkRContainer);
+ DefineStreamFunctions(LinkRContainer);
+
+ class LinkRContainer : public ClassContainer {
+
+ public :
+
+ LinkRContainer () : ClassContainer() {}
+ LinkRContainer ( io::RPStream Object )
+ : ClassContainer ( Object ) {}
+ ~LinkRContainer () {}
+
+ PContainerClass MakeContainerClass ( int ClassID );
+
+ };
+
+
+ // ==================== LinkR ============================
+
+ DefineClass(LinkR);
+ DefineStreamFunctions(LinkR);
+
+ /*
+
+ Garib's
+ LINK LYS A 27 PLP A 255 PLPLYS
+ LINK MAN S 3 MAN S 4 BETA1-4
+ LINK C6 BBEN B 1 O1 BMAF S 2 BEN-MAF
+ LINK OE2 AGLU A 320 C1 AMAF S 2 GLU-MAF
+ LINK OE2 GLU A 67 1.895 ZN ZN R 5 GLU-ZN
+ LINK NE2 HIS A 71 2.055 ZN ZN R 5 HIS-ZN
+ LINK O ARG A 69 2.240 NA NA R 9 ARG-NA
+
+ Coot's
+ LINKR O VAL C 103 NA NA C 401 VAL-NA
+ LINKR OD1 ASP D 58 NA NA D 401 ASP-NA
+ LINKR O ALA D 97 NA NA D 401 ALA-NA
+ LINKR OG1 THR D 99 NA NA D 401 THR-NA
+ LINKR O SER D 101 NA NA D 401 SER-NA
+ LINKR O VAL D 103 NA NA D 401 VAL-NA
+
+ PDB's
+ LINK O GLY A 49 NA NA A6001 1555 1555 2.98
+ LINK OG1 THR A 51 NA NA A6001 1555 1555 2.72
+ LINK OD2 ASP A 66 NA NA A6001 1555 1555 2.72
+ LINK NE ARG A 68 NA NA A6001 1555 1555 2.93
+
+ LINK NE ARG A 68 NA NA A6001 1555 1555 2.93
+ LINK C21 2EG A 7 C22 2EG B 19 1555 1555 1.56
+ */
+
+ class LinkR : public ContainerClass {
+
+ public :
+ LinkRID linkRID; // link name
+ AtomName atName1; // name of 1st linked atom
+ AltLoc aloc1; // alternative location of 1st linked atom
+ ResName resName1; // residue name of 1st linked atom
+ ChainID chainID1; // chain ID of 1st linked atom
+ int seqNum1; // sequence number of 1st linked atom
+ InsCode insCode1; // insertion code of 1st linked atom
+ AtomName atName2; // name of 2nd linked atom
+ AltLoc aloc2; // alternative location of 2nd linked atom
+ ResName resName2; // residue name of 2nd linked atom
+ ChainID chainID2; // chain ID of 2nd linked atom
+ int seqNum2; // sequence number of 2nd linked atom
+ InsCode insCode2; // insertion code of 2nd linked atom
+ realtype dist; // link distance
+
+ LinkR ();
+ LinkR ( cpstr S );
+ LinkR ( io::RPStream Object );
+ ~LinkR();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_LinkR; }
+
+ void Copy ( PContainerClass LinkR );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitLinkR();
+
+ };
+
+
+
+ // =================== CisPepContainer =====================
+
+ DefineClass(CisPepContainer);
+ DefineStreamFunctions(CisPepContainer);
+
+ class CisPepContainer : public ClassContainer {
+
+ public :
+
+ CisPepContainer () : ClassContainer() {}
+ CisPepContainer ( io::RPStream Object )
+ : ClassContainer ( Object ) {}
+ ~CisPepContainer () {}
+
+ PContainerClass MakeContainerClass ( int ClassID );
+
+ };
+
+
+ // ===================== CisPep ===========================
+
+ DefineClass(CisPep);
+ DefineStreamFunctions(CisPep);
+
+ class CisPep : public ContainerClass {
+
+ public :
+ int serNum; // record serial number
+ ResName pep1; // residue name
+ ChainID chainID1; // chain identifier 1
+ int seqNum1; // residue sequence number 1
+ InsCode icode1; // insertion code 1
+ ResName pep2; // residue name 2
+ ChainID chainID2; // chain identifier 2
+ int seqNum2; // residue sequence number 2
+ InsCode icode2; // insertion code 2
+ int modNum; // model number
+ realtype measure; // measure of the angle in degrees.
+
+ CisPep ();
+ CisPep ( cpstr S );
+ CisPep ( io::RPStream Object );
+ ~CisPep();
+
+ void PDBASCIIDump ( pstr S, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ CLASS_ID GetClassID () { return ClassID_CisPep; }
+
+ void Copy ( PContainerClass cisPep );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitCisPep();
+
+ };
+
+
+
+ // ==================== Model ===============================
+
+ enum SSE_RC {
+ SSERC_Ok = 0,
+ SSERC_noResidues = 1,
+ SSERC_noAminoacids = 2,
+ SSERC_noSSE = 3
+ };
+
+ enum SORT_CHAIN_DIR {
+ SORT_CHAIN_ChainID_Asc = 0,
+ SORT_CHAIN_ChainID_Desc = 1
+ };
+
+ DefineFactoryFunctions(Model);
+
+ class Model : public ProModel {
+
+ friend class Manager;
+ friend class BondManager;
+ friend class SelManager;
+ friend class CoorManager;
+ friend class Root;
+ friend class Chain;
+ friend class Residue;
+ friend class Atom;
+
+ public :
+
+ Model (); // SetMMDBFile() MUST be used after this constructor!
+ Model ( PManager MMDBF, int serialNum );
+ Model ( io::RPStream Object );
+ ~Model();
+
+ void SetMMDBManager ( PManager MMDBM, int serialNum );
+ PManager GetCoordHierarchy() { return manager; }
+
+ // GetChainCreate() returns pointer on chain, whose identifier
+ // is given in chID. If such a chain is absent in the model,
+ // it is created. If enforceUniqueChainID is true and chain with
+ // the same first letter in chain ID already exists in the model,
+ // then the new chain ID will be appended with a serial number
+ // in order to keep it unique. The model will contain chains like
+ // A, A0, A1, A2, ... in such cases.
+ PChain GetChainCreate ( const ChainID chID,
+ bool enforceUniqueChainID );
+
+ // CreateChain() creates a new chain with chain ID regardless
+ // the presence of same-ID chains in the model. This function
+ // was introduced only for compatibility with older CCP4
+ // applications and using it in any new developments should be
+ // strictly discouraged.
+ PChain CreateChain ( const ChainID chID );
+
+ cpstr GetEntryID ();
+ void SetEntryID ( const IDCode idCode );
+
+ int GetSerNum (); // returns the model's serial number
+
+ cpstr GetModelID ( pstr modelID ); // returns "/mdl"
+
+ int GetNumberOfModels (); // returns TOTAL number of models
+ int GetNumberOfAtoms ( bool countTers ); // returns number
+ // of atoms in the model
+ int GetNumberOfResidues(); // returns number of residues in
+ // the model
+
+
+ // ---------------- Extracting chains --------------------------
+
+ int GetNumberOfChains(); // returns number of chains in the model
+ bool GetNewChainID ( ChainID chID, int length=1 );
+ // GetChain() returns pointer on chain, whose identifier
+ // is given in chID. If such a chain is absent in the model,
+ // returns NULL.
+ PChain GetChain ( const ChainID chID );
+ PChain GetChain ( int chainNo ); // returns chainNo-th chain
+ // in the model;
+ // 0<=chainNo<nChains
+ void GetChainTable ( PPChain & chainTable,
+ int & NumberOfChains );
+
+ // ------------------ Deleting chains --------------------------
+
+ int DeleteChain ( const ChainID chID );
+ int DeleteChain ( int chainNo );
+ int DeleteAllChains ();
+ int DeleteSolventChains();
+ void TrimChainTable ();
+
+ // ------------------- Adding chains ---------------------------
+
+ int AddChain ( PChain chn );
+
+ // -------------------- Sort chains ----------------------------
+
+ void SortChains ( int sortKey ); // SORT_CHAIN_XXXX
+
+ // ---------------- Extracting residues ------------------------
+
+ int GetNumberOfResidues ( const ChainID chainID );
+ int GetNumberOfResidues ( int chainNo );
+ PResidue GetResidue ( const ChainID chainID, int seqNo,
+ const InsCode insCode );
+ PResidue GetResidue ( const ChainID chainID, int resNo );
+ PResidue GetResidue ( int chainNo, int seqNo,
+ const InsCode insCode );
+ PResidue GetResidue ( int chainNo, int resNo );
+ int GetResidueNo ( const ChainID chainID, int seqNo,
+ const InsCode insCode );
+ int GetResidueNo ( int chainNo, int seqNo,
+ const InsCode insCode );
+ void GetResidueTable ( PPResidue & resTable,
+ int & NumberOfResidues );
+ void GetResidueTable ( const ChainID chainID,
+ PPResidue & resTable,
+ int & NumberOfResidues );
+ void GetResidueTable ( int chainNo, PPResidue & resTable,
+ int & NumberOfResidues );
+
+ // ----------------- Deleting residues -------------------------
+
+ int DeleteResidue ( const ChainID chainID, int seqNo,
+ const InsCode insCode );
+ int DeleteResidue ( const ChainID chainID, int resNo );
+ int DeleteResidue ( int chainNo, int seqNo,
+ const InsCode insCode );
+ int DeleteResidue ( int chainNo, int resNo );
+ int DeleteAllResidues ( const ChainID chainID );
+ int DeleteAllResidues ( int chainNo );
+ int DeleteSolvent (); // in difference of DeleteSolventChains,
+ // this will remove all solvent molecules
+ // from the file rather then
+ // solely-solvent chains
+ int DeleteAllResidues ();
+
+ // ------------------ Adding residues --------------------------
+
+ int AddResidue ( const ChainID chainID, PResidue res );
+ int AddResidue ( int chainNo, PResidue res );
+
+ // ------------------- Extracting atoms ------------------------
+
+ int GetNumberOfAllAtoms(); // returns TOTAL number of atoms in all
+ // models
+ PPAtom GetAllAtoms (); // returns pointer to Atom array
+
+ int GetNumberOfAtoms ( const ChainID chainID, int seqNo,
+ const InsCode insCode );
+ int GetNumberOfAtoms ( int chainNo, int seqNo,
+ const InsCode insCode );
+ int GetNumberOfAtoms ( const ChainID chainID, int resNo );
+ int GetNumberOfAtoms ( int chainNo, int resNo );
+
+ PAtom GetAtom ( const ChainID chID,
+ int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ PAtom GetAtom ( const ChainID chID, int seqNo,
+ const InsCode insCode, int atomNo );
+ PAtom GetAtom ( const ChainID chID,
+ int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ PAtom GetAtom ( const ChainID chID, int resNo, int atomNo );
+ PAtom GetAtom ( int chNo, int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ PAtom GetAtom ( int chNo, int seqNo, const InsCode insCode,
+ int atomNo );
+ PAtom GetAtom ( int chNo, int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ PAtom GetAtom ( int chNo, int resNo, int atomNo );
+
+ void GetAtomTable ( const ChainID chainID, int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable ( int chainNo, int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable ( const ChainID chainID, int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable ( int chainNo, int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+
+ // GetAtomTable1(..) returns atom table without TER atoms and
+ // without NULL atom pointers. NumberOfAtoms returns the actual
+ // number of atom pointers in atomTable.
+ // atomTable is allocated withing the function. If it was
+ // not set to NULL before calling the function, the latter will
+ // attempt to deallocate it first.
+ // The application is responsible for deleting atomTable,
+ // however it must not touch atom pointers, i.e. use simply
+ // "delete atomTable;". Never pass atomTable from GetAtomTable(..)
+ // into this function, unless you set it to NULL before doing that.
+ void GetAtomTable1 ( const ChainID chainID, int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable1 ( int chainNo, int seqNo,
+ const InsCode insCode,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable1 ( const ChainID chainID, int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+ void GetAtomTable1 ( int chainNo, int resNo,
+ PPAtom & atomTable, int & NumberOfAtoms );
+
+ void GetAtomStatistics ( RAtomStat AS );
+ void CalAtomStatistics ( RAtomStat AS );
+
+
+ // -------------------- Deleting atoms -------------------------
+
+ int DeleteAtom ( const ChainID chID,
+ int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( const ChainID chID, int seqNo,
+ const InsCode insCode, int atomNo );
+ int DeleteAtom ( const ChainID chID,
+ int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( const ChainID chID, int resNo, int atomNo );
+ int DeleteAtom ( int chNo, int seqNo,
+ const InsCode insCode,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( int chNo, int seqNo, const InsCode insCode,
+ int atomNo );
+ int DeleteAtom ( int chNo, int resNo,
+ const AtomName aname,
+ const Element elmnt,
+ const AltLoc aloc );
+ int DeleteAtom ( int chNo, int resNo, int atomNo );
+
+ int DeleteAllAtoms ( const ChainID chID, int seqNo,
+ const InsCode insCode );
+ int DeleteAllAtoms ( const ChainID chID, int resNo );
+ int DeleteAllAtoms ( const ChainID chID );
+ int DeleteAllAtoms ( int chNo, int seqNo, const InsCode insCode );
+ int DeleteAllAtoms ( int chNo, int resNo );
+ int DeleteAllAtoms ( int chNo );
+ int DeleteAllAtoms ();
+
+ // DeleteAltLocs() leaves only alternative location with maximal
+ // occupancy, if those are equal or unspecified, the one with
+ // "least" alternative location indicator.
+ // The function returns the number of deleted. All tables remain
+ // untrimmed, so that explicit trimming or calling
+ // FinishStructEdit() is required.
+ int DeleteAltLocs();
+
+
+ // --------------------- Adding atoms --------------------------
+
+ int AddAtom ( const ChainID chID, int seqNo,
+ const InsCode insCode, PAtom atom );
+ int AddAtom ( const ChainID chID, int resNo, PAtom atom );
+ int AddAtom ( int chNo, int seqNo, const InsCode insCode,
+ PAtom atom );
+ int AddAtom ( int chNo, int resNo, PAtom atom );
+
+
+ // ---------------------------------------------------------------
+
+ // ConvertPDBString(..) interprets PDB records DBREF, SEQADV,
+ // SEQRES, MODRES.
+ // Returns zero if the line was converted, otherwise returns a
+ // non-negative value of Error_XXXX.
+ // PDBString must be not shorter than 81 characters.
+ ERROR_CODE ConvertPDBString ( pstr PDBString );
+
+ // PDBASCIIDumpPS(..) makes output of PDB primary structure records
+ // excluding cispeps
+ void PDBASCIIDumpPS ( io::RFile f );
+
+ // PDBASCIIDumpCP(..) makes output of cispep records
+ void PDBASCIIDumpCP ( io::RFile f );
+
+ // PDBASCIIDump(..) makes output of PDB coordinate (ATOM etc.)
+ // records
+ void PDBASCIIDump ( io::RFile f );
+
+ void MakeAtomCIF ( mmcif::PData CIF );
+ void MakePSCIF ( mmcif::PData CIF );
+ ERROR_CODE GetCIF ( mmcif::PData CIF );
+
+ // MoveChain(..) adds chain m_chain on the top Chain array.
+ // The pointer on chain is then set to NULL (m_chain=NULL).
+ // If chain_ext is greater than 0, the moved chain will be
+ // forcefully renamed; the new name is composed as the previous
+ // one + underscore + chain_ext (e.g. A_1). If thus generated
+ // name duplicates any of existing chain IDs, or if chain_ext
+ // was set to 0 and there is a duplication of chain IDs, the
+ // name is again modified as above, with the extension number
+ // generated automatically (this may result in IDs like
+ // A_1_10).
+ // m_atom must give pointer to the Atom array, from which
+ // the atoms belonging to m_chain, are moved to Atom array
+ // given by 'atom', starting from poisition 'atom_index'.
+ // 'atom_index' is then automatically updated to the next
+ // free position in 'atom'.
+ // Note1: the moved atoms will occupy a continuous range
+ // in 'atom' array; no checks on whether the corresponding
+ // cells are occupied or not, are performed.
+ // Note2: the 'atom_index' is numbered from 0 on, i.e.
+ // it is equal to atom[atom_index]->index-1; atom[]->index
+ // is assigned automatically.
+ void MoveChain ( PChain & m_chain, PPAtom m_atom,
+ PPAtom atom, int & atom_index,
+ int chain_ext );
+
+ void GetAIndexRange ( int & i1, int & i2 );
+
+ void MaskAtoms ( PMask mask );
+ void MaskResidues ( PMask mask );
+ void MaskChains ( PMask mask );
+ void UnmaskAtoms ( PMask mask );
+ void UnmaskResidues ( PMask mask );
+ void UnmaskChains ( PMask mask );
+
+
+ // ---- Getting Secondary Structure Elements
+
+ int GetNumberOfHelices ();
+ int GetNumberOfSheets ();
+
+ PHelix GetHelix ( int serialNum ); // 1<=serNum<=NofHelices
+
+ void GetSheetID ( int serialNum, SheetID sheetID );
+ // '\0' for none
+
+ PSheet GetSheet ( int serialNum ); //1<=serNum<=NofSheets
+ PSheet GetSheet ( const SheetID sheetID ); // NULL for none
+ int GetNumberOfStrands ( int sheetSerNum );
+ int GetNumberOfStrands ( const SheetID sheetID );
+ PStrand GetStrand ( int sheetSerNum,
+ int strandSerNum );
+ PStrand GetStrand ( const SheetID sheetID,
+ int strandSerNum );
+
+ inline PSSContainer GetHelices() { return &helices; }
+ inline PSheets GetSheets () { return &sheets; }
+
+ void RemoveSecStructure();
+ int CalcSecStructure ( bool flagBulge=true,
+ int aminoSelHnd=-1 );
+ // int CalcSecStructure ( bool flagBulge=true );
+
+ PHetCompounds GetHetInfo() { return &hetCompounds; }
+ void RemoveHetInfo ();
+
+
+ // ---- Working Links
+
+ int GetNumberOfLinks ();
+ PLink GetLink ( int serialNum ); // 1<=serNum<=NofLinks
+ PLinkContainer GetLinks() { return &links; }
+
+ void RemoveLinks();
+ void AddLink ( PLink link );
+
+ // ---- Working Refmac Links
+
+ int GetNumberOfLinkRs ();
+ PLinkR GetLinkR ( int serialNum ); // 1<=serNum<=NofLinks
+ PLinkRContainer GetLinkRs() { return &linkRs; }
+
+ void RemoveLinkRs();
+ void AddLinkR ( PLinkR linkR );
+
+
+ // ---- Working CisPeps
+
+ int GetNumberOfCisPeps();
+ PCisPep GetCisPep ( int CisPepNum );
+ PCisPepContainer GetCisPeps() { return &cisPeps; }
+
+ void RemoveCisPeps();
+ void AddCisPep ( PCisPep cisPep );
+
+
+
+ void ApplyTransform ( mat44 & TMatrix ); // transforms all
+ // coordinates by multiplying
+ // with matrix TMatrix
+
+ bool isInSelection ( int selHnd );
+
+
+ // ------- user-defined data handlers
+ int PutUDData ( int UDDhandle, int iudd );
+ int PutUDData ( int UDDhandle, realtype rudd );
+ int PutUDData ( int UDDhandle, cpstr sudd );
+
+ int GetUDData ( int UDDhandle, int & iudd );
+ int GetUDData ( int UDDhandle, realtype & rudd );
+ int GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+ int GetUDData ( int UDDhandle, pstr & sudd );
+
+
+ void Copy ( PModel model );
+ void CopyHets ( PModel model );
+ void CopySecStructure ( PModel model );
+ void CopyLinks ( PModel model );
+ void CopyLinkRs ( PModel model );
+ void CopyCisPeps ( PModel model );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ int serNum; // the model serial number
+ PManager manager; // pointer to mmdbmanager class
+
+ HetCompounds hetCompounds; // information on heterocompounds
+ SSContainer helices; // information on helices
+ Sheets sheets; // information on sheets
+ SSContainer turns; // information on turns
+ LinkContainer links; // information on links
+ LinkRContainer linkRs; // information on refmac links
+ CisPepContainer cisPeps; // information on cispeps
+
+ int nChains; // number of chains
+ int nChainsAlloc; // actual length of Chain[]
+ PPChain chain; // array of chains
+
+ bool Exclude; // used internally
+
+ void InitModel ();
+ void FreeMemory ();
+ void ExpandChainArray ( int nOfChains );
+ ERROR_CODE GetCIFPSClass ( mmcif::PData CIF, int ClassID );
+
+ // _ExcludeChain(..) excludes (but does not dispose!) a chain
+ // from the model. Returns 1 if the chain gets empty and 0
+ // otherwise.
+ int _ExcludeChain ( const ChainID chainID );
+
+ // _copy(PModel) does not copy atoms! -- not for use in
+ // applications
+ void _copy ( PModel Model );
+
+ // _copy(PModel,PPAtom,int&) does copy atoms into array 'atom'
+ // starting from position atom_index. 'atom' should be able to
+ // accept all new atoms - no checks on the length of 'atom'
+ // is being made. This function should not be used in applications.
+ void _copy ( PModel Model, PPAtom atom, int & atom_index );
+
+ void CheckInAtoms ();
+
+ };
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_root.cpp b/mmdb2/mmdb_root.cpp
new file mode 100644
index 0000000..3a98edb
--- /dev/null
+++ b/mmdb2/mmdb_root.cpp
@@ -0,0 +1,3054 @@
+// $Id: mmdb_root.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 14.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Root <implementation>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Root
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include "string.h"
+#include "stdlib.h"
+
+#include "mmdb_root.h"
+#include "mmdb_atom.h"
+#include "mmdb_mmcif_.h"
+#include "mmdb_cifdefs.h"
+#include "mmdb_tables.h"
+#include "mmdb_defs.h"
+
+
+namespace mmdb {
+
+ // ===================== Root =======================
+
+ Root::Root() : UDData() {
+ InitMMDBRoot();
+ }
+
+ Root::Root ( io::RPStream Object ) : UDData(Object) {
+ InitMMDBRoot();
+ }
+
+ Root::~Root() {
+ FreeFileMemory();
+ }
+
+ void Root::InitMMDBRoot() {
+ nModels = 0;
+ model = NULL;
+ nAtoms = 0;
+ atmLen = 0;
+ atom = NULL;
+ CIF = NULL;
+ crModel = NULL;
+ crChain = NULL;
+ crRes = NULL;
+ lcount = 0;
+ strcpy ( S,"" );
+ // Flags = 0x00000000; // no special effects
+ Flags = MMDBF_IgnoreElement; // done at request for default
+ FType = MMDB_FILE_Undefined; // undefined file operation
+ Exclude = true;
+ ignoreRemarks = false; // used temporarily
+ allowDuplChID = false; // used temporarily
+ enforceUniqueChID = false; // used temporarily
+ modelCnt = 0; // used only at reading files
+ }
+
+
+ void Root::FreeCoordMemory() {
+ //int i;
+
+ /*
+ // All atoms are kept in array Atom. Models, chains
+ // and residues have only references to Atom and
+ // they do not dispose Atoms when disposed themselves.
+ // It is important, however, to dispose Atom at
+ // still alive residues, because each atom wipes out
+ // reference to itself from the corresponding residue
+ // before it dies.
+ if (Atom) {
+ for (i=0;i<atmLen;i++)
+ if (atom[i]) delete atom[i];
+ delete Atom;
+ }
+ Atom = NULL;
+ atmLen = 0;
+ nAtoms = 0;
+ */
+ DeleteAllModels();
+ if (model) delete[] model;
+ model = NULL;
+ nModels = 0;
+
+ crModel = NULL;
+ crChain = NULL;
+ crRes = NULL;
+
+ if (atom) delete[] atom;
+
+ atom = NULL;
+ atmLen = 0;
+ nAtoms = 0;
+
+ modelCnt = 0;
+
+ }
+
+ void Root::FreeFileMemory() {
+
+ FreeCoordMemory ();
+ title.FreeMemory ( false );
+ cryst.FreeMemory ();
+
+ SA .FreeContainer();
+ Footnote.FreeContainer();
+ SB .FreeContainer();
+ SC .FreeContainer();
+
+ if (CIF) delete CIF;
+ CIF = NULL;
+
+ lcount = 0;
+ S[0] = char(0);
+
+ }
+
+ // virtual to be served by MMDB manager classes
+ void Root::ResetManager() {
+ cryst.Reset();
+ }
+
+ void Root::SetFlag ( word Flag ) {
+ Flags |= Flag;
+ ignoreSegID = (Flags & MMDBF_IgnoreSegID ) != 0;
+ ignoreElement = (Flags & MMDBF_IgnoreElement ) != 0;
+ ignoreCharge = (Flags & MMDBF_IgnoreCharge ) != 0;
+ ignoreNonCoorPDBErrors = (Flags & MMDBF_IgnoreNonCoorPDBErrors ) != 0;
+ ignoreUnmatch = (Flags & MMDBF_IgnoreUnmatch ) != 0;
+ allowDuplChID = (Flags & MMDBF_AllowDuplChainID ) != 0;
+ enforceUniqueChID = (Flags & MMDBF_EnforceUniqueChainID ) != 0;
+ cryst.processSG = (Flags & MMDBF_DoNotProcessSpaceGroup ) == 0;
+ cryst.fixSpaceGroup = (Flags & MMDBF_FixSpaceGroup ) != 0;
+ }
+
+ void Root::RemoveFlag ( word Flag ) {
+ Flags &= ~Flag;
+ ignoreSegID = (Flags & MMDBF_IgnoreSegID ) != 0;
+ ignoreElement = (Flags & MMDBF_IgnoreElement ) != 0;
+ ignoreCharge = (Flags & MMDBF_IgnoreCharge ) != 0;
+ ignoreNonCoorPDBErrors = (Flags & MMDBF_IgnoreNonCoorPDBErrors ) != 0;
+ ignoreUnmatch = (Flags & MMDBF_IgnoreUnmatch ) != 0;
+ allowDuplChID = (Flags & MMDBF_AllowDuplChainID ) != 0;
+ enforceUniqueChID = (Flags & MMDBF_EnforceUniqueChainID ) != 0;
+ cryst.processSG = (Flags & MMDBF_DoNotProcessSpaceGroup ) == 0;
+ cryst.fixSpaceGroup = (Flags & MMDBF_FixSpaceGroup ) != 0;
+ }
+
+
+ ERROR_CODE Root::ReadPDBASCII1 ( cpstr PDBLFName, io::GZ_MODE gzipMode ) {
+ pstr FName;
+ FName = getenv ( PDBLFName );
+ if (FName) return ReadPDBASCII ( FName,gzipMode );
+ else return Error_NoLogicalName;
+ }
+
+ void Root::ReadPDBLine ( io::RFile f, pstr L, int maxlen ) {
+ int i;
+ bool Done;
+ do {
+ f.ReadLine ( L,maxlen );
+ Done = true;
+ if (ignoreRemarks) {
+ if (!strncasecmp(L,"REMARK",6)) Done = false;
+ }
+ if (Flags & MMDBF_IgnoreBlankLines) {
+ i = 0;
+ while (L[i] && (L[i]==' ')) i++;
+ if (!L[i]) Done = false;
+ }
+ if ((Flags & MMDBF_IgnoreHash) && (L[0]=='#'))
+ Done = false;
+ } while ((!f.FileEnd()) && (!Done));
+ PadSpaces ( L,80 );
+ }
+
+ ERROR_CODE Root::ReadPDBASCII ( cpstr PDBFileName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ ERROR_CODE RC;
+
+ // open the file as ASCII for reading
+ // opening it in pseudo-binary mode helps reading various
+ // line terminators for files coming from different platforms
+ f.assign ( PDBFileName,false,false,gzipMode );
+
+ if (f.reset(true)) {
+
+ RC = ReadPDBASCII ( f );
+ f.shut();
+
+ } else {
+
+ RC = Error_CantOpenFile;
+ ResetManager ();
+ FreeFileMemory();
+ FType = MMDB_FILE_PDB;
+
+ }
+
+ return RC;
+
+ }
+
+
+ ERROR_CODE Root::ReadPDBASCII ( io::RFile f ) {
+ PContString contString;
+ word cleanKey;
+ int modNum;
+ bool fend;
+ ERROR_CODE RC;
+
+ // remove previous data
+ ResetManager ();
+ FreeFileMemory();
+
+ FType = MMDB_FILE_PDB;
+ SetFlag ( 0 );
+
+ if (f.FileEnd()) return Error_EmptyFile;
+
+ lcount = 1; // line counter
+
+ // read title section
+ RC = Error_NoError;
+ ReadPDBLine ( f,S,sizeof(S) );
+ if (Flags & MMDBF_EnforceSpaces) EnforceSpaces ( S );
+ do {
+ if (!strncmp(S,"FTNOTE",6)) {
+ contString = new ContString(S);
+ Footnote.AddData ( contString );
+ } else {
+ RC = title.ConvertPDBString(S);
+ if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
+ RC = Error_NoError;
+ if (RC) break;
+ }
+ fend = f.FileEnd();
+ if (!fend) {
+ ReadPDBLine ( f,S,sizeof(S) );
+ lcount++;
+ }
+ } while (!fend);
+
+ title.GetResolution(); // only to fetch resolution from remarks
+
+ if (RC!=Error_WrongSection) return RC;
+
+ ignoreRemarks = (Flags & MMDBF_IgnoreRemarks)!=0;
+
+ // read primary structure section
+ SwitchModel ( 1 );
+ if (!crModel) return Error_GeneralError1;
+ do {
+ if (!strncmp(S,"FTNOTE",6)) {
+ contString = new ContString(S);
+ Footnote.AddData ( contString );
+ } else {
+ RC = crModel->ConvertPDBString ( S );
+ if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
+ RC = Error_NoError;
+ if (RC) break;
+ }
+ fend = f.FileEnd();
+ if (!fend) {
+ ReadPDBLine ( f,S,sizeof(S) );
+ title.TrimInput ( S );
+ lcount++;
+ }
+ } while (!fend);
+
+ if (RC!=Error_WrongSection) return RC;
+
+ // temporary solution: the rest of file is stored
+ // in the form of strings
+ while (!f.FileEnd() &&
+ strncmp(S,"CRYST" ,5) &&
+ strncmp(S,"ORIGX" ,5) &&
+ strncmp(S,"SCALE" ,5) &&
+ strncmp(S,"MTRIX" ,5) &&
+ strncmp(S,"TVECT" ,5) &&
+ strncmp(S,"MODEL ",6) &&
+ strncmp(S,"ATOM ",6) &&
+ strncmp(S,"SIGATM",6) &&
+ strncmp(S,"ANISOU",6) &&
+ strncmp(S,"SIGUIJ",6) &&
+ strncmp(S,"TER ",6) &&
+ strncmp(S,"HETATM",6) &&
+ strncmp(S,"ENDMDL",6)) {
+ if (!strncmp(S,"LINK ",6))
+ crModel->ConvertPDBString ( S );
+ else if (!strncmp(S,"LINKR ",6))
+ crModel->ConvertPDBString ( S );
+ else if (!strncmp(S,"CISPEP",6)) {
+ GetInteger ( modNum,&(S[43]),3 );
+ if (modNum<=0) modNum = 1;
+ if (modNum!=1) SwitchModel ( modNum );
+ crModel->ConvertPDBString ( S );
+ if (modNum!=1) SwitchModel ( 1 );
+ } else {
+ contString = new ContString(S);
+ SA.AddData ( contString );
+ }
+ ReadPDBLine ( f,S,sizeof(S) );
+ title.TrimInput ( S );
+ lcount++;
+ }
+
+ // read crystallographic information section
+ do {
+ RC = cryst.ConvertPDBString ( S );
+ if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
+ RC = Error_NoError;
+ if (RC) break;
+ fend = f.FileEnd();
+ if (!fend) {
+ ReadPDBLine ( f,S,sizeof(S) );
+ title.TrimInput ( S );
+ lcount++;
+ }
+ } while (!fend);
+
+ if (!RC) {
+ RC = cryst.ConvertPDBString ( S );
+ if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
+ RC = Error_WrongSection;
+ }
+
+ cryst.CalcCoordTransforms();
+ if (Flags & MMDBF_SimRWBROOK)
+ cryst.RWBROOKReadPrintout();
+
+ if (RC!=Error_WrongSection) return RC;
+
+ // temporary solution: the rest of file is stored
+ // in the form of strings
+ while (!f.FileEnd() &&
+ strncmp(S,"MODEL ",6) &&
+ strncmp(S,"ATOM ",6) &&
+ strncmp(S,"SIGATM",6) &&
+ strncmp(S,"ANISOU",6) &&
+ strncmp(S,"SIGUIJ",6) &&
+ strncmp(S,"TER ",6) &&
+ strncmp(S,"HETATM",6) &&
+ strncmp(S,"ENDMDL",6)) {
+ contString = new ContString(S);
+ SB.AddData ( contString );
+ ReadPDBLine ( f,S,sizeof(S) );
+ title.TrimInput ( S );
+ lcount++;
+ }
+
+ if (Flags & MMDBF_NoCoordRead) return Error_NoError;
+
+ // read coordinate section
+ RC = Error_NoError;
+ do {
+ RC = ReadPDBAtom ( S );
+ if (RC) break;
+ fend = f.FileEnd();
+ if (!fend) {
+ ReadPDBLine ( f,S,sizeof(S) );
+ title.TrimInput ( S );
+ lcount++;
+ }
+ } while (!fend);
+ // if (!RC)
+ // RC = ReadPDBAtom(S);
+ // commented on 28.05.2004, it appears that "CHAIN_ORDER" should not
+ // be enforced here
+ // cleanKey = PDBCLEAN_ATNAME | PDBCLEAN_CHAIN_ORDER;
+ cleanKey = 0x00000000;
+ if (Flags & MMDBF_EnforceAtomNames)
+ cleanKey = PDBCLEAN_ATNAME;
+ if (Flags & MMDBF_AutoSerials)
+ cleanKey |= PDBCLEAN_SERIAL;
+
+ if (cleanKey)
+ PDBCleanup ( cleanKey );
+
+ if ((!f.FileEnd()) && (RC!=Error_WrongSection)) return RC;
+
+ // temporary solution: the rest of file is stored
+ // in the form of strings
+ while (!f.FileEnd()) {
+ if (strncmp(S,"END ",6)) { // END is added automatically
+ contString = new ContString(S);
+ SC.AddData ( contString );
+ }
+ ReadPDBLine ( f,S,sizeof(S) );
+ title.TrimInput ( S );
+ lcount++;
+ }
+ lcount--; // last line was not read
+
+ return Error_NoError;
+
+ }
+
+
+ ERROR_CODE Root::ReadCIFASCII1 ( cpstr CIFLFName, io::GZ_MODE gzipMode ) {
+ pstr FName;
+ FName = getenv ( CIFLFName );
+ if (FName) return ReadCIFASCII ( FName,gzipMode );
+ else return Error_NoLogicalName;
+ }
+
+ ERROR_CODE Root::ReadCIFASCII ( cpstr CIFFileName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ ERROR_CODE rc;
+
+ // open the file as ASCII for reading
+ // opening it in pseudo-binary mode helps reading various
+ // line terminators for files coming from different platforms
+ f.assign ( CIFFileName,false,false,gzipMode );
+
+ if (f.reset(true)) {
+ rc = ReadCIFASCII ( f );
+ f.shut();
+ } else
+ rc = Error_CantOpenFile;
+
+ return rc;
+
+ }
+
+ ERROR_CODE Root::ReadCIFASCII ( io::RFile f ) {
+ int W;
+ ERROR_CODE RC;
+
+ // remove previous data
+ ResetManager ();
+ FreeFileMemory();
+ FType = MMDB_FILE_CIF;
+
+ SetFlag ( 0 );
+
+ CIFErrorLocation[0] = char(0); // CIF reading phase
+
+ lcount = 0; // line counter
+ S[0] = char(0);
+
+ if (f.FileEnd())
+ return Error_EmptyFile;
+
+ if (!CIF) CIF = new mmcif::Data();
+ CIF->SetStopOnWarning ( true );
+ CIF->SetPrintWarnings ( (Flags & MMDBF_PrintCIFWarnings)!=0 );
+ W = CIF->ReadMMCIFData ( f,S,lcount );
+
+ if (W) {
+ if (W == mmcif::CIFRC_NoDataLine) return Error_NotACIFFile;
+ if (W & mmcif::CIFW_UnrecognizedItems) return Error_UnrecognCIFItems;
+ if (W & mmcif::CIFW_MissingField) return Error_MissingCIFField;
+ if (W & mmcif::CIFW_EmptyLoop) return Error_EmptyCIFLoop;
+ if (W & mmcif::CIFW_UnexpectedEOF) return Error_UnexpEndOfCIF;
+ if (W & mmcif::CIFW_LoopFieldMissing) return Error_MissgCIFLoopField;
+ if (W & mmcif::CIFW_NotAStructure) return Error_NotACIFStructure;
+ if (W & mmcif::CIFW_NotALoop) return Error_NotACIFLoop;
+ return Error_Unknown;
+ }
+
+ RC = ReadFromCIF ( CIF );
+ if (CIF) {
+ delete CIF;
+ CIF = NULL;
+ }
+
+ return RC;
+
+ }
+
+
+ ERROR_CODE Root::ReadFromCIF ( mmcif::PData CIFD ) {
+ mmcif::PLoop Loop1,Loop2;
+ pstr F,FC;
+ word cleanKey;
+ int i,l,j,n,retc;
+ ERROR_CODE RC;
+
+ RC = title.GetCIF ( CIFD );
+
+ if (RC!=Error_NoError) {
+ CIFD->Optimize();
+ return RC;
+ }
+
+ SwitchModel ( 1 );
+ if (!crModel) return Error_GeneralError1;
+ RC = crModel->GetCIF ( CIFD );
+ if (RC!=Error_NoError) {
+ CIFD->Optimize();
+ return RC;
+ }
+
+ RC = cryst.GetCIF ( CIFD );
+ if (RC!=Error_NoError) {
+ CIFD->Optimize();
+ return RC;
+ }
+ cryst.CalcCoordTransforms();
+ if (Flags & MMDBF_SimRWBROOK)
+ cryst.RWBROOKReadPrintout();
+
+ RC = ReadCIFAtom ( CIFD );
+
+ Loop1 = CIFD->GetLoop ( CIFCAT_ENTITY );
+ Loop2 = CIFD->GetLoop ( CIFCAT_STRUCT_ASYM );
+ if (Loop1 && Loop2) {
+ // make 'Het' atoms
+ l = Loop1->GetLoopLength();
+ n = Loop2->GetLoopLength();
+ for (i=0;i<l;i++) {
+ F = Loop1->GetString ( CIFTAG_TYPE,i,retc );
+ if (F && (!retc)) {
+ if (!strcasecmp(F,"non-polymer")) {
+ F = Loop1->GetString ( CIFTAG_ID,i,retc );
+ if (F && (!retc))
+ for (j=0;j<n;j++) {
+ FC = Loop2->GetString ( CIFTAG_ENTITY_ID,j,retc );
+ if (FC && (!retc)) {
+ if (!strcasecmp(FC,F)) {
+ FC = Loop2->GetString ( CIFTAG_ID,j,retc );
+ if (FC && (!retc))
+ MakeHetAtoms ( FC,true );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (RC==Error_NoError) {
+ // deleting these CIF loops here is a temporary solution
+ // taken in order to avoid mess at rewriting the CIF file.
+ CIFD->DeleteLoop ( CIFCAT_ATOM_SITE );
+ CIFD->DeleteLoop ( CIFCAT_ATOM_SITE_ANISOTROP );
+ CIFD->Optimize ();
+ }
+
+ cleanKey = 0x00000000;
+ if (Flags & MMDBF_EnforceAtomNames)
+ cleanKey = PDBCLEAN_ATNAME;
+ if (Flags & MMDBF_AutoSerials)
+ cleanKey |= PDBCLEAN_SERIAL;
+ if (cleanKey)
+ PDBCleanup ( cleanKey );
+
+ return RC;
+
+ }
+
+ ERROR_CODE Root::ReadCoorFile1 ( cpstr LFName, io::GZ_MODE gzipMode ) {
+ pstr FName;
+ FName = getenv ( LFName );
+ if (FName) return ReadCoorFile ( FName,gzipMode );
+ else return Error_NoLogicalName;
+ }
+
+ ERROR_CODE Root::ReadCoorFile ( cpstr CFName, io::GZ_MODE gzipMode ) {
+ // auto format recognition
+ int kin;
+ bool IBL;
+
+ kin = isMMDBBIN ( CFName,gzipMode );
+ if (kin==Error_EmptyFile)
+ return Error_EmptyFile;
+ if (kin<0) return Error_CantOpenFile;
+
+ if (kin==0) return ReadMMDBF ( CFName,gzipMode );
+
+ IBL = ((Flags & MMDBF_IgnoreBlankLines)!=0);
+ if (isPDB(CFName,gzipMode,IBL)==0)
+ return ReadPDBASCII ( CFName,gzipMode );
+ if (mmcif::isCIF(CFName,gzipMode)==0)
+ return ReadCIFASCII ( CFName,gzipMode );
+
+ return Error_ForeignFile;
+
+ }
+
+
+ ERROR_CODE Root::ReadCoorFile ( io::RFile f ) {
+ // auto format recognition
+ int kin;
+ bool IBL;
+
+ kin = isMMDBBIN ( f );
+ f.reset ( true );
+ if (kin==Error_EmptyFile)
+ return Error_EmptyFile;
+ if (kin<0) return Error_CantOpenFile;
+
+ if (kin==0) return ReadMMDBF ( f );
+
+ IBL = ((Flags & MMDBF_IgnoreBlankLines)!=0);
+ kin = isPDB ( f,IBL );
+ f.reset ( true );
+ if (kin==0)
+ return ReadPDBASCII ( f );
+
+ kin = mmcif::isCIF ( f );
+ f.reset ( true );
+ if (kin==0)
+ return ReadCIFASCII ( f );
+
+ return Error_ForeignFile;
+
+ }
+
+
+ word Root::PDBCleanup ( word CleanKey ) {
+ // cleans coordinate part to comply with PDB standards:
+ //
+ // CleanKey Action
+ // PDBCLEAN_ATNAME pads atom names with spaces to form 4-symbol names
+ // PDBCLEAN_TER inserts TER cards in the end of each chain
+ // PDBCLEAN_CHAIN generates 1-character chain ids instead of
+ // those many-character
+ // PDBCLEAN_CHAIN_STRONG generates 1-character chain ids starting
+ // from 'A' on for all ids, including single-char
+ // PDBCLEAN_ALTCODE generates 1-character alternative codes instead
+ // of those many-character
+ // PDBCLEAN_ALTCODE_STRONG generates 1-character alternative codes
+ // from 'A' on for all codes, including
+ // single-character ones
+ // PDBCLEAN_SERIAL puts serial numbers in due order
+ // PDBCLEAN_INDEX reorders the internal index of atoms such that
+ // it follows the actual order of atoms in
+ // the object hierarchy
+ // PDBCLEAN_SEQNUM renumbers all residues so that they go
+ // incrementally-by-one without insertion codes
+ // PDBCLEAN_CHAIN_ORDER puts chains in order of atom's serial numbers
+ // PDBCLEAN_SOLVENT moves solvent chains at the end of each model
+ // PDBCLEAN_ELEMENT calculates PDB element names where they are not
+ // found in the chemical element table
+ // PDBCLEAN_ELEMENT_STRONG calculates all chemical element names
+ //
+ // Return codes (as bits):
+ // 0 Ok
+ // PDBCLEAN_CHAIN too many chains for assigning them 1-letter codes
+ // PDBCLEAN_ATNAME element names were not available
+ // PDBCLEAN_ALTCODE too many alternative codes encountered.
+ //
+ word RC;
+ int i,j,k,nal,nch,nr, nch1,nch2;
+ char c;
+ AltLoc * altLoc;
+ ChainID * chain_ID;
+ char aLoc [257];
+ char chnID[257];
+ int modN,modl;
+ PPAtom atom1;
+ PPChain Chain1,Chain2;
+ PModel crModel0;
+ PChain crChain0;
+ PResidue crRes0;
+ PAtom A;
+ pstr chID;
+ ChainID chainID;
+ bool NewChain,Done,Solvent;
+
+ RC = 0;
+ if (nAtoms<=0) return RC;
+
+ if (CleanKey & PDBCLEAN_ATNAME)
+ for (i=0;i<nAtoms;i++)
+ if (atom[i])
+ if (!atom[i]->MakePDBAtomName()) RC |= PDBCLEAN_ATNAME;
+
+ k = -1;
+
+ if (CleanKey & PDBCLEAN_TER) {
+ modN = -1;
+ crModel0 = crModel;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ modl = atom[i]->GetModelNum();
+ chID = atom[i]->GetChainID ();
+ if (modN<0) {
+ modN = modl;
+ SwitchModel ( modN );
+ if (chID) strcpy ( chainID,chID );
+ else chainID[0] = char(0);
+ } else {
+ if (modN!=modl) NewChain = true;
+ else if (chID) NewChain = strcmp(chID,chainID)!=0;
+ else NewChain = chainID[0]!=char(0);
+ if (NewChain) {
+ if (k>=0) {
+ if ((!atom[k]->Ter) && (!atom[k]->Het)) {
+ // insert 'Ter' before atom in position 'i'
+ PutAtom ( -(i+1),atom[k]->serNum+1,pstr("TER"),
+ atom[k]->GetResName(),atom[k]->GetChainID(),
+ atom[k]->GetSeqNum (),atom[k]->GetInsCode(),
+ pstr(" "),pstr(" "),pstr(" ") );
+ atom[i]->MakeTer();
+ }
+ }
+ modN = modl;
+ SwitchModel ( modN );
+ if (chID) strcpy ( chainID,chID );
+ else chainID[0] = char(0);
+ }
+ }
+ k = i;
+ }
+
+ if (k>=0) {
+ if ((!atom[k]->Ter) && (!atom[k]->Het)) { // add last TER
+ i = nAtoms;
+ SwitchModel ( atom[k]->GetModelNum() );
+ PutAtom ( 0,nAtoms+1,pstr("TER"),atom[k]->GetResName(),
+ atom[k]->GetChainID(),atom[k]->GetSeqNum(),
+ atom[k]->GetInsCode(),pstr(" "),pstr(" "),
+ pstr(" ") );
+ atom[i]->MakeTer();
+ }
+ }
+
+ crModel = crModel0;
+ }
+
+
+ if (CleanKey & (PDBCLEAN_CHAIN | PDBCLEAN_CHAIN_STRONG)) {
+ chain_ID = new ChainID[256];
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ for (j=0;j<256;j++) {
+ strcpy ( chain_ID[j]," " );
+ chnID[j] = char(0);
+ }
+ chnID[256] = char(0);
+ nch = 0;
+ for (j=0;j<model[i]->nChains;j++) {
+ crChain0 = model[i]->chain[j];
+ if (crChain0) {
+ if (!crChain0->chainID[0])
+ strcpy ( crChain0->chainID," " );
+ k = 0;
+ while ((k<nch) && (strcmp(chain_ID[k],crChain0->chainID)))
+ k++;
+ if (k>=nch) {
+ if (nch>=255) RC |= PDBCLEAN_CHAIN;
+ else {
+ strcpy ( chain_ID[nch],crChain0->chainID );
+ if (!chain_ID[nch][1])
+ chnID[nch] = chain_ID[nch][0];
+ nch++;
+ }
+ }
+ }
+ }
+ c = 'A';
+ if (CleanKey & PDBCLEAN_CHAIN_STRONG) {
+ // rename all chains through from A to Z
+ for (k=0;k<nch;k++) {
+ chnID[k] = c;
+ c = char(int(c)+1);
+ }
+ } else {
+ // rename only multi-character chain IDs
+ for (j=0;(j<nch) && (k<256);j++) {
+ k = 0;
+ do {
+ while ((k<nch) && (chnID[k]!=c)) k++;
+ if (k<nch) c = char(int(c)+1);
+ } while (k<nch);
+ k = 0;
+ while ((k<256) && (chnID[k])) k++;
+ if (k<256) {
+ chnID[k] = c;
+ c = char(int(c)+1);
+ }
+ }
+ }
+ // assign new chain IDs
+ for (j=0;j<model[i]->nChains;j++) {
+ crChain0 = model[i]->chain[j];
+ if (crChain0) {
+ k = 0;
+ while ((k<nch) && (strcmp(chain_ID[k],crChain0->chainID)))
+ k++;
+ strcpy ( crChain0->prevChainID,crChain0->chainID );
+ crChain0->chainID[0] = chnID[k];
+ crChain0->chainID[1] = char(0);
+ }
+ }
+ }
+ delete[] chain_ID;
+ }
+
+
+ if (CleanKey & (PDBCLEAN_ALTCODE | PDBCLEAN_ALTCODE_STRONG)) {
+ altLoc = new AltLoc[256];
+ for (i=0;i<256;i++) {
+ strcpy ( altLoc[i]," " );
+ aLoc[i] = char(0);
+ }
+ aLoc[0] = ' ';
+ aLoc[256] = char(0);
+ nal = 1;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->altLoc[0]) strcpy ( atom[i]->altLoc," " );
+ else {
+ k = 0;
+ while ((k<nal) && (strcmp(altLoc[k],atom[i]->altLoc))) k++;
+ if (k>=nal) {
+ if (nal>=255) RC |= PDBCLEAN_ALTCODE;
+ else {
+ strcpy ( altLoc[nal],atom[i]->altLoc );
+ if (!altLoc[nal][1]) aLoc[nal] = altLoc[nal][0];
+ nal++;
+ }
+ }
+ }
+ }
+ c = 'A';
+ if (CleanKey & PDBCLEAN_ALTCODE_STRONG)
+ for (i=1;i<nal;i++) {
+ aLoc[i] = c;
+ c = char(int(c)+1);
+ }
+ else
+ for (i=1;(i<nal) && (k<256);i++) {
+ k = 0;
+ do {
+ while ((k<nal) && (aLoc[k]!=c)) k++;
+ if (k<nal) c = char(int(c)+1);
+ } while (k<nal);
+ k = 0;
+ while ((k<256) && (aLoc[k])) k++;
+ if (k<256) {
+ aLoc[k] = c;
+ c = char(int(c)+1);
+ }
+ }
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ k = 0;
+ while ((k<nal) && (strcmp(altLoc[k],atom[i]->altLoc))) k++;
+ atom[i]->altLoc[0] = aLoc[k];
+ atom[i]->altLoc[1] = char(0);
+ }
+ delete[] altLoc;
+ }
+
+
+ if (CleanKey & PDBCLEAN_SEQNUM)
+ for (i=0;i<nModels;i++) {
+ crModel0 = model[i];
+ if (crModel0)
+ for (j=0;j<crModel0->nChains;j++) {
+ crChain0 = crModel0->chain[j];
+ if (crChain0) {
+ nr = 0;
+ for (k=0;k<crChain0->nResidues;k++) {
+ crRes0 = crChain0->residue[k];
+ if (crRes0) {
+ nr++;
+ crRes0->seqNum = nr;
+ crRes0->insCode[0] = char(0);
+ }
+ }
+ }
+ }
+ }
+
+ if (CleanKey & PDBCLEAN_SOLVENT) {
+ atom1 = new PAtom[nAtoms];
+ k = 1;
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ if (model[i]->nChains>k) k = model[i]->nChains;
+ }
+ Chain1 = new PChain[k];
+ Chain2 = new PChain[k];
+ k = 0;
+ for (i=0;i<nModels;i++) {
+ crModel0 = model[i];
+ if (crModel0) {
+ nch1 = 0;
+ nch2 = 0;
+ for (nch=0;nch<crModel0->nChains;nch++) {
+ crChain0 = crModel0->chain[nch];
+ if (crChain0) {
+ Solvent = false;
+ for (nr=0;(nr<crChain0->nResidues) && (!Solvent);nr++) {
+ crRes0 = crChain0->residue[nr];
+ if (crRes0)
+ for (j=0;(j<nSolventNames) && (!Solvent);j++)
+ Solvent = !strcmp ( StdSolventName[j],crRes0->name );
+ }
+ if (Solvent) Chain2[nch2++] = crChain0;
+ else Chain1[nch1++] = crChain0;
+ }
+ }
+ for (nch=0;nch<nch1;nch++) {
+ crChain0 = Chain1[nch];
+ for (nr=0;nr<crChain0->nResidues;nr++) {
+ crRes0 = crChain0->residue[nr];
+ if (crRes0)
+ for (j=0;j<crRes0->nAtoms;j++)
+ if (crRes0->atom[j]) {
+ atom1[k] = crRes0->atom[j];
+ atom1[k]->index = k+1;
+ k++;
+ }
+ }
+ crModel0->chain[nch] = Chain1[nch];
+ }
+ for (nch=0;nch<nch2;nch++) {
+ crChain0 = Chain2[nch];
+ for (nr=0;nr<crChain0->nResidues;nr++) {
+ crRes0 = crChain0->residue[nr];
+ if (crRes0)
+ for (j=0;j<crRes0->nAtoms;j++)
+ if (crRes0->atom[j]) {
+ atom1[k] = crRes0->atom[j];
+ atom1[k]->index = k+1;
+ k++;
+ }
+ }
+ crModel0->chain[nch1++] = Chain2[nch];
+ }
+ crModel0->nChains = nch1;
+ }
+ }
+ delete[] Chain1;
+ delete[] Chain2;
+ if (atom) delete[] atom;
+ atom = atom1;
+ atmLen = nAtoms;
+ nAtoms = k;
+ }
+
+ if (CleanKey & (PDBCLEAN_CHAIN_ORDER | PDBCLEAN_CHAIN_ORDER_IX)) {
+ for (i=0;i<nModels;i++) {
+ crModel0 = model[i];
+ if (crModel0) {
+ k = 0;
+ for (j=0;j<crModel0->nChains;j++) {
+ crChain0 = crModel0->chain[j];
+ if (crChain0) {
+ crChain0->nWeights = 0;
+ crChain0->Weight = 0.0;
+ if (k<j) {
+ crModel0->chain[k] = crModel0->chain[j];
+ crModel0->chain[j] = NULL;
+ }
+ k++;
+ }
+ }
+ crModel0->nChains = k;
+ }
+ }
+ if (CleanKey & PDBCLEAN_CHAIN_ORDER)
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ crChain0 = atom[i]->GetChain();
+ crChain0->nWeights++;
+ crChain0->Weight += atom[i]->serNum;
+ }
+ else
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ crChain0 = atom[i]->GetChain();
+ crChain0->nWeights++;
+ crChain0->Weight += atom[i]->GetIndex();
+ }
+ for (i=0;i<nModels;i++) {
+ crModel0 = model[i];
+ if (crModel0) {
+ for (j=0;j<crModel0->nChains;j++) {
+ crChain0 = crModel0->chain[j];
+ if (crChain0->nWeights)
+ crChain0->Weight /= crChain0->nWeights;
+ }
+ // bubble sorting
+ do {
+ Done = true;
+ for (j=1;j<crModel0->nChains;j++)
+ if (crModel0->chain[j-1]->Weight >
+ crModel0->chain[j]->Weight) {
+ crChain0 = crModel0->chain[j-1];
+ crModel0->chain[j-1] = crModel0->chain[j];
+ crModel0->chain[j] = crChain0;
+ Done = false;
+ }
+ } while (!Done);
+ }
+ }
+ }
+
+ if (CleanKey & PDBCLEAN_INDEX) {
+ k = 0;
+ for (i=0;i<nModels;i++) {
+ crModel0 = model[i];
+ if (crModel0) {
+ for (nch=0;nch<crModel0->nChains;nch++) {
+ crChain0 = crModel0->chain[nch];
+ if (crChain0) {
+ for (nr=0;nr<crChain0->nResidues;nr++) {
+ crRes0 = crChain0->residue[nr];
+ if (crRes0) {
+ for (j=0;j<crRes0->nAtoms;j++) {
+ A = crRes0->atom[j];
+ if (A) {
+ atom[A->index-1] = atom[k];
+ if (atom[k])
+ atom[k]->index = A->index;
+ atom[k] = A;
+ k++;
+ A->index = k;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ nAtoms = k;
+ }
+
+ if (CleanKey & PDBCLEAN_SERIAL) {
+ k = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (k<i) {
+ atom[k] = atom[i];
+ atom[i] = NULL;
+ }
+ atom[k]->index = k+1;
+ atom[k]->serNum = atom[k]->index;
+ k++;
+ }
+ nAtoms = k;
+ }
+
+ if (CleanKey & PDBCLEAN_ELEMENT) {
+ for (i=0;i<nAtoms;i++)
+ if (atom[i] && (!atom[i]->Ter)) {
+ if (getElementNo(atom[i]->element)==ELEMENT_UNKNOWN) {
+ strcpy ( atom[i]->element," " );
+ atom[i]->MakePDBAtomName();
+ }
+ }
+ }
+
+ if (CleanKey & PDBCLEAN_ELEMENT_STRONG) {
+ for (i=0;i<nAtoms;i++)
+ if (atom[i] && (!atom[i]->Ter)) {
+ strcpy ( atom[i]->element," " );
+ atom[i]->MakePDBAtomName();
+ }
+ }
+
+ return RC;
+
+ }
+
+ void Root::MakeHetAtoms ( cpstr chainID, bool Make ) {
+ // Makes all atoms in chain 'chainID', in all models, as 'Het' atoms
+ // if Make is set true, and makes them 'ordinary' atoms otherwise.
+ // 'Ter' is automatically removed when converting to 'Het' atoms,
+ // and is automatically added when converting to 'ordinary' atoms.
+ int i,j,k,l,n;
+ PModel crModel0;
+ PChain crChain0;
+ PResidue crRes0;
+ crModel0 = crModel;
+ for (i=0;i<nModels;i++)
+ if (model[i])
+ for (j=0;j<model[i]->nChains;j++) {
+ crChain0 = model[i]->chain[j];
+ if (crChain0) {
+ if (!strcmp(crChain0->chainID,chainID)) {
+ n = 0;
+ for (k=0;k<crChain0->nResidues;k++) {
+ crRes0 = crChain0->residue[k];
+ if (crRes0)
+ for (l=0;l<crRes0->nAtoms;l++)
+ if (crRes0->atom[l]) {
+ crRes0->atom[l]->Het = Make;
+ n = crRes0->atom[l]->index;
+ }
+ }
+ if (n>0) {
+ n--;
+ if (atom[n]->Het && atom[n]->Ter) RemoveAtom ( n+1 );
+ else if ((!atom[n]->Het) && (!atom[n]->Ter)) {
+ SwitchModel ( model[i]->GetSerNum() );
+ if (n<nAtoms-1)
+ PutAtom ( -(n+2),atom[n]->serNum+1,pstr("TER"),
+ atom[n]->GetResName(),atom[n]->GetChainID(),
+ atom[n]->GetSeqNum (),atom[n]->GetInsCode(),
+ pstr(" "),pstr(" "),pstr(" ") );
+ else
+ PutAtom ( 0,nAtoms+1,pstr("TER"),
+ atom[n]->GetResName(),atom[n]->GetChainID(),
+ atom[n]->GetSeqNum (),atom[n]->GetInsCode(),
+ pstr(" "),pstr(" "),pstr(" ") );
+ atom[n+1]->MakeTer();
+ }
+ }
+ }
+ }
+ }
+ crModel = crModel0;
+ }
+
+
+ void Root::RemoveAtom ( int index ) {
+ // Removes atom at the specified index in the Atom array.
+ // This index is always accessible as atom[index]->index.
+ // If this leaves a residue empty, the residue is removed.
+ // If this leaves an empty chain, the chain is removed as well;
+ // the same happens to the model.
+ PResidue crRes0;
+ PChain crChain0;
+ PModel crModel0;
+ int i,j;
+
+ if ((index>0) && (index<=nAtoms)) {
+ if (atom[index-1]) {
+ crRes0 = atom[index-1]->residue;
+ if (crRes0) {
+ if (crRes0->_ExcludeAtom(index)) {
+ // the residue appears empty after the exclusion
+ if (crRes) {
+ if ((crRes->seqNum==crRes0->seqNum) &&
+ (!strcmp(crRes->insCode,crRes0->insCode)))
+ crRes = NULL;
+ }
+ crChain0 = crRes0->chain;
+ if (crChain0) {
+ if (crChain0->_ExcludeResidue(crRes0->name,crRes0->seqNum,
+ crRes0->insCode)) {
+ // the chain appears empty after the exclusion
+ if (crChain) {
+ if (!strcmp(crChain->chainID,crChain0->chainID))
+ crChain = NULL;
+ }
+ crModel0 = PModel(crChain0->model);
+ if (crModel0) {
+ if (crModel0->_ExcludeChain(crChain0->chainID)) {
+ // the model appears ampty after the exclusion
+ if (crModel) {
+ if (crModel->serNum==crModel0->serNum)
+ crModel = NULL;
+ }
+ i = crModel0->serNum-1;
+ delete model[i];
+ model[i] = NULL;
+ }
+ }
+ delete crChain0; // it is already excluded from the hierarchy!
+ }
+ }
+ delete crRes0; // it is already excluded from the hierarchy!
+ }
+ }
+ delete atom[index-1]; // it is already excluded from the hierarchy!
+ atom[index-1] = NULL;
+ // now rearrange and re-index atoms.
+ j = 0;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (j<i) {
+ atom[j] = atom[i];
+ atom[i] = NULL;
+ }
+ atom[j]->index = j+1;
+ j++;
+ }
+ nAtoms = j;
+ }
+ }
+ }
+
+
+ int Root::_ExcludeModel ( int serNum ) {
+ // _ExcludeModel(..) excludes (but does not dispose!) a model
+ // from the file. Returns 1 if the file gets empty and 0 otherwise.
+ int i,k;
+
+ if (!Exclude) return 0;
+
+ if ((0<serNum) && (serNum<=nModels))
+ model[serNum-1] = NULL;
+
+ k = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ if (k<i) {
+ model[k] = model[i];
+ model[i] = NULL;
+ }
+ model[k]->serNum = k+1;
+ k++;
+ }
+
+ nModels = k;
+
+ if (nModels<=0) return 1;
+ else return 0;
+
+ }
+
+
+ int Root::FinishStructEdit() {
+ // Makes a new atom index after insertion or deletion of atoms.
+ // This function may change atoms' positions in the index and
+ // correspondingly the Atom::index field.
+ PResidue res;
+ PChain chain;
+ PModel Model1;
+ PPAtom Atom1;
+ int i,j,k,l,n,index,nAtoms1;
+
+ // calculate new number of atoms
+ nAtoms1 = 0;
+ for (i=0;i<nModels;i++) {
+ Model1 = model[i];
+ if (Model1) {
+ for (j=0;j<Model1->nChains;j++) {
+ chain = Model1->chain[j];
+ if (chain) {
+ for (k=0;k<chain->nResidues;k++) {
+ res = chain->residue[k];
+ if (res) {
+ res->TrimAtomTable();
+ nAtoms1 += res->nAtoms;
+ }
+ }
+ chain->TrimResidueTable();
+ }
+ }
+ Model1->TrimChainTable();
+ }
+ }
+ TrimModelTable();
+
+ // compile a new index and null the old one
+
+ if (nAtoms1>0) Atom1 = new PAtom[nAtoms1];
+ else Atom1 = NULL;
+
+ n = 0;
+ for (i=0;i<nModels;i++) {
+ Model1 = model[i];
+ for (j=0;j<Model1->nChains;j++) {
+ chain = Model1->chain[j];
+ for (k=0;k<chain->nResidues;k++) {
+ res = chain->residue[k];
+ for (l=0;l<res->nAtoms;l++) {
+ Atom1[n] = res->atom[l];
+ index = Atom1[n]->index;
+ if ((index>0) && (index<=atmLen))
+ atom[index-1] = NULL;
+ Atom1[n]->index = n+1;
+ n++;
+ }
+ }
+ }
+ }
+
+ // if (n!=nAtoms1) {
+ // printf ( " **** PROGRAM ERROR IN Root::FinishStructEdit\n" );
+ // exit ( 1 );
+ // }
+
+
+ // check if there are dead atoms in the old index
+ for (i=0;i<atmLen;i++)
+ if (atom[i]) delete atom[i];
+
+ // dispose old index and replace it with the new one
+ if (atom) delete[] atom;
+
+ atom = Atom1;
+ atmLen = n;
+ nAtoms = n;
+
+ if (n==nAtoms1) return 0; // Ok
+ else return 1; // not Ok; should never happen
+
+ }
+
+ void Root::TrimModelTable() {
+ int i,j;
+ j = 0;
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ if (j<i) {
+ model[j] = model[i];
+ model[i] = NULL;
+ }
+ model[j]->serNum = j+1;
+ j++;
+ }
+ nModels = j;
+ }
+
+
+ int Root::GenerateNCSMates() {
+ //
+ // Generates NCS mates according to NCS matrices given
+ // in cryst. This will result in generating many-character
+ // chain names, composed as 'x_n' where 'x' is the original
+ // name and 'n' is a unique number, which will coincide with
+ // the symmetry operation (order) number. Another side
+ // effect will be a disorder in atoms' serial numbers.
+ // The hierarchy should therefore be cleaned after
+ // generating the NCS mates. An appropriate way to do that
+ // is to issue the following call:
+ //
+ // PDBCleanup ( PDBCLEAN_TER | PDBCLEAN_ALTCODE_STRONG |
+ // PDBCLEAN_CHAIN_STRONG | PDBCLEAN_SERIAL );
+ //
+ PPChain chainTable,chain;
+ PChain chn;
+ mat44 ncs_m;
+ ChainID chainID;
+ int i,j,k,nNCSOps,nChains,iGiven;
+
+ nNCSOps = cryst.GetNumberOfNCSMatrices();
+ if (nNCSOps<=0) return 1;
+
+ for (i=0;i<nModels;i++)
+ if (model[i]) {
+ model[i]->GetChainTable ( chainTable,nChains );
+ if (nChains>0) {
+ chain = new PChain[nChains];
+ for (j=0;j<nChains;j++)
+ chain[j] = chainTable[j];
+ for (j=0;j<nChains;j++)
+ if (chain[j]) {
+ for (k=0;k<nNCSOps;k++)
+ if (cryst.GetNCSMatrix(k,ncs_m,iGiven)) {
+ if (!iGiven) {
+ chn = newChain();
+ chn->Copy ( chain[j] );
+ sprintf ( chainID,"%s_%i",
+ chain[j]->GetChainID(),k+1 );
+ chn->SetChainID ( chainID );
+ chn->ApplyTransform ( ncs_m );
+ model[i]->AddChain ( chn );
+ }
+ }
+ }
+ delete[] chain;
+ }
+ }
+
+ return 0;
+
+ }
+
+
+ void Root::ApplyNCSTransform ( int NCSMatrixNo ) {
+ mat33 t;
+ vect3 v;
+ int i;
+ if (!cryst.GetNCSMatrix(NCSMatrixNo,t,v)) return;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) atom[i]->Transform ( t,v );
+ }
+
+
+ ERROR_CODE Root::PutPDBString ( cpstr PDBString ) {
+ PContString contString;
+ ERROR_CODE RC;
+
+ strcpy ( S,PDBString ); // maintain the buffer!
+ PadSpaces ( S,80 );
+ lcount++;
+
+ // belongs to title?
+ RC = title.ConvertPDBString ( S );
+ if (RC!=Error_WrongSection) return RC;
+
+ // belongs to primary structure section?
+ SwitchModel ( 1 );
+ RC = crModel->ConvertPDBString ( S );
+ if (RC!=Error_WrongSection) return RC;
+
+ // belongs to the crystallographic information section?
+ RC = cryst.ConvertPDBString ( S );
+ if (RC!=Error_WrongSection) {
+ // if (RC==0) cryst.CalcCoordTransforms();
+ return RC;
+ }
+
+ // belongs to the coordinate section?
+ RC = ReadPDBAtom ( S );
+ if (RC!=Error_WrongSection) return RC;
+
+ // temporary solution: the rest of file is stored
+ // in the form of strings
+ if ((S[0]) && (S[0]!=' ') && (strncmp(S,"END ",6))) {
+ // END is added automatically
+ contString = new ContString(S);
+ SC.AddData ( contString );
+ }
+
+ return Error_NoError;
+
+ }
+
+
+ ERROR_CODE Root::AddPDBASCII1 ( cpstr PDBLFName, io::GZ_MODE gzipMode ) {
+ pstr FName;
+ FName = getenv ( PDBLFName );
+ if (FName) return AddPDBASCII ( FName,gzipMode );
+ else return Error_NoLogicalName;
+ }
+
+ ERROR_CODE Root::AddPDBASCII ( cpstr PDBFileName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ ERROR_CODE RC;
+ // open the file as ASCII for reading
+ // opening it in pseudo-binary mode helps reading various
+ // line terminators for files coming from different platforms
+ f.assign ( PDBFileName,false,false,gzipMode );
+ if (f.reset(true)) {
+ lcount = 1; // line counter
+ RC = Error_NoError;
+ while ((!f.FileEnd()) && (!RC)) {
+ ReadPDBLine ( f,S,sizeof(S) );
+ RC = PutPDBString ( S );
+ }
+ f.shut();
+ } else
+ RC = Error_CantOpenFile;
+ return RC;
+ }
+
+
+ void Root::GetInputBuffer ( pstr Line, int & count ) {
+ if (FType==MMDB_FILE_PDB) { // PDB File
+ strcpy ( Line,S );
+ count = lcount;
+ } else if (FType==MMDB_FILE_CIF) {
+ if (!CIFErrorLocation[0]) { // CIF reading phase
+ strcpy ( Line,S );
+ count = lcount;
+ } else {
+ strcpy ( Line,CIFErrorLocation );
+ count = -1; // CIF interpretation phase
+ }
+ } else {
+ Line[0] = char(0);
+ count = -2;
+ }
+ }
+
+
+ int Root::CrystReady() {
+ // Returns flags:
+ // CRRDY_Complete if crystallographic information is complete
+ // CRRDY_NotPrecise if cryst. inf-n is not precise
+ // CRRDY_isTranslation if cryst. inf-n contains translation
+ // CRRDY_NoOrthCode no orthogonalization code
+ // Fatal:
+ // CRRDY_NoTransfMatrices if transform. matrices were not calculated
+ // CRRDY_Unchecked if cryst. inf-n was not checked
+ // CRRDY_Ambiguous if cryst. inf-n is ambiguous
+ // CRRDY_NoCell if cryst. inf-n is unusable
+ // CRRDY_NoSpaceGroup if space group is not set
+ int k;
+
+ if (!(cryst.WhatIsSet & CSET_Transforms))
+ return CRRDY_NoTransfMatrices;
+
+ if ((cryst.WhatIsSet & CSET_CellParams)!=CSET_CellParams)
+ return CRRDY_NoCell;
+
+ if (!(cryst.WhatIsSet & CSET_SpaceGroup))
+ return CRRDY_NoSpaceGroup;
+
+ if (cryst.CellCheck & CCHK_Unchecked)
+ return CRRDY_Unchecked;
+
+ if (cryst.CellCheck & CCHK_Disagreement)
+ return CRRDY_Ambiguous;
+
+ k = 0x0000;
+ if (cryst.CellCheck & CCHK_Error) k |= CRRDY_NotPrecise;
+ if (cryst.CellCheck & CCHK_Translations) k |= CRRDY_isTranslation;
+ if (cryst.CellCheck & CCHK_NoOrthCode) k |= CRRDY_NoOrthCode;
+
+ return k;
+
+ }
+
+
+ bool Root::isCrystInfo() {
+ return (((cryst.WhatIsSet & CSET_CellParams)==CSET_CellParams) &&
+ (cryst.WhatIsSet & CSET_SpaceGroup));
+ }
+
+ bool Root::isCellInfo() {
+ return ((cryst.WhatIsSet & CSET_CellParams)==CSET_CellParams);
+ }
+
+ bool Root::isSpaceGroup() {
+ return (cryst.WhatIsSet & CSET_SpaceGroup);
+ }
+
+ bool Root::isTransfMatrix() {
+ return cryst.areMatrices();
+ }
+
+ bool Root::isScaleMatrix() {
+ return ((cryst.WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix);
+ }
+
+ bool Root::isNCSMatrix() {
+ return cryst.isNCSMatrix();
+ }
+
+ int Root::AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v,
+ int iGiven ) {
+ return cryst.AddNCSMatrix ( ncs_m,ncs_v,iGiven );
+ }
+
+ int Root::GetNumberOfNCSMatrices() {
+ return cryst.GetNumberOfNCSMatrices();
+ }
+
+ int Root::GetNumberOfNCSMates() {
+ // Returns the number of NCS mates not given in the file (iGiven==0)
+ return cryst.GetNumberOfNCSMates();
+ }
+
+ bool Root::GetNCSMatrix ( int NCSMatrixNo, // 0..N-1
+ mat44 & ncs_m, int & iGiven ) {
+ return cryst.GetNCSMatrix ( NCSMatrixNo,ncs_m,iGiven );
+ }
+
+ ERROR_CODE Root::ReadPDBAtom ( cpstr L ) {
+ // If string L belongs to the coordinate section
+ // (records ATOM, SIGATM, ANISOU, SIGUIJ, TER, HETATM),
+ // the correspondent information is retrieved and
+ // stored in the dynamic Atom array. In parallel, the
+ // structures of Model/Chain/Residue are generated and
+ // referenced to the corresponding Atom.
+ // If processing of L was successful, the return is 0,
+ // otherwise it returns the corresponding Error_XXX
+ // code.
+ // If L does not belong to the coordinate section,
+ // Error_WrongSection is returned.
+ int index,i;
+ ERROR_CODE RC;
+
+ if (!strncmp(L,"ATOM ",6)) {
+
+ index = nAtoms+1; // index for the next atom in Atom array
+ RC = CheckAtomPlace ( index,L );
+ if (!RC) RC = atom[index-1]->ConvertPDBATOM ( index,L );
+
+ } else if (!strncmp(L,"SIGATM",6)) {
+
+ index = nAtoms; // keep index!
+ RC = CheckAtomPlace ( index,L );
+ if (!RC) RC = atom[index-1]->ConvertPDBSIGATM ( index,L );
+
+ } else if (!strncmp(L,"ANISOU",6)) {
+
+ index = nAtoms; // keep index
+ RC = CheckAtomPlace ( index,L );
+ if (!RC) RC = atom[index-1]->ConvertPDBANISOU ( index,L );
+
+ } else if (!strncmp(L,"SIGUIJ",6)) {
+
+ index = nAtoms; // keep index
+ RC = CheckAtomPlace ( index,L );
+ if (!RC) RC = atom[index-1]->ConvertPDBSIGUIJ ( index,L );
+
+ } else if (!strncmp(L,"TER ",6)) {
+
+ index = nAtoms+1; // new place in Atom array
+ RC = CheckAtomPlace ( index,L );
+ if (!RC) RC = atom[index-1]->ConvertPDBTER ( index,L );
+
+ } else if (!strncmp(L,"HETATM",6)) {
+
+ index = nAtoms+1; // new place in Atom array
+ RC = CheckAtomPlace ( index,L );
+ if (!RC) RC = atom[index-1]->ConvertPDBHETATM ( index,L );
+
+ } else if (!strncmp(L,"MODEL ",6)) {
+
+ modelCnt++;
+ RC = SwitchModel ( L );
+ for (i=0;(i<nModels) && (!RC);i++)
+ if (model[i] && (model[i]!=crModel)) {
+ if (crModel->serNum==model[i]->serNum)
+ RC = Error_DuplicatedModel;
+ }
+ // if (!RC) {
+ // if (crModel->serNum!=modelCnt)
+ // RC = Error_DuplicatedModel;
+ // }
+
+ } else if (!strncmp(L,"ENDMDL",6)) {
+
+ crModel = NULL;
+ crChain = NULL;
+ crRes = NULL;
+
+ RC = Error_NoError;
+
+ } else
+ return Error_WrongSection;
+
+ return RC;
+
+ }
+
+
+ ERROR_CODE Root::ReadCIFAtom ( mmcif::PData CIFD ) {
+ mmcif::PLoop Loop,LoopAnis;
+ int i,index,nATS;
+ ERROR_CODE RC;
+
+ Loop = CIFD->GetLoop ( CIFCAT_ATOM_SITE );
+ if (!Loop) return Error_NoError; // no atom coordinates in the file
+
+ LoopAnis = CIFD->GetLoop ( CIFCAT_ATOM_SITE_ANISOTROP );
+ nATS = Loop->GetLoopLength();
+
+ for (i=1;i<=nATS;i++) {
+ // nAtoms and i should always coincide at this point. This piece
+ // of code was however left in order to reach identity with
+ // ReadPDBAtom(..).
+ index = nAtoms+1; // index for the next atom in Atom array
+ RC = CheckAtomPlace ( index,Loop );
+ if (!RC) RC = atom[index-1]->GetCIF ( i,Loop,LoopAnis );
+ if (RC && (RC!=Error_CIF_EmptyRow)) return RC;
+ }
+ if (Flags & MMDBF_AutoSerials)
+ PDBCleanup ( PDBCLEAN_SERIAL );
+
+ return Error_NoError;
+
+ }
+
+ int Root::PutAtom ( int index,
+ int serNum,
+ const AtomName atomName,
+ const ResName resName,
+ const ChainID chainID,
+ int seqNum,
+ const InsCode insCode,
+ const AltLoc altLoc,
+ const SegID segID,
+ const Element element ) {
+
+ // An atom with the specified properties is put into the
+ // structure. The current model is used; if no model is
+ // set (crModel==NULL), one is created. Coordinates and
+ // other parameters of the atom need to be set separately.
+ //
+ // If index is positive and there is already an atom at
+ // this position in the system, the new atom will REPLACE
+ // it. The corresponding residues are automatically
+ // updated.
+ //
+ // If index is null (=0), the new atom will be put on
+ // the top of the structure, i.e. it will be put into
+ // (index=nAtoms+1)-th position.
+ //
+ // If index is negative, then the new atom is INSERTED
+ // BEFORE the atom in the (-index)th position. For
+ // saving the computational efforts, this WILL NOT cause
+ // the recalculation of all atoms' serial numbers
+ // according to their actual positions. It will be needed
+ // however to put the things in order by calling
+ // Root::OrderAtoms() at a certain point, especially
+ // before writing an output ASCII file. NOTE that this
+ // ordering is never done automatically.
+ //
+ // Limitation: if PutAtom implies creating new
+ // chains/residues, these are always created on the top
+ // of existing chains/residues.
+
+
+ int i,kndex,RC;
+
+ kndex = index;
+
+ if (kndex<0) { // the new atom is to be inserted
+
+ kndex = -kndex;
+ if (kndex>atmLen)
+ ExpandAtomArray ( kndex+1000-atmLen );
+
+ if (atom[kndex-1]!=NULL) { // the position is occupied
+
+ // expand the array if necessary
+ if (nAtoms>=atmLen)
+ ExpandAtomArray ( IMax(kndex,nAtoms)+1000-atmLen );
+
+ // now shift all atoms from (kndex-1)th to the end of array.
+ // note that this does not affect residues as they keep only
+ // pointers on atoms
+ for (i=nAtoms;i>=kndex;i--) {
+ atom[i] = atom[i-1];
+ atom[i]->index = i+1; // this is Ok because residues keep
+ // POINTERS rather than indices!
+ }
+ atom[kndex-1] = NULL;
+ nAtoms++;
+
+ }
+
+ }
+
+ if (kndex==0) kndex = nAtoms+1;
+
+ if (!crModel) SwitchModel ( 1 );
+
+
+ RC = AllocateAtom ( kndex,chainID,chainID,resName,resName,
+ seqNum,seqNum,1,insCode,true );
+ if (!RC)
+ atom[kndex-1]->SetAtomName ( kndex,serNum,atomName,altLoc,
+ segID,element );
+ return RC;
+
+ }
+
+
+ int Root::PutAtom ( int index, // same meaning as above
+ PAtom A, // pointer to completed atom
+ // class
+ int serNum // 0 means that the serial
+ // number will be set equal
+ // to "index". Otherwise,
+ // the serial number is set
+ // to the specified value
+ ) {
+ int i,kndex,RC,sn;
+
+ if (!A) return -1;
+
+ kndex = index;
+
+ if (kndex<0) { // the new atom is to be inserted
+
+ kndex = -kndex;
+
+ if (kndex>atmLen)
+ ExpandAtomArray ( kndex+1000-atmLen );
+
+ if (atom[kndex-1]!=NULL) { // the position is occupied
+
+ // expand the array if necessary
+ if (nAtoms>=atmLen)
+ ExpandAtomArray ( IMax(kndex,nAtoms)+1000-atmLen );
+ // now shift all atoms from (kndex-1)th to the end of array.
+ // note that this does not affect residues as they keep only
+ // pointers on atoms
+
+ for (i=nAtoms;i>=kndex;i--) {
+ atom[i] = atom[i-1];
+ atom[i]->index = i+1; // this is Ok because residues keep
+ // POINTERS rather than indices!
+ }
+
+ atom[kndex-1] = NULL;
+ nAtoms++;
+
+ }
+
+ }
+
+ if (kndex==0) kndex = nAtoms+1;
+
+
+ RC = AllocateAtom ( kndex,A->GetChainID(),A->GetLabelAsymID(),
+ A->GetResName(),A->GetLabelCompID(),
+ A->GetSeqNum (),A->GetLabelSeqID (),
+ A->GetLabelEntityID(),A->GetInsCode(),
+ true );
+
+ if (serNum<=0) sn = kndex;
+ else sn = serNum;
+ if (!RC) {
+ atom[kndex-1]->Copy ( A );
+ atom[kndex-1]->serNum = sn;
+ }
+
+ return RC;
+
+ }
+
+ int Root::CheckInAtom ( int index, // same meaning as above
+ PAtom A // pointer to completed
+ // atom class
+ ) {
+ int i,kndex;
+
+ if (!A) return -1;
+
+ kndex = index;
+
+ if (kndex<0) { // the new atom is to be inserted
+
+ kndex = -kndex;
+
+ if (kndex>atmLen)
+ ExpandAtomArray ( kndex+1000-atmLen );
+
+ if (atom[kndex-1]!=NULL) { // the position is occupied
+
+ // expand the array if necessary
+ if (nAtoms>=atmLen)
+ ExpandAtomArray ( IMax(kndex,nAtoms)+1000-atmLen );
+ // now shift all atoms from (kndex-1)th to the end of array.
+ // note that this does not affect residues as they keep only
+ // pointers on atoms
+
+ for (i=nAtoms;i>=kndex;i--) {
+ atom[i] = atom[i-1];
+ if (atom[i])
+ atom[i]->index = i+1; // this is Ok because residues keep
+ // POINTERS rather than indices!
+ }
+
+ }
+
+ nAtoms++;
+
+ } else {
+ if (kndex==0) kndex = nAtoms + 1; // add atom on the very top
+ if (kndex>atmLen) ExpandAtomArray ( kndex+1000-atmLen );
+ if (kndex>nAtoms) nAtoms = kndex;
+ if (atom[kndex-1]) delete atom[kndex-1];
+ }
+
+ atom[kndex-1] = A;
+ A->index = kndex;
+
+ return 0;
+
+ }
+
+ int Root::CheckInAtoms ( int index, // same meaning as above
+ PPAtom A, // array of atoms to check in
+ int natms // number of atoms to check in
+ ) {
+ PPAtom A1;
+ int i,j,k,k1,kndex;
+
+ if (!A) return -1;
+
+ A1 = NULL;
+ kndex = index;
+
+ if (kndex<0) { // the new atoms are to be inserted
+
+ kndex = -kndex;
+
+ if (nAtoms+natms>=atmLen)
+ ExpandAtomArray ( IMax(kndex,nAtoms)+1000+natms-atmLen );
+
+ if (kndex<nAtoms)
+ A1 = new PAtom[natms];
+ k = kndex-1;
+ j = 0;
+ for (i=0;i<natms;i++)
+ if (A[i]) {
+ if (atom[k]) A1[j++] = atom[k];
+ atom[k] = A[i];
+ atom[k]->index = k+1;
+ k++;
+ }
+
+ if (j>0) {
+ // insert removed atoms into the gap
+ nAtoms += j;
+ k1 = k+j;
+ for (i=nAtoms-1;i>=k1;i--) {
+ atom[i] = atom[i-j];
+ if (atom[i])
+ atom[i]->index = i+1; // this is Ok because residues keep
+ // POINTERS rather than indices!
+ }
+ for (i=0;i<j;i++) {
+ atom[k] = A1[i];
+ atom[k]->index = k+1;
+ k++;
+ }
+ }
+
+ delete[] A1;
+
+ } else {
+
+ if (kndex==0) kndex = nAtoms + 1; // add atom on the very top
+ k = kndex + natms;
+ if (k>atmLen) ExpandAtomArray ( k+1000-atmLen );
+ kndex--;
+ for (i=0;i<natms;i++)
+ if (A[i]) {
+ if (atom[kndex]) delete atom[kndex];
+ atom[kndex] = A[i];
+ atom[kndex]->index = kndex+1;
+ kndex++;
+ }
+ nAtoms = IMax(nAtoms,kndex);
+
+ }
+
+ return 0;
+
+ }
+
+
+ ERROR_CODE Root::SwitchModel ( cpstr L ) {
+ int nM;
+
+ if (!GetInteger(nM,&(L[10]),4))
+ return Error_UnrecognizedInteger;
+
+ return SwitchModel ( nM );
+
+ }
+
+ ERROR_CODE Root::SwitchModel ( int nM ) {
+ PPModel Mdl;
+ int i;
+ bool Transfer;
+
+ if (nM<=0)
+ return Error_WrongModelNo;
+
+ if (nM>nModels) {
+ if ((nModels==1) && model[0]) Transfer = (nAtoms<=0);
+ else Transfer = false;
+ Mdl = new PModel[nM];
+ for (i=0;i<nModels;i++)
+ Mdl[i] = model[i];
+ for (i=nModels;i<nM;i++)
+ Mdl[i] = NULL;
+ if (model) delete[] model;
+ model = Mdl;
+ nModels = nM;
+ if (Transfer) {
+ model[nM-1] = model[0];
+ model[0] = NULL;
+ }
+ }
+
+ if (!model[nM-1])
+ model[nM-1] = newModel();
+ model[nM-1]->SetMMDBManager ( PManager(this),nM );
+
+ crModel = model[nM-1];
+ crChain = NULL; // new model - new chain
+ crRes = NULL; // new chain - new residue
+
+ return Error_NoError;
+
+ }
+
+ ERROR_CODE Root::CheckAtomPlace ( int index, cpstr L ) {
+ // This function gets the residue/chain information stored
+ // in PDB string L (the records should start with the
+ // keywords ATOM, SIGATM, ANISOU, SIGUIJ, TER, HETATM) and
+ // sets the pointers crChain and crRes to the respective.
+ // chain and residue. If there is no chain/residue to place
+ // the atom in, these will be created.
+ // The function prepares place for the atom in the index-th
+ // cell of the Atom array, expanding it as necessary. If the
+ // corresponding element in the Atom array was not initialized,
+ // a Atom class is created with reference to the current
+ // residue.
+ // This function DOES NOT check the PDB string L for
+ // atom keywords.
+ ResName resName;
+ int seqNum;
+ ChainID chainID;
+ InsCode insCode;
+
+ // get the residue sequence number/ insert code
+ if (!GetIntIns(seqNum,insCode,&(L[22]),4)) {
+ if (strncmp(L,"TER ",6))
+ return Error_UnrecognizedInteger;
+ else { // we allow for empty TER card here
+ seqNum = 0;
+ insCode[0] = char(1); // unprintable symbol! used as
+ // flag that TER card does not
+ // have serial number
+ insCode[1] = char(0);
+ }
+ }
+
+ // get chain ID
+ if (L[20]!=' ') {
+ chainID[0] = L[20];
+ chainID[1] = L[21];
+ chainID[2] = char(0);
+ } else if (L[21]!=' ') {
+ chainID[0] = L[21];
+ chainID[1] = char(0);
+ } else
+ chainID[0] = char(0);
+
+ // get residue name
+ strcpy_ncss ( resName,&(L[17]),3 );
+ if ((!resName[0]) && (!strncmp(L,"TER ",6))) {
+ insCode[0] = char(1);
+ insCode[1] = char(0);
+ }
+
+ return AllocateAtom ( index ,chainID,chainID,resName,resName,
+ seqNum,seqNum,1,insCode,false );
+
+ }
+
+ ERROR_CODE Root::CheckAtomPlace ( int index, mmcif::PLoop Loop ) {
+ // Version of CheckAtomPlace(..) for reading from CIF file.
+ ResName resName,label_comp_id;
+ int seqNum ,label_seq_id,label_entity_id,RC,k,nM;
+ ChainID chainID,label_asym_id;
+ InsCode insCode;
+ pstr F;
+
+ // Get the residue sequence number/insert code. They are
+ // removed from the file after reading.
+ k = index-1;
+ // if (!CIFGetInteger1(seqNum,Loop,CIFTAG_LABEL_SEQ_ID,k))
+ if (!CIFGetInteger1(seqNum,Loop,CIFTAG_AUTH_SEQ_ID,k))
+ CIFGetString ( insCode,Loop,CIFTAG_NDB_HELIX_CLASS_PDB,k,
+ sizeof(InsCode),pstr("") );
+ else {
+ F = Loop->GetString ( CIFTAG_GROUP_PDB,k,RC );
+ if ((!F) || (RC)) return Error_CIF_EmptyRow;
+ if (strcmp(F,"TER")) {
+ seqNum = MinInt4; // only at reading CIF we allow this
+ CIFGetString ( insCode,Loop,CIFTAG_NDB_HELIX_CLASS_PDB,k,
+ sizeof(InsCode),pstr("") );
+ } else { // we allow for empty TER card here
+ seqNum = 0;
+ insCode[0] = char(1); // unprintable symbol! used as
+ // flag that TER card does not
+ // have serial number
+ insCode[1] = char(0);
+ }
+ }
+
+ CIFGetInteger1 ( label_seq_id ,Loop,CIFTAG_LABEL_SEQ_ID ,k );
+ CIFGetInteger1 ( label_entity_id,Loop,CIFTAG_LABEL_ENTITY_ID,k );
+
+ // get chain/residue ID
+ CIFGetString ( chainID,Loop,CIFTAG_AUTH_ASYM_ID,k,
+ sizeof(ChainID),pstr("") );
+ CIFGetString ( resName,Loop,CIFTAG_AUTH_COMP_ID,k,
+ sizeof(ResName),pstr("") );
+
+ CIFGetString ( label_asym_id,Loop,CIFTAG_LABEL_ASYM_ID,k,
+ sizeof(ChainID),pstr("") );
+ CIFGetString ( label_comp_id,Loop,CIFTAG_LABEL_COMP_ID,k,
+ sizeof(ResName),pstr("") );
+
+ if (!resName[0]) strcpy ( resName,label_comp_id );
+
+ if (!CIFGetInteger1(nM,Loop,CIFTAG_PDBX_PDB_MODEL_NUM,k)) {
+ if (crModel) {
+ if (nM!=crModel->serNum) SwitchModel ( nM );
+ } else
+ SwitchModel ( nM );
+ }
+
+ return AllocateAtom ( index ,chainID,label_asym_id,resName,
+ label_comp_id,seqNum,label_seq_id,
+ label_entity_id,insCode,false );
+
+ }
+
+
+ ERROR_CODE Root::AllocateAtom ( int index,
+ const ChainID chainID,
+ const ChainID label_asym_id,
+ const ResName resName,
+ const ResName label_comp_id,
+ int seqNum,
+ int label_seq_id,
+ int label_entity_id,
+ const InsCode insCode,
+ bool Replace ) {
+
+ if ((!resName[0]) && (insCode[0]!=char(1)))
+ return Error_EmptyResidueName;
+
+ // check if there is a pointer to model
+ if (!crModel) {
+ // the model pointer was not set. Check if there are
+ // models already defined
+ if (!model)
+ SwitchModel ( 1 ); // creates a model
+ else return Error_NoModel;
+ }
+
+ if (crChain && (insCode[0]!=char(1))) {
+ // If crChain is not NULL, the model pointer was not
+ // changed and we may try to keep using crChain as
+ // pointer to the being-read chain. However, we must
+ // check that the record still belongs to the same chain.
+ // All this does not work if insCode[0] is set to 1
+ // which indicates a special case of 'TER' card without
+ // parameters.
+ if (enforceUniqueChID) {
+ // enforcing unique chain IDs should be used only in case
+ // of multi-chain complexes where 1-letter chain IDs are
+ // not enough to accomodate all chains. Then chains are
+ // dynamically renamed like A0,A1,A2,.. etc. Therefore, we
+ // check only first symbol here.
+ if (chainID[0]!=crChain->chainID[0])
+ crChain = NULL; // the chain has to be changed
+ } else if (strcmp(chainID,crChain->chainID))
+ crChain = NULL; // the chain has to be changed
+ }
+ if (!crChain) {
+ // either the model or chain was changed -- get a new chain
+ if (allowDuplChID)
+ crChain = crModel->CreateChain ( chainID );
+ else crChain = crModel->GetChainCreate ( chainID,
+ enforceUniqueChID );
+ crRes = NULL; // new chain - new residue
+ }
+
+ if (crRes && (insCode[0]!=char(1))) {
+ // If crRes is not NULL, neither the model nor chain were
+ // changed. Check if this record still belongs to the
+ // same residue.
+ // All this does not work if insCode[0] is set to 1
+ // which indicates a special case of 'TER' card without
+ // parameters.
+ if ((seqNum!=crRes->seqNum) ||
+ strcmp(insCode,crRes->insCode) ||
+ strcmp(resName,crRes->name))
+ crRes = NULL; // the residue has to be changed
+ }
+ if (!crRes) {
+ // either the chain or residue was changed -- get a new residue
+ crRes = crChain->GetResidueCreate ( resName,seqNum,insCode,
+ Flags & MMDBF_IgnoreDuplSeqNum );
+ if (!crRes) return Error_DuplicateSeqNum;
+ }
+
+ strcpy ( crRes->label_asym_id,label_asym_id );
+ strcpy ( crRes->label_comp_id,label_comp_id );
+ crRes->label_seq_id = label_seq_id;
+ crRes->label_entity_id = label_entity_id;
+
+ // now check if there is place in the Atom array
+ if (index>atmLen)
+ // there is no place, expand Atom by 1000 atom places at once
+ ExpandAtomArray ( index+1000-atmLen );
+ nAtoms = IMax(nAtoms,index);
+
+ // delete the to-be-replaced atom if there is any
+ if (Replace && atom[index-1]) {
+ delete atom[index-1];
+ atom[index-1] = NULL;
+ }
+ if (!atom[index-1]) {
+ atom[index-1] = newAtom();
+ crRes->_AddAtom ( atom[index-1] );
+ atom[index-1]->index = index;
+ }
+
+ return Error_NoError;
+
+ }
+
+ void Root::ExpandAtomArray ( int inc ) {
+ // Expands the Atom array by adding more inc positions.
+ // The length of Atom array is increased unconditionally.
+ PPAtom Atom1;
+ int i;
+ atmLen += inc;
+ Atom1 = new PAtom[atmLen];
+ for (i=0;i<nAtoms;i++)
+ Atom1[i] = atom[i];
+ for (i=nAtoms;i<atmLen;i++)
+ Atom1[i] = NULL;
+ if (atom) delete[] atom;
+ atom = Atom1;
+ }
+
+ void Root::AddAtomArray ( int inc ) {
+ // Checks if 'inc' atoms may be added into Atom array,
+ // and if not, expands the Atom array such that to
+ // allocate exactly 'inc' atoms more than is currently
+ // contained.
+ PPAtom Atom1;
+ int i;
+ if (nAtoms+inc>atmLen) {
+ atmLen = nAtoms+inc;
+ Atom1 = new PAtom[atmLen];
+ for (i=0;i<nAtoms;i++)
+ Atom1[i] = atom[i];
+ for (i=nAtoms;i<atmLen;i++)
+ Atom1[i] = NULL;
+ if (atom) delete[] atom;
+ atom = Atom1;
+ }
+ }
+
+
+ ERROR_CODE Root::WritePDBASCII1 ( cpstr PDBLFName,
+ io::GZ_MODE gzipMode ) {
+ pstr FName;
+ FName = getenv ( PDBLFName );
+ if (FName) return WritePDBASCII ( FName,gzipMode );
+ else return Error_NoLogicalName;
+ }
+
+ ERROR_CODE Root::WritePDBASCII ( cpstr PDBFileName,
+ io::GZ_MODE gzipMode ) {
+ io::File f;
+
+ // opening it in pseudo-text mode ensures that the line
+ // endings will correspond to the system MMDB is running on
+ f.assign ( PDBFileName,true,false,gzipMode );
+ FType = MMDB_FILE_PDB;
+
+ if (f.rewrite()) {
+ WritePDBASCII ( f );
+ f.shut();
+ } else
+ return Error_CantOpenFile;
+
+ return Error_NoError;
+
+ }
+
+
+ void Root::WritePDBASCII ( io::RFile f ) {
+ int i;
+
+ FType = MMDB_FILE_PDB;
+
+ title.PDBASCIIDump ( f );
+
+ i = 0;
+ while (i<nModels)
+ if (model[i]) break;
+ else i++;
+ if (i<nModels)
+ model[i]->PDBASCIIDumpPS ( f );
+
+ // output cispep records
+ for (i=0;i<nModels;i++)
+ if (model[i])
+ model[i]->PDBASCIIDumpCP ( f );
+
+ SA .PDBASCIIDump ( f );
+ Footnote.PDBASCIIDump ( f );
+ cryst .PDBASCIIDump ( f );
+ SB .PDBASCIIDump ( f );
+
+ for (i=0;i<nModels;i++)
+ if (model[i])
+ model[i]->PDBASCIIDump ( f );
+
+ SC.PDBASCIIDump ( f );
+
+ f.WriteLine ( pstr("END") );
+
+ }
+
+
+ ERROR_CODE Root::WriteCIFASCII1 ( cpstr CIFLFName,
+ io::GZ_MODE gzipMode ) {
+ pstr FName;
+ FName = getenv ( CIFLFName );
+ if (FName) return WriteCIFASCII ( FName,gzipMode );
+ else return Error_NoLogicalName;
+ }
+
+ ERROR_CODE Root::WriteCIFASCII ( cpstr CIFFileName,
+ io::GZ_MODE gzipMode ) {
+ int i;
+
+ if (!CIF) CIF = new mmcif::Data();
+ CIF->SetStopOnWarning ( true );
+ CIF->SetPrintWarnings ( (Flags & MMDBF_PrintCIFWarnings)!=0 );
+ FType = MMDB_FILE_CIF;
+
+ title.MakeCIF ( CIF );
+
+ i = 0;
+ while (i<nModels)
+ if (model[i]) break;
+ else i++;
+ if (i<nModels)
+ model[i]->MakePSCIF ( CIF );
+
+ cryst.MakeCIF ( CIF );
+
+ for (i=0;i<nModels;i++)
+ if (model[i])
+ model[i]->MakeAtomCIF ( CIF );
+
+ CIF->Optimize();
+ CIF->WriteMMCIFData ( CIFFileName,gzipMode );
+
+ return Error_NoError;
+
+ }
+
+
+ PAtom Root::GetAtomI ( int index ) {
+ if (index>nAtoms) return NULL;
+ if (index<1) return NULL;
+ if (!atom) return NULL;
+ return atom[index-1];
+ }
+
+
+ #define MMDBFLabel "**** This is MMDB binary file ****"
+ #define Edition 1
+
+ ERROR_CODE Root::ReadMMDBF1 ( cpstr MMDBLFName,
+ io::GZ_MODE gzipMode ) {
+ pstr FName;
+ FName = getenv ( MMDBLFName );
+ if (FName) return ReadCoorFile ( FName,gzipMode );
+ else return Error_NoLogicalName;
+ }
+
+ ERROR_CODE Root::ReadMMDBF ( cpstr MMDBRootName,
+ io::GZ_MODE gzipMode ) {
+ io::File f;
+ ERROR_CODE rc;
+
+ f.assign ( MMDBRootName,false,true,gzipMode );
+ FType = MMDB_FILE_Binary;
+ if (f.reset(true)) {
+ rc = ReadMMDBF ( f );
+ f.shut();
+ } else
+ rc = Error_CantOpenFile;
+
+ return rc;
+
+ }
+
+ ERROR_CODE Root::ReadMMDBF ( io::RFile f ) {
+ char Label[100];
+ byte Version;
+
+ FType = MMDB_FILE_Binary;
+ f.ReadFile ( Label,sizeof(MMDBFLabel) );
+ if (strncmp(Label,MMDBFLabel,sizeof(MMDBFLabel)))
+ return Error_ForeignFile;
+
+ f.ReadByte ( &Version );
+ if (Version>Edition)
+ return Error_WrongEdition;
+
+ read ( f );
+
+ return Error_NoError;
+
+ }
+
+
+ ERROR_CODE Root::WriteMMDBF1 ( cpstr MMDBLFName, io::GZ_MODE gzipMode ) {
+ pstr FName;
+ FName = getenv ( MMDBLFName );
+ if (FName) return WriteMMDBF ( FName,gzipMode );
+ else return Error_NoLogicalName;
+ }
+
+ ERROR_CODE Root::WriteMMDBF ( cpstr MMDBRootName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ char Label[100];
+ byte Version=Edition;
+
+ f.assign ( MMDBRootName,false,true,gzipMode );
+ FType = MMDB_FILE_Binary;
+ if (f.rewrite()) {
+ strcpy ( Label,MMDBFLabel );
+ f.WriteFile ( Label,sizeof(MMDBFLabel) );
+ f.WriteByte ( &Version );
+ write ( f );
+ f.shut();
+ } else
+ return Error_CantOpenFile;
+
+ return Error_NoError;
+
+ }
+
+
+ pstr Root::GetEntryID() {
+ return title.idCode;
+ }
+
+ void Root::SetEntryID ( const IDCode idCode ) {
+ strcpy ( title.idCode,idCode );
+ }
+
+ void Root::SetSyminfoLib ( cpstr syminfo_lib ) {
+ cryst.SetSyminfoLib ( syminfo_lib );
+ }
+
+ pstr Root::GetSyminfoLib() {
+ return cryst.GetSyminfoLib();
+ }
+
+ int Root::SetSpaceGroup ( cpstr spGroup ) {
+ return cryst.SetSpaceGroup ( spGroup );
+ }
+
+ pstr Root::GetSpaceGroup() {
+ return cryst.GetSpaceGroup();
+ }
+
+ pstr Root::GetSpaceGroupFix() {
+ return cryst.GetSpaceGroupFix();
+ }
+
+ void Root::GetAtomStatistics ( RAtomStat AS ) {
+ int i;
+ AS.Init();
+ for (i=0;i<nModels;i++)
+ if (model[i]) model[i]->CalAtomStatistics ( AS );
+ AS.Finish();
+ }
+
+ void Root::SetIgnoreSCALEi ( bool ignoreScalei ) {
+ cryst.ignoreScalei = ignoreScalei;
+ }
+
+ void Root::SetCell ( realtype cell_a,
+ realtype cell_b,
+ realtype cell_c,
+ realtype cell_alpha,
+ realtype cell_beta,
+ realtype cell_gamma,
+ int OrthCode ) {
+ cryst.SetCell ( cell_a,cell_b,cell_c,cell_alpha,cell_beta,
+ cell_gamma,OrthCode );
+ }
+
+ void Root::PutCell ( realtype cell_a,
+ realtype cell_b,
+ realtype cell_c,
+ realtype cell_alpha,
+ realtype cell_beta,
+ realtype cell_gamma,
+ int OrthCode ) {
+ cryst.PutCell ( cell_a,cell_b,cell_c,cell_alpha,cell_beta,
+ cell_gamma,OrthCode );
+ }
+
+ int Root::GetCell ( realtype & cell_a,
+ realtype & cell_b,
+ realtype & cell_c,
+ realtype & cell_alpha,
+ realtype & cell_beta,
+ realtype & cell_gamma,
+ realtype & vol,
+ int & OrthCode ) {
+ if (cryst.WhatIsSet & CSET_CellParams) {
+ cryst.GetCell ( cell_a,cell_b,cell_c,cell_alpha,cell_beta,
+ cell_gamma,vol );
+ OrthCode = cryst.NCode + 1;
+ return 1;
+ } else {
+ cell_a = 0.0; cell_b = 0.0; cell_c = 0.0;
+ cell_alpha = 0.0; cell_beta = 0.0; cell_gamma = 0.0;
+ vol = 0.0; OrthCode = 0;
+ return 0;
+ }
+ }
+
+ int Root::GetRCell ( realtype & cell_as,
+ realtype & cell_bs,
+ realtype & cell_cs,
+ realtype & cell_alphas,
+ realtype & cell_betas,
+ realtype & cell_gammas,
+ realtype & vols,
+ int & OrthCode ) {
+ if (cryst.WhatIsSet & CSET_CellParams) {
+ cryst.GetRCell ( cell_as,cell_bs,cell_cs,cell_alphas,cell_betas,
+ cell_gammas,vols );
+ OrthCode = cryst.NCode + 1;
+ return 1;
+ } else {
+ cell_as = 0.0; cell_bs = 0.0; cell_cs = 0.0;
+ cell_alphas = 0.0; cell_betas = 0.0; cell_gammas = 0.0;
+ vols = 0.0; OrthCode = 0;
+ return 0;
+ }
+ }
+
+ int Root::GetNumberOfSymOps() {
+ if (cryst.WhatIsSet & CSET_SpaceGroup)
+ return cryst.GetNumberOfSymOps();
+ else return 0;
+ }
+
+ pstr Root::GetSymOp ( int Nop ) {
+ return cryst.GetSymOp ( Nop );
+ }
+
+
+ void Root::GetROMatrix ( mat44 & RO ) {
+ Mat4Copy ( cryst.RO,RO );
+ }
+
+ int Root::GetTMatrix ( mat44 & TMatrix, int Nop,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c ) {
+ // GetTMatrix(..) calculates and returns the coordinate transformation
+ // matrix, which converts orthogonal coordinates according to
+ // the symmetry operation number Nop and places them into unit cell
+ // shifted by cellshift_a a's, cellshift_b b's and cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ return cryst.GetTMatrix ( TMatrix,Nop,cellshift_a,cellshift_b,
+ cellshift_c,NULL );
+ }
+
+
+ int Root::GetUCTMatrix ( mat44 & TMatrix, int Nop,
+ realtype x, realtype y, realtype z,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c ) {
+ // GetUCTMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts orthogonal coordinates
+ // according to the symmetry operation number Nop. Translation
+ // part of the resulting matrix is being chosen such that point
+ // (x,y,z) has least distance to the center of primary (333)
+ // unit cell, and then it is shifted by cellshift_a a's,
+ // cellshift_b b's and cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ return cryst.GetUCTMatrix ( TMatrix,Nop,x,y,z,
+ cellshift_a,cellshift_b,cellshift_c,
+ NULL );
+ }
+
+
+ int Root::GetFractMatrix ( mat44 & TMatrix, int Nop,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c ) {
+ // GetFractMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts fractional coordinates
+ // according to the symmetry operation number Nop and places them
+ // into unit cell shifted by cellshift_a a's, cellshift_b b's and
+ // cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ return cryst.GetFractMatrix ( TMatrix,Nop,cellshift_a,cellshift_b,
+ cellshift_c,NULL );
+ }
+
+ int Root::GetSymOpMatrix ( mat44 & TMatrix, int Nop ) {
+ //
+ // GetSymOpMatrix(..) returns the transformation matrix for
+ // Nop-th symmetry operator in the space group
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ //
+ return cryst.GetSymOpMatrix ( TMatrix,Nop );
+ }
+
+ // ------------- User-Defined Data ------------------------
+
+ int Root::RegisterUDInteger ( UDR_TYPE udr_type, cpstr UDDataID ) {
+ return udRegister.RegisterUDInteger ( udr_type,UDDataID );
+ }
+
+ int Root::RegisterUDReal ( UDR_TYPE udr_type, cpstr UDDataID ) {
+ return udRegister.RegisterUDReal ( udr_type,UDDataID );
+ }
+
+ int Root::RegisterUDString ( UDR_TYPE udr_type, cpstr UDDataID ) {
+ return udRegister.RegisterUDString ( udr_type,UDDataID );
+ }
+
+ int Root::GetUDDHandle ( UDR_TYPE udr_type, cpstr UDDataID ) {
+ return udRegister.GetUDDHandle ( udr_type,UDDataID );
+ }
+
+
+
+ // ----------------------------------------------------------
+
+ int Root::DeleteAllModels() {
+ int i,k;
+ Exclude = false;
+ k = 0;
+ for (i=0;i<nModels;i++) {
+ if (model[i]) {
+ delete model[i];
+ model[i] = NULL;
+ k++;
+ }
+ }
+ Exclude = true;
+ FinishStructEdit();
+ return k;
+ }
+
+ bool Root::GetNewChainID ( int modelNo, ChainID chID,
+ int length ) {
+ if ((modelNo>=1) && (modelNo<=nModels)) {
+ if (model[modelNo-1])
+ return model[modelNo-1]->GetNewChainID ( chID,length );
+ }
+ return false;
+ }
+
+ // -------------------------------------------------------------
+
+ PMask Root::GetSelMask ( int selHnd ) {
+ UNUSED_ARGUMENT(selHnd);
+ return NULL;
+ }
+
+ // -------------------------------------------------------------
+
+ int Root::GetNofExpDataRecs() {
+ return title.expData.Length();
+ }
+
+ pstr Root::GetExpDataRec ( int recNo ) {
+ PExpData expData;
+ expData = PExpData(title.expData.GetContainerClass(recNo));
+ if (expData) return expData->Line;
+ return NULL;
+ }
+
+
+ // -------------------------------------------------------------
+
+ int Root::GetNofMdlTypeRecs() {
+ return title.mdlType.Length();
+ }
+
+ pstr Root::GetMdlTypeRec ( int recNo ) {
+ PMdlType mdlType;
+ mdlType = PMdlType(title.mdlType.GetContainerClass(recNo));
+ if (mdlType) return mdlType->Line;
+ return NULL;
+ }
+
+
+ // ------------------- Stream functions ----------------------
+
+ void Root::Copy ( PRoot MMDBRoot ) {
+ int i;
+
+ title.Copy ( &MMDBRoot->title );
+ cryst.Copy ( &MMDBRoot->cryst );
+
+ // It is important to copy atoms _before_ models,
+ // residues and chains!
+ Flags = MMDBRoot->Flags;
+ nAtoms = MMDBRoot->nAtoms;
+ atmLen = nAtoms;
+ if (nAtoms>0) {
+ atom = new PAtom[atmLen];
+ for (i=0;i<nAtoms;i++)
+ if (MMDBRoot->atom[i]) {
+ atom[i] = newAtom();
+ atom[i]->Copy ( MMDBRoot->atom[i] );
+ atom[i]->index = i+1;
+ // the internal atom references are installed
+ // by residue classes when they are copied in
+ // model->chain below
+ } else
+ atom[i] = NULL;
+ }
+
+ nModels = MMDBRoot->nModels;
+ if (nModels>0) {
+ model = new PModel[nModels];
+ for (i=0;i<nModels;i++) {
+ if (MMDBRoot->model[i]) {
+ model[i] = newModel();
+ model[i]->SetMMDBManager ( PManager(this),i+1 );
+ model[i]->_copy ( MMDBRoot->model[i] );
+ } else
+ model[i] = NULL;
+ }
+ }
+
+ SA .Copy ( &MMDBRoot->SA );
+ Footnote.Copy ( &MMDBRoot->Footnote );
+ SB .Copy ( &MMDBRoot->SB );
+ SC .Copy ( &MMDBRoot->SC );
+
+ if (MMDBRoot->CIF) {
+ CIF = new mmcif::Data;
+ CIF->Copy ( MMDBRoot->CIF );
+ }
+
+ }
+
+
+
+ // ------- user-defined data handlers
+
+ int Root::PutUDData ( int UDDhandle, int iudd ) {
+ if (UDDhandle & UDRF_HIERARCHY)
+ return UDData::putUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Root::PutUDData ( int UDDhandle, realtype rudd ) {
+ if (UDDhandle & UDRF_HIERARCHY)
+ return UDData::putUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Root::PutUDData ( int UDDhandle, cpstr sudd ) {
+ if (UDDhandle & UDRF_HIERARCHY)
+ return UDData::putUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Root::GetUDData ( int UDDhandle, int & iudd ) {
+ if (UDDhandle & UDRF_HIERARCHY)
+ return UDData::getUDData ( UDDhandle,iudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Root::GetUDData ( int UDDhandle, realtype & rudd ) {
+ if (UDDhandle & UDRF_HIERARCHY)
+ return UDData::getUDData ( UDDhandle,rudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Root::GetUDData ( int UDDhandle, pstr sudd, int maxLen ) {
+ if (UDDhandle & UDRF_HIERARCHY)
+ return UDData::getUDData ( UDDhandle,sudd,maxLen );
+ else return UDDATA_WrongUDRType;
+ }
+
+ int Root::GetUDData ( int UDDhandle, pstr & sudd ) {
+ if (UDDhandle & UDRF_HIERARCHY)
+ return UDData::getUDData ( UDDhandle,sudd );
+ else return UDDATA_WrongUDRType;
+ }
+
+
+ pstr Root::GetStructureTitle ( pstr & L ) {
+ return title.GetStructureTitle ( L );
+ }
+
+ void Root::SetShortBinary() {
+ // leaves only coordinates in binary files
+ int i;
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) atom[i]->SetShortBinary();
+ }
+
+
+ void Root::write ( io::RFile f ) {
+ int i,k;
+ byte Version=1;
+
+ f.WriteByte ( &Version );
+
+ UDData::write ( f );
+
+ title .write ( f );
+ cryst .write ( f );
+ udRegister.write ( f );
+ DefPath .write ( f );
+
+ f.WriteWord ( &Flags );
+ f.WriteInt ( &nAtoms );
+ for (i=0;i<nAtoms;i++) {
+ if (atom[i]) k = 1;
+ else k = 0;
+ f.WriteInt ( &k );
+ if (atom[i]) atom[i]->write ( f );
+ }
+
+ f.WriteInt ( &nModels );
+ for (i=0;i<nModels;i++) {
+ if (model[i]) k = 1;
+ else k = 0;
+ f.WriteInt ( &k );
+ if (model[i]) model[i]->write ( f );
+ }
+
+ SA .write ( f );
+ Footnote.write ( f );
+ SB .write ( f );
+ SC .write ( f );
+
+ StreamWrite ( f,CIF );
+
+ }
+
+ void Root::read ( io::RFile f ) {
+ int i,k;
+ byte Version;
+
+ ResetManager ();
+ FreeFileMemory();
+
+ f.ReadByte ( &Version );
+
+ UDData::read ( f );
+
+ title .read ( f );
+ cryst .read ( f );
+ udRegister.read ( f );
+ DefPath .read ( f );
+
+ // It is important to read atoms before models,
+ // residues and chains!
+ f.ReadWord ( &Flags );
+ f.ReadInt ( &nAtoms );
+ atmLen = nAtoms;
+ if (nAtoms>0) {
+ atom = new PAtom[atmLen];
+ for (i=0;i<nAtoms;i++) {
+ f.ReadInt ( &k );
+ if (k) {
+ atom[i] = newAtom();
+ atom[i]->read ( f );
+ // the internal atom references are installed
+ // by residue classes when they are read in
+ // model->chain below
+ } else
+ atom[i] = NULL;
+ }
+ }
+
+ f.ReadInt ( &nModels );
+ if (nModels>0) {
+ model = new PModel[nModels];
+ for (i=0;i<nModels;i++) {
+ f.ReadInt ( &k );
+ if (k) {
+ model[i] = newModel();
+ model[i]->SetMMDBManager ( PManager(this),0 );
+ model[i]->read ( f );
+ } else
+ model[i] = NULL;
+ }
+ }
+
+ SA .read ( f );
+ Footnote.read ( f );
+ SB .read ( f );
+ SC .read ( f );
+
+ StreamRead ( f,CIF );
+
+ }
+
+
+ MakeStreamFunctions(Root)
+
+
+ int isMMDBBIN ( cpstr FName, io::GZ_MODE gzipMode ) {
+ io::File f;
+ int rc;
+
+ f.assign ( FName,false,true,gzipMode );
+ if (f.reset(true)) {
+ rc = isMMDBBIN ( f );
+ f.shut();
+ } else
+ rc = -1;
+
+ return rc;
+
+ }
+
+ int isMMDBBIN ( io::RFile f ) {
+ char Label[100];
+ byte Version;
+
+ if (f.FileEnd())
+ return Error_EmptyFile;
+
+ f.ReadFile ( Label,sizeof(MMDBFLabel) );
+ if (strncmp(Label,MMDBFLabel,sizeof(MMDBFLabel)))
+ return 1;
+
+ f.ReadByte ( &Version );
+
+ if (Version>Edition) return 2;
+ else return 0;
+
+ }
+
+
+ int isPDB ( cpstr FName, io::GZ_MODE gzipMode,
+ bool IgnoreBlankLines ) {
+ io::File f;
+ int rc;
+
+ f.assign ( FName,false,false,gzipMode );
+ if (f.reset(true)) {
+ // opening it in pseudo-binary mode helps reading various
+ // line terminators for files coming from different platforms
+ rc = isPDB ( f,IgnoreBlankLines );
+ f.shut();
+ } else
+ rc = -1;
+
+ return rc;
+
+ }
+
+ int isPDB ( io::RFile f, bool IgnoreBlankLines ) {
+ char S[256];
+ int i;
+ bool Done;
+
+ if (f.FileEnd())
+ return Error_EmptyFile;
+
+ do {
+ Done = true;
+ f.ReadLine ( S,sizeof(S)-1 );
+ if (IgnoreBlankLines) {
+ i = 0;
+ while (S[i] && (S[i]==' ')) i++;
+ if (!S[i]) Done = false;
+ }
+ } while ((!f.FileEnd()) && (!Done));
+
+ PadSpaces ( S,80 );
+ if (!strncasecmp(S,"HEADER",6)) return 0;
+ if (!strncasecmp(S,"OBSLTE",6)) return 0;
+ if (!strncasecmp(S,"TITLE ",6)) return 0;
+ if (!strncasecmp(S,"CAVEAT",6)) return 0;
+ if (!strncasecmp(S,"COMPND",6)) return 0;
+ if (!strncasecmp(S,"SOURCE",6)) return 0;
+ if (!strncasecmp(S,"KEYWDS",6)) return 0;
+ if (!strncasecmp(S,"EXPDTA",6)) return 0;
+ if (!strncasecmp(S,"AUTHOR",6)) return 0;
+ if (!strncasecmp(S,"REVDAT",6)) return 0;
+ if (!strncasecmp(S,"SPRSDE",6)) return 0;
+ if (!strncasecmp(S,"JRNL ",6)) return 0;
+ if (!strncasecmp(S,"REMARK",6)) return 0;
+ if (!strncasecmp(S,"DBREF ",6)) return 0;
+ if (!strncasecmp(S,"SEQADV",6)) return 0;
+ if (!strncasecmp(S,"SEQRES",6)) return 0;
+ if (!strncasecmp(S,"MODRES",6)) return 0;
+ if (!strncasecmp(S,"HET ",6)) return 0;
+ if (!strncasecmp(S,"HETNAM",6)) return 0;
+ if (!strncasecmp(S,"HETSYN",6)) return 0;
+ if (!strncasecmp(S,"FORMUL",6)) return 0;
+ if (!strncasecmp(S,"HELIX ",6)) return 0;
+ if (!strncasecmp(S,"SHEET ",6)) return 0;
+ if (!strncasecmp(S,"TURN ",6)) return 0;
+ if (!strncasecmp(S,"SSBOND",6)) return 0;
+ if (!strncasecmp(S,"LINK ",6)) return 0;
+ if (!strncasecmp(S,"HYDBND",6)) return 0;
+ if (!strncasecmp(S,"SLTBRG",6)) return 0;
+ if (!strncasecmp(S,"CISPEP",6)) return 0;
+ if (!strncasecmp(S,"SITE ",6)) return 0;
+ if (!strncasecmp(S,"CRYST1",6)) return 0;
+ if (!strncasecmp(S,"CRYST ",6)) return 0;
+ if (!strncasecmp(S,"ORIGX1",6)) return 0;
+ if (!strncasecmp(S,"ORIGX2",6)) return 0;
+ if (!strncasecmp(S,"ORIGX3",6)) return 0;
+ if (!strncasecmp(S,"SCALE1",6)) return 0;
+ if (!strncasecmp(S,"SCALE2",6)) return 0;
+ if (!strncasecmp(S,"SCALE3",6)) return 0;
+ if (!strncasecmp(S,"MTRIX1",6)) return 0;
+ if (!strncasecmp(S,"MTRIX2",6)) return 0;
+ if (!strncasecmp(S,"MTRIX3",6)) return 0;
+ if (!strncasecmp(S,"TVECT ",6)) return 0;
+ if (!strncasecmp(S,"MODEL ",6)) return 0;
+ if (!strncasecmp(S,"ATOM ",6)) return 0;
+ if (!strncasecmp(S,"SIGATM",6)) return 0;
+ if (!strncasecmp(S,"ANISOU",6)) return 0;
+ if (!strncasecmp(S,"SIGUIJ",6)) return 0;
+ if (!strncasecmp(S,"TER ",6)) return 0;
+ if (!strncasecmp(S,"HETATM",6)) return 0;
+ if (!strncasecmp(S,"ENDMDL",6)) return 0;
+ if (!strncasecmp(S,"CONECT",6)) return 0;
+ if (!strncasecmp(S,"MASTER",6)) return 0;
+ if (!strncasecmp(S,"END ",6)) return 0;
+ if (!strncasecmp(S,"USER ",6)) return 0;
+
+ return 1;
+
+ }
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_root.h b/mmdb2/mmdb_root.h
new file mode 100644
index 0000000..df5c0e1
--- /dev/null
+++ b/mmdb2/mmdb_root.h
@@ -0,0 +1,639 @@
+// $Id: mmdb_root.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 14.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Root <interface>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Root
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Root__
+#define __MMDB_Root__
+
+#include "mmdb_io_file.h"
+#include "mmdb_uddata.h"
+#include "mmdb_title.h"
+#include "mmdb_cryst.h"
+#include "mmdb_chain.h"
+#include "mmdb_model.h"
+#include "mmdb_defs.h"
+
+namespace mmdb {
+
+ // ======================= Root ===========================
+
+ // special effect flags
+ enum MMDB_READ_FLAG {
+ MMDBF_AutoSerials = 0x00000001,
+ MMDBF_NoCoordRead = 0x00000002,
+ MMDBF_SimRWBROOK = 0x00000004,
+ MMDBF_PrintCIFWarnings = 0x00000008,
+ MMDBF_EnforceSpaces = 0x00000010,
+ MMDBF_IgnoreDuplSeqNum = 0x00000020,
+ MMDBF_IgnoreSegID = 0x00000040,
+ MMDBF_IgnoreElement = 0x00000080,
+ MMDBF_IgnoreCharge = 0x00000100,
+ MMDBF_IgnoreNonCoorPDBErrors = 0x00000200,
+ MMDBF_IgnoreUnmatch = 0x00000400,
+ MMDBF_IgnoreBlankLines = 0x00000800,
+ MMDBF_IgnoreHash = 0x00001000,
+ MMDBF_IgnoreRemarks = 0x00002000,
+ MMDBF_AllowDuplChainID = 0x00004000,
+ MMDBF_FixSpaceGroup = 0x00008000,
+ MMDBF_EnforceAtomNames = 0x00010000,
+ MMDBF_EnforceUniqueChainID = 0x00020000,
+ MMDBF_DoNotProcessSpaceGroup = 0x00040000
+ };
+
+ // MMDBF_EnforceUniqueChainID will make MMDB to rename chains on
+ // reading a file such as to maintain chains uniquesness. This
+ // is supposed to work only with 1-letter chain IDs and only
+ // if chain names are interchanged in the file. For example,
+ // if file contains a sequence of chains named
+ //
+ // A,B, A,B, A,B, A,B, A,B
+ //
+ // and this flag is set on, the resulting chain names in
+ // MMDB will be:
+ //
+ // A,B, A0,B0, A1,B1, A2,B2, A3,B3
+ //
+
+ // file types:
+ enum MMDB_FILE_TYPE {
+ MMDB_FILE_Undefined = -1,
+ MMDB_FILE_PDB = 0,
+ MMDB_FILE_CIF = 1,
+ MMDB_FILE_Binary = 2
+ };
+
+ // cleanup flags:
+ enum PDB_CLEAN_FLAG {
+ PDBCLEAN_ATNAME = 0x00000001,
+ PDBCLEAN_TER = 0x00000002,
+ PDBCLEAN_CHAIN = 0x00000004,
+ PDBCLEAN_CHAIN_STRONG = 0x00000008,
+ PDBCLEAN_ALTCODE = 0x00000010,
+ PDBCLEAN_ALTCODE_STRONG = 0x00000020,
+ PDBCLEAN_SERIAL = 0x00000040,
+ PDBCLEAN_SEQNUM = 0x00000080,
+ PDBCLEAN_CHAIN_ORDER = 0x00000100,
+ PDBCLEAN_CHAIN_ORDER_IX = 0x00000200,
+ PDBCLEAN_SOLVENT = 0x00000400,
+ PDBCLEAN_INDEX = 0x00000800,
+ PDBCLEAN_ELEMENT = 0x00001000,
+ PDBCLEAN_ELEMENT_STRONG = 0x00002000
+ };
+
+ // crystallographic info inquery
+ enum MMDB_CRYST_FLAG {
+ CRRDY_NotPrecise = 0x00000001,
+ CRRDY_isTranslation = 0x00000002,
+ CRRDY_NoOrthCode = 0x00000004,
+ CRRDY_Complete = 0,
+ CRRDY_NoTransfMatrices = -1,
+ CRRDY_Unchecked = -2,
+ CRRDY_Ambiguous = -3,
+ CRRDY_NoCell = -4,
+ CRRDY_NoSpaceGroup = -5
+ };
+
+ DefineClass(Root);
+ DefineStreamFunctions(Root);
+
+ class Root : public UDData {
+
+ friend class Model;
+ friend class Chain;
+ friend class Residue;
+ friend class Atom;
+
+ public :
+
+ Root ();
+ Root ( io::RPStream Object );
+ ~Root();
+
+ void FreeFileMemory();
+
+
+ // --------------- Reading/Writing external files ---------
+
+ void SetFlag ( word Flag );
+ void RemoveFlag ( word Flag );
+
+ ERROR_CODE ReadPDBASCII ( cpstr PDBFileName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE ReadPDBASCII1 ( cpstr PDBLFName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE ReadPDBASCII ( io::RFile f );
+
+ ERROR_CODE ReadCIFASCII ( cpstr CIFFileName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE ReadCIFASCII1 ( cpstr CIFLFName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE ReadCIFASCII ( io::RFile f );
+ ERROR_CODE ReadFromCIF ( mmcif::PData CIFD );
+
+ // adds info from PDB file
+ ERROR_CODE AddPDBASCII1 ( cpstr PDBLFName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE AddPDBASCII ( cpstr PDBFileName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+ // auto format recognition
+ ERROR_CODE ReadCoorFile ( cpstr LFName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE ReadCoorFile1 ( cpstr CFName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE ReadCoorFile ( io::RFile f );
+
+ ERROR_CODE WritePDBASCII ( cpstr PDBFileName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE WritePDBASCII1 ( cpstr PDBLFName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ void WritePDBASCII ( io::RFile f );
+
+ ERROR_CODE WriteCIFASCII ( cpstr CIFFileName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE WriteCIFASCII1 ( cpstr CIFLFName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+ ERROR_CODE ReadMMDBF ( cpstr MMDBRootName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE ReadMMDBF1 ( cpstr MMDBLFName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE ReadMMDBF ( io::RFile f );
+ ERROR_CODE WriteMMDBF ( cpstr MMDBRootName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+ ERROR_CODE WriteMMDBF1 ( cpstr MMDBLFName,
+ io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+ void GetInputBuffer ( pstr Line, int & count );
+
+ // PutPDBString adds a PDB-keyworded string
+ // to the existing structure. Note that the string
+ // is namely added meaning that it will be the
+ // last REMARK, last JRNL, last ATOM etc. string
+ // -- always the last one in its group.
+ ERROR_CODE PutPDBString ( cpstr PDBString );
+
+
+ // PDBCleanup(..) cleans coordinate part to comply with PDB
+ // standards and MMDB "expectations":
+ //
+ // PDBCLEAN_ATNAME pads atom names with spaces to form
+ // 4-symbol names
+ // PDBCLEAN_TER inserts TER cards in the end of each chain
+ // PDBCLEAN_CHAIN generates 1-character chain ids instead of
+ // those many-character
+ // PDBCLEAN_CHAIN_STRONG generates 1-character chain ids starting
+ // from 'A' on for all ids, including the
+ // single-character ones
+ // PDBCLEAN_ALTCODE generates 1-character alternative codes
+ // instead of many-character ones
+ // PDBCLEAN_ALTCODE_STRONG generates 1-character alternative codes
+ // from 'A' on for all codes, including the
+ // single-character ones
+ // PDBCLEAN_SERIAL puts serial numbers in due order
+ // PDBCLEAN_SEQNUM renumbers all residues so that they go
+ // incrementally-by-one without insertion codes
+ // PDBCLEAN_CHAIN_ORDER puts chains in order of atom's serial
+ // numbers
+ // PDBCLEAN_CHAIN_ORDER_IX puts chains in order of atom's
+ // indices internal to MMDB
+ // PDBCLEAN_SOLVENT moves solvent chains at the end of each model
+ //
+ // Return codes (as bits):
+ // 0 Ok
+ // PDBCLEAN_CHAIN too many chains for assigning them
+ // 1-letter codes
+ // PDBCLEAN_ATNAME element names were not available
+ // PDBCLEAN_ALTCODE too many alternative codes encountered.
+ //
+ word PDBCleanup ( word CleanKey );
+
+ // Makes all atoms in chain 'chainID', in all models, as
+ // 'Het' atoms if Make is set True, and makes them 'ordinary'
+ // atoms otherwise. 'Ter' is automatically removed when
+ // converting to 'Het' atoms, and is automatically added
+ // when converting to 'ordinary' atoms. This may cause
+ // disorder in serial numbers -- just call
+ // PDBClean(PDBCLEAN_SERIAL) when necessary to fix this.
+ void MakeHetAtoms ( cpstr chainID, bool Make );
+
+ // --------------- Working with atoms by serial numbers ---
+
+ inline PPAtom GetAtomArray () { return atom; }
+ inline int GetAtomArrayLength() { return atmLen; } // strictly not for
+ // use in applications!!
+ PAtom GetAtomI ( int index ); // returns Atom[index-1]
+
+ // PutAtom(..) puts atom with the specified properties
+ // into the structure. The current model is used; if no model
+ // is set (crModel==NULL), one is created. Coordinates and
+ // other parameters of the atom need to be set separately.
+ // The place, at which the atom is put, is determined by
+ // index. If index is positive, then it points onto (index-1)th
+ // element of the Atom array (the index counts 1,2,... and
+ // generally coincides with the atom's serial number). If
+ // there is already an atom at this position in the system,
+ // the new atom will REPLACE it. The corresponding residues
+ // are automatically updated.
+ // If index is null (=0), the new atom will be put on
+ // the top of the structure, i.e. it will be put into
+ // (index=nAtoms+1)-th position.
+ // If index is negative, then the new atom is INSERTED
+ // BEFORE the atom in the (-index)th position. For saving
+ // the computational efforts, this WILL NOT cause the
+ // recalculation of all atoms' serial numbers according
+ // to their actual positions. It will be needed, however,
+ // for putting the things in order at a certain point,
+ // especially before writing an output ASCII file. NOTE
+ // that this ordering is never done automatically.
+ // In a correct PDB file the serial number (serNum) is always
+ // equal to its position (index). However here we allow them
+ // to be different for easing the management of relations,
+ // particularly the connectivity.
+ //
+ // Limitation: if PutAtom implies creating new
+ // chains/residues, these are always created on the top
+ // of existing chains/residues.
+ int PutAtom ( int index,
+ int serNum,
+ const AtomName atomName,
+ const ResName resName,
+ const ChainID chainID,
+ int seqNum,
+ const InsCode insCode,
+ const AltLoc altLoc,
+ const SegID segID,
+ const Element element );
+
+ int PutAtom (
+ int index, // same meaning as above
+ PAtom A, // pointer to completed atom class
+ int serNum=0 // 0 means that the serial number
+ // will be set equal to index.
+ // Otherwise the serial number
+ // is set to the specified
+ // value
+ );
+
+
+ // RemoveAtom(..) removes atom at the specified index
+ // in the Atom array. This index is always accessible
+ // as Atom[index]->index. If this leaves a residue empty,
+ // the residue is removed. If this leaves an empty chain,
+ // the chain is removed as well; the same happens to the
+ // model.
+ void RemoveAtom ( int index );
+
+ int FinishStructEdit();
+
+ void TrimModelTable();
+
+ // ---------------- Deleting models -----------------------
+
+ int DeleteAllModels ();
+ bool GetNewChainID ( int modelNo, ChainID chID, int length=1 );
+
+ // --------------- Enquiring -------------------------------
+
+ int CrystReady();
+ // Returns flags:
+ // CRRDY_Complete if crystallographic information is complete
+ // CRRDY_NotPrecise if cryst. inf-n is not precise
+ // CRRDY_isTranslation if cryst. inf-n contains translation
+ // CRRDY_NoOrthCode no orthogonalization code
+ // Fatal:
+ // CRRDY_NoTransfMatrices if transform. matrices were not
+ // calculated
+ // CRRDY_Unchecked if cryst. inf-n was not checked
+ // CRRDY_Ambiguous if cryst. inf-n is ambiguous
+ // CRRDY_NoCell if cryst. inf-n is unusable
+ // CRRDY_NoSpaceGroup if space group is not set
+
+
+ bool isCrystInfo (); // cell parameters and space group
+ bool isCellInfo (); // cell param-s a,b,c, alpha,beta,gamma
+ bool isSpaceGroup (); // space group on CRYST1 card
+ bool isTransfMatrix(); // orthogonalizing/fractionalizing
+ // matrices
+ bool isScaleMatrix (); // SCALEx PDB records
+ bool isNCSMatrix (); // MTRIXx PDB records
+ int GetNumberOfNCSMatrices();
+ int GetNumberOfNCSMates (); // Returns the number of
+ // NCS mates not given in
+ // the file (iGiven==0)
+ bool GetNCSMatrix ( int NCSMatrixNo, // 0..N-1
+ mat44 & ncs_m, int & iGiven );
+
+ int GetNumberOfSymOps (); // number of symmetry operations
+ pstr GetSymOp ( int Nop ); // XYZ symmetry operation name
+
+
+ // ------------- User-Defined Data ------------------------
+
+ int RegisterUDInteger ( UDR_TYPE udr_type, cpstr UDDataID );
+ int RegisterUDReal ( UDR_TYPE udr_type, cpstr UDDataID );
+ int RegisterUDString ( UDR_TYPE udr_type, cpstr UDDataID );
+ int GetUDDHandle ( UDR_TYPE udr_type, cpstr UDDataID );
+
+ // ----------------------------------------------------------
+
+ void SetSyminfoLib ( cpstr syminfo_lib );
+ pstr GetSyminfoLib ();
+ int SetSpaceGroup ( cpstr spGroup );
+ pstr GetSpaceGroup ();
+ pstr GetSpaceGroupFix();
+
+ void GetAtomStatistics ( RAtomStat AS );
+
+ void SetIgnoreSCALEi ( bool ignoreScalei );
+
+ // SetCell(..) is for changing cell parameters
+ void SetCell ( realtype cell_a,
+ realtype cell_b,
+ realtype cell_c,
+ realtype cell_alpha,
+ realtype cell_beta,
+ realtype cell_gamma,
+ int OrthCode=0 );
+
+ // PutCell(..) is for setting cell parameters
+ void PutCell ( realtype cell_a,
+ realtype cell_b,
+ realtype cell_c,
+ realtype cell_alpha,
+ realtype cell_beta,
+ realtype cell_gamma,
+ int OrthCode=0 );
+
+ int GetCell ( realtype & cell_a,
+ realtype & cell_b,
+ realtype & cell_c,
+ realtype & cell_alpha,
+ realtype & cell_beta,
+ realtype & cell_gamma,
+ realtype & vol,
+ int & OrthCode );
+
+ int GetRCell ( realtype & cell_as,
+ realtype & cell_bs,
+ realtype & cell_cs,
+ realtype & cell_alphas,
+ realtype & cell_betas,
+ realtype & cell_gammas,
+ realtype & vols,
+ int & OrthCode );
+
+ void GetROMatrix ( mat44 & RO );
+
+ // GetTMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts orthogonal coordinates
+ // according to the symmetry operation number Nop and places
+ // them into unit cell shifted by cellshift_a a's, cellshift_b
+ // b's and cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ int GetTMatrix ( mat44 & TMatrix, int Nop,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c );
+
+ // GetUCTMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts orthogonal coordinates
+ // according to the symmetry operation number Nop. Translation
+ // part of the matrix is being chosen such that point (x,y,z)
+ // has least distance to the center of primary (333) unit cell,
+ // and then it is shifted by cellshift_a a's, cellshift_b b's and
+ // cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ int GetUCTMatrix ( mat44 & TMatrix, int Nop,
+ realtype x, realtype y, realtype z,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c );
+
+ // GetFractMatrix(..) calculates and returns the coordinate
+ // transformation matrix, which converts fractional coordinates
+ // according to the symmetry operation number Nop and places them
+ // into unit cell shifted by cellshift_a a's, cellshift_b b's
+ // and cellshift_c c's.
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ int GetFractMatrix ( mat44 & TMatrix, int Nop,
+ int cellshift_a, int cellshift_b,
+ int cellshift_c );
+
+
+ // GetSymOpMatrix(..) returns the transformation matrix for
+ // Nop-th symmetry operator in the space group
+ //
+ // Return 0 means everything's fine,
+ // 1 there's no symmetry operation Nop defined
+ // 2 fractionalizing/orthogonalizing matrices were not
+ // calculated
+ // 3 cell parameters were not set up.
+ //
+ int GetSymOpMatrix ( mat44 & TMatrix, int Nop );
+
+
+ int AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v, int iGiven );
+ int GenerateNCSMates(); // 1: no NCS matrices, 0: Ok
+
+ pstr GetEntryID ();
+ void SetEntryID ( const IDCode idCode );
+
+ int GetNofExpDataRecs();
+ pstr GetExpDataRec ( int recNo ); // 0.. on
+
+ int GetNofMdlTypeRecs();
+ pstr GetMdlTypeRec ( int recNo ); // 0.. on
+
+ int GetFileType() { return FType; }
+
+ void Copy ( PRoot MMDBRoot );
+
+ void SetShortBinary(); // leaves only coordinates in binary files
+
+ // ------- user-defined data handlers
+ int PutUDData ( int UDDhandle, int iudd );
+ int PutUDData ( int UDDhandle, realtype rudd );
+ int PutUDData ( int UDDhandle, cpstr sudd );
+
+ int GetUDData ( int UDDhandle, int & iudd );
+ int GetUDData ( int UDDhandle, realtype & rudd );
+ int GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+ int GetUDData ( int UDDhandle, pstr & sudd );
+
+ // GetStructureTitle() returns the contents of TITLE record
+ // unfolded into single line. If Title is missing, returns
+ // contents of COMPND(:MOLECULE). If COMPND is missing, returns
+ // HEADER. If Header is missing, returns PDB code. If no PDB
+ // code is there, returns "Not available".
+ pstr GetStructureTitle ( pstr & L );
+
+ PCryst GetCrystData() { return &cryst; }
+
+ PClassContainer GetUnparsedA() { return &SA; }
+ PClassContainer GetUnparsedB() { return &SB; }
+ PClassContainer GetUnparsedC() { return &SC; }
+
+ protected :
+
+ word Flags; // special effect flags
+ int FType; // type of last file operation:
+ // -1 : none
+ // 0 : PDB
+ // 1 : CIF
+ // 2 : BIN
+ // encoded as MMDB_FILE_XXXXX above
+
+ Title title; // title section
+ Cryst cryst; // crystallographic information section
+ UDRegister udRegister; // register of user-defined data
+
+ int nModels; // number of models
+ PPModel model; // array of models [0..nModels-1]
+
+ int nAtoms; // number of atoms
+ int atmLen; // length of Atom array
+ PPAtom atom; // array of atoms ordered by serial numbers
+
+ AtomPath DefPath; // default coordinate path
+
+ ClassContainer SA; // string container for unrecognized strings
+ // which are between the title and the
+ // crystallographic sections
+ ClassContainer Footnote; // string container for footnotes
+ ClassContainer SB; // string container for unrecognized strings
+ // which are between the crystallographic and
+ // the coordinate sections
+ ClassContainer SC; // string container for unrecognized strings
+ // following the coordinate section
+
+ // input buffer
+ int lcount; // input line counter
+ char S[500]; // read buffer
+ mmcif::PData CIF; // CIF file manager
+
+ PModel crModel; // current model, used at reading a PDB file
+ PChain crChain; // current chain, used at reading a PDB file
+ PResidue crRes; // current residue, used at reading a PDB file
+
+ bool Exclude; // used internally
+ bool ignoreRemarks; // used temporarily
+ bool allowDuplChID; // used temporarily
+ bool enforceUniqueChID; // used temporarily
+
+ void InitMMDBRoot ();
+ void FreeCoordMemory ();
+ void ReadPDBLine ( io::RFile f, pstr L, int maxlen );
+ ERROR_CODE ReadPDBAtom ( cpstr L );
+ ERROR_CODE ReadCIFAtom ( mmcif::PData CIFD );
+ ERROR_CODE CheckAtomPlace ( int index, cpstr L );
+ ERROR_CODE CheckAtomPlace ( int index, mmcif::PLoop Loop );
+ ERROR_CODE SwitchModel ( cpstr L );
+ ERROR_CODE SwitchModel ( int nM );
+ ERROR_CODE AllocateAtom ( int index,
+ const ChainID chainID,
+ const ChainID label_asym_id,
+ const ResName resName,
+ const ResName label_comp_id,
+ int seqNum,
+ int label_seq_id,
+ int label_entity_id,
+ const InsCode insCode,
+ bool Replace );
+ void ExpandAtomArray ( int inc );
+ void AddAtomArray ( int inc );
+
+ void ApplyNCSTransform ( int NCSMatrixNo );
+
+ virtual void ResetManager();
+
+ // --------------- Stream I/O -----------------------------
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ // don't use _ExcludeModel in your applications!
+ int _ExcludeModel ( int serNum );
+
+ int CheckInAtom ( int index, PAtom A );
+ int CheckInAtoms ( int index, PPAtom A, int natms );
+
+ virtual PMask GetSelMask ( int selHnd );
+
+ private :
+ int modelCnt; // used only at reading files
+
+ };
+
+
+
+ // isMMDBBIN will return
+ // -1 if file FName does not exist
+ // 0 if file FName is likely a MMDB BIN (binary) file
+ // 1 if file FName is not a MMDB BIN (binary) file
+ // 2 if file FName is likely a MMDB BIN (binary) file,
+ // but of a wrong edition (i.e. produced by a lower
+ // version of MMDB).
+ extern int isMMDBBIN ( cpstr FName, io::GZ_MODE gzipMode=io::GZM_CHECK );
+ extern int isMMDBBIN ( io::RFile f );
+
+ // isPDB will return
+ // -1 if file FName does not exist
+ // 0 if file FName is likely a PDB file
+ // 1 if file FName is not a PDB file
+ extern int isPDB ( cpstr FName, io::GZ_MODE gzipMode=io::GZM_CHECK,
+ bool IgnoreBlankLines=false );
+ extern int isPDB ( io::RFile f, bool IgnoreBlankLines=false );
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_rwbrook.cpp b/mmdb2/mmdb_rwbrook.cpp
new file mode 100644
index 0000000..5bc056c
--- /dev/null
+++ b/mmdb2/mmdb_rwbrook.cpp
@@ -0,0 +1,3082 @@
+// $Id: mmdb_rwbrook.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 16.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_RWBrook <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB), "new rwbrook"
+// ~~~~~~~~~
+// **** Functions : mmdb_f_init_ ( initializer )
+// ~~~~~~~~~~~ mmdb_f_quit_ ( disposer )
+// autoserials_ ( switch to the autoserials regime )
+// setreadcoords_ ( switch for reading coordinates )
+// simrwbrook_ ( simulates old RWBROOK printout )
+// mmdb_f_openl_ ( associates a unit with a file )
+// mmdb_f_open_ ( associates a unit with a file )
+// mmdb_f_copy_ ( copies contents of units )
+// mmdb_f_delete_ ( deletes part of a unit )
+// mmdb_f_settype_ ( changes type of file and r/w mode )
+// mmdb_f_setname_ ( changes file name )
+// mmdb_f_write_ ( writes a data structure into file )
+// mmdb_f_close_ ( closes and disposes a data str-re )
+// mmdb_f_advance_ ( advances the internal pointer )
+// mmdb_f_rewd_ ( sets internal pointer on the top )
+// mmdb_f_bksp_ ( shifts int-l pointer 1 atom back )
+// mmdb_f_atom_ ( reads/writes atom properties )
+// mmdb_f_coord_ ( reads/writes atom coordinates )
+// mmdb_f_setcell_ ( sets the crystal cell parameters )
+// mmdb_f_wbspgrp_ ( sets the space group )
+// mmdb_f_rbspgrp_ ( gets the space group )
+// mmdb_f_wbcell_ ( sets the crystal cell parameters )
+// mmdb_f_rbcell_ ( gets the crystal cell parameters )
+// mmdb_f_rbcelln_ ( gets the crystal cell parameters )
+// mmdb_f_rbrcel_ ( gets the recipricol cell )
+// mmdb_f_rborf_ ( returns or fill transf. matrices )
+// mmdb_f_orthmat_ ( calc. standard othogonalisations )
+// mmdb_f_cvanisou_ ( converts between cryst-c units )
+// mmdb_f_wremark_ ( writes a remark statement )
+// mmdb_f_setter
+// mmdb_f_sethet
+// rberrstop_ ( error messenger )
+// rbcheckerr_ ( a simple error messenger )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include "string.h"
+#include "stdlib.h"
+#include "math.h"
+
+#include "mmdb_rwbrook.h"
+#include "mmdb_manager.h"
+#include "mmdb_tables.h"
+#include "hybrid_36.h"
+
+// ========================== Channel ===========================
+
+DefineClass(Channel)
+
+class Channel {
+
+ public :
+
+ int nUnit; // unit number
+ int nType; // unit type: 0- PDB; 1- CIF; 2- binary
+ int nRead; // 0: input, 1: output
+ mmdb::PManager MMDBManager; // MMDB manager
+ mmdb::pstr FName; // file name
+ int fPos; // "position" in the file
+ int ErrCode; // error code of last operation
+ bool FAutoSer; // autoserials flag for reading PDB
+ bool FReadCoords; // flag to read coordinate section
+ bool FSimRWBROOK; // flag to simulate old RWBROOK's printout
+
+ Channel ();
+ ~Channel();
+
+ void Dispose();
+ void Init ();
+
+ void SetFileType ( mmdb::pstr FType );
+ void SetFileName ( mmdb::pstr FileName, int FNameLen );
+ void IdentifyFile( mmdb::pstr ExistingFName );
+
+ bool EndOfFile ();
+ mmdb::PAtom * GetAtomArray();
+ mmdb::PAtom GetAtomI ( int index );
+
+ mmdb::PCryst GetCryst ();
+
+ bool areCrystMatrices();
+ void Frac2Orth (
+ mmdb::realtype x, mmdb::realtype y, mmdb::realtype z,
+ mmdb::realtype & xx, mmdb::realtype & yy, mmdb::realtype & zz );
+ void Orth2Frac (
+ mmdb::realtype x, mmdb::realtype y, mmdb::realtype z,
+ mmdb::realtype & xx, mmdb::realtype & yy, mmdb::realtype & zz );
+ void Cryst2Orth ( mmdb::rvector U );
+ void Orth2Cryst ( mmdb::rvector U );
+ int SetCell ( mmdb::realtype cell_a,
+ mmdb::realtype cell_b,
+ mmdb::realtype cell_c,
+ mmdb::realtype cell_alpha,
+ mmdb::realtype cell_beta,
+ mmdb::realtype cell_gamma,
+ int OrthCode );
+ int PutCell ( mmdb::realtype cell_a,
+ mmdb::realtype cell_b,
+ mmdb::realtype cell_c,
+ mmdb::realtype cell_alpha,
+ mmdb::realtype cell_beta,
+ mmdb::realtype cell_gamma,
+ int OrthCode );
+ int SetSpGroup ( mmdb::pstr spGroup );
+ int GetSpGroup ( mmdb::pstr spGroup );
+ int GetCell ( mmdb::realtype & cell_a,
+ mmdb::realtype & cell_b,
+ mmdb::realtype & cell_c,
+ mmdb::realtype & cell_alpha,
+ mmdb::realtype & cell_beta,
+ mmdb::realtype & cell_gamma,
+ mmdb::realtype & cell_v,
+ int & OrthCode );
+ int GetRCell ( mmdb::realtype & cell_as,
+ mmdb::realtype & cell_bs,
+ mmdb::realtype & cell_cs,
+ mmdb::realtype & cell_alphas,
+ mmdb::realtype & cell_betas,
+ mmdb::realtype & cell_gammas,
+ mmdb::realtype & cell_vs );
+
+ void MakeCoordStructure();
+ void Read ();
+ void Write();
+
+ void GetInputBuffer ( mmdb::pstr Line, int & count );
+
+ protected :
+
+ void TranslateError();
+
+};
+
+Channel::Channel() {
+ Init();
+}
+
+Channel::~Channel() {
+ Dispose();
+}
+
+void Channel::Init() {
+ nUnit = -1;
+ nType = -1;
+ nRead = 0;
+ MMDBManager = NULL;
+ FName = NULL;
+ ErrCode = 0;
+ fPos = 0;
+ FAutoSer = false;
+ FReadCoords = true;
+ FSimRWBROOK = false;
+}
+
+void Channel::Dispose() {
+ if (MMDBManager) delete MMDBManager;
+ if (FName) delete[] FName;
+ MMDBManager = NULL;
+ FName = NULL;
+ nUnit = -1;
+ nType = -1;
+ nRead = 0;
+ ErrCode = 0;
+ fPos = 0;
+}
+
+
+void Channel::SetFileType ( mmdb::pstr FType ) {
+ switch (FType[0]) {
+ default :
+ case ' ' : if (nRead==0)
+ nType = -1; // auto at reading
+ else if (MMDBManager)
+ nType = MMDBManager->GetFileType(); // auto at writing
+ else nType = -1;
+ break;
+ case 'P' : nType = 0; break; // PDB
+ case 'C' : nType = 1; break; // CIF
+ case 'B' : nType = 2; break; // BIN
+ }
+}
+
+void Channel::IdentifyFile ( mmdb::pstr ExistingFName ) {
+ if (nType==-1) {
+ if (ExistingFName) {
+ if (mmdb::isMMDBBIN(ExistingFName)==0) nType = 2;
+ else if (mmdb::isPDB(ExistingFName,mmdb::io::GZM_CHECK,true)==0)
+ nType = 0;
+ else if (mmdb::mmcif::isCIF(ExistingFName)==0) nType = 1;
+ else nType = -2; // unidentified
+ } else {
+ if (MMDBManager) {
+ if (MMDBManager->GetFileType()<0)
+ nType = 0; // PDB
+ else nType = MMDBManager->GetFileType(); // same as it was on last input
+ } else nType = 0;
+ }
+ }
+}
+
+void Channel::SetFileName ( mmdb::pstr FileName, int FNameLen ) {
+ if (FName) delete[] FName;
+ FName = new char[FNameLen+1];
+ strncpy ( FName,FileName,FNameLen );
+ FName[FNameLen] = char(0);
+}
+
+void Channel::MakeCoordStructure() {
+ if (MMDBManager)
+ MMDBManager->Delete ( mmdb::MMDBFCM_All );
+ else {
+ MMDBManager = new mmdb::Manager();
+ MMDBManager->SetFlag ( mmdb::MMDBF_AllowDuplChainID );
+ }
+}
+
+void Channel::Read() {
+int RC;
+
+ ErrCode = -2;
+ if (!FName) return;
+
+ MakeCoordStructure();
+
+ IdentifyFile ( FName );
+
+ if (FAutoSer) MMDBManager->SetFlag ( mmdb::MMDBF_AutoSerials );
+ else MMDBManager->RemoveFlag ( mmdb::MMDBF_AutoSerials );
+ if (FReadCoords) MMDBManager->RemoveFlag ( mmdb::MMDBF_NoCoordRead );
+ else MMDBManager->SetFlag ( mmdb::MMDBF_NoCoordRead );
+ if (FSimRWBROOK) MMDBManager->SetFlag ( mmdb::MMDBF_SimRWBROOK );
+ else MMDBManager->RemoveFlag ( mmdb::MMDBF_SimRWBROOK );
+
+ MMDBManager->SetFlag ( mmdb::MMDBF_IgnoreDuplSeqNum |
+ mmdb::MMDBF_IgnoreBlankLines |
+ mmdb::MMDBF_IgnoreRemarks |
+ mmdb::MMDBF_IgnoreNonCoorPDBErrors |
+ mmdb::MMDBF_AllowDuplChainID );
+
+ switch (nType) {
+ default : nType = 0; // nType=-2: unidentified: try PDB
+ case 0 : ErrCode = MMDBManager->ReadPDBASCII ( FName ); break;
+ case 1 : ErrCode = MMDBManager->ReadCIFASCII ( FName ); break;
+ case 2 : ErrCode = MMDBManager->ReadMMDBF ( FName ); break;
+ }
+ if (ErrCode==0) {
+ RC = MMDBManager->CrystReady();
+ switch (RC) {
+ case mmdb::CRRDY_NoTransfMatrices : ErrCode = RWBERR_NoMatrices; break;
+ case mmdb::CRRDY_Unchecked : ErrCode = RWBERR_NoCheck; break;
+ case mmdb::CRRDY_Ambiguous : ErrCode = RWBERR_Disagreement; break;
+ case mmdb::CRRDY_NoCell : ErrCode = RWBERR_NoCellParams; break;
+ default : ;
+ }
+ }
+ fPos = 0; // begining of the file
+ TranslateError();
+}
+
+void Channel::Write() {
+ ErrCode = -3;
+ if ((!MMDBManager) || (!FName)) return;
+ IdentifyFile ( FName );
+ switch (nType) {
+ default : nType = 0; // nType=-2: unidentified: make PDB
+ case 0 : ErrCode = MMDBManager->WritePDBASCII ( FName ); break;
+ case 1 : ErrCode = MMDBManager->WriteCIFASCII ( FName ); break;
+ case 2 : ErrCode = MMDBManager->WriteMMDBF ( FName ); break;
+ }
+ // we do not change fPos here!
+ TranslateError();
+}
+
+void Channel::TranslateError() {
+
+ switch (ErrCode) {
+
+ case mmdb::Error_CantOpenFile : ErrCode = RWBERR_CantOpenFile; break;
+ case mmdb::Error_UnrecognizedInteger : ErrCode = RWBERR_WrongInteger; break;
+ case mmdb::Error_NoData : ErrCode = RWBERR_NotACIFFile; break;
+ case mmdb::Error_WrongModelNo : ErrCode = RWBERR_WrongModelNo; break;
+ case mmdb::Error_DuplicatedModel : ErrCode = RWBERR_DuplicatedModel; break;
+ case mmdb::Error_ForeignFile : ErrCode = RWBERR_ForeignFile; break;
+ case mmdb::Error_WrongEdition : ErrCode = RWBERR_WrongEdition; break;
+ case mmdb::Error_ATOM_Unrecognized : ErrCode = RWBERR_ATOM_Unrecognd; break;
+ case mmdb::Error_ATOM_AlreadySet : ErrCode = RWBERR_ATOM_AlreadySet; break;
+ case mmdb::Error_ATOM_NoResidue : ErrCode = RWBERR_ATOM_NoResidue; break;
+ case mmdb::Error_ATOM_Unmatch : ErrCode = RWBERR_ATOM_Unmatch; break;
+ case mmdb::Error_NotACIFFile : ErrCode = RWBERR_NotACIFFile; break;
+ case mmdb::Error_UnrecognCIFItems : ErrCode = RWBERR_UnrecognCIFItems; break;
+ case mmdb::Error_MissingCIFField : ErrCode = RWBERR_MissingCIFField; break;
+ case mmdb::Error_EmptyCIFLoop : ErrCode = RWBERR_EmptyCIFLoop; break;
+ case mmdb::Error_UnexpEndOfCIF : ErrCode = RWBERR_UnexpEndOfCIF; break;
+ case mmdb::Error_MissgCIFLoopField : ErrCode = RWBERR_MissgCIFLoopField; break;
+ case mmdb::Error_NotACIFStructure : ErrCode = RWBERR_NotACIFStructure; break;
+ case mmdb::Error_NotACIFLoop : ErrCode = RWBERR_NotACIFLoop; break;
+ case mmdb::Error_UnrecognizedReal : ErrCode = RWBERR_WrongReal; break;
+
+ case mmdb::Error_Ok : ErrCode = RWBERR_Ok; break;
+ case mmdb::Error_WrongChainID : ErrCode = RWBERR_WrongChainID; break;
+ case mmdb::Error_WrongEntryID : ErrCode = RWBERR_WrongEntryID; break;
+ case mmdb::Error_SEQRES_serNum : ErrCode = RWBERR_SEQRES_serNum; break;
+ case mmdb::Error_SEQRES_numRes : ErrCode = RWBERR_SEQRES_numRes; break;
+ case mmdb::Error_SEQRES_extraRes : ErrCode = RWBERR_SEQRES_exraRes; break;
+ case mmdb::Error_NCSM_Unrecognized : ErrCode = RWBERR_NCSM_Unrecogn; break;
+ case mmdb::Error_NCSM_AlreadySet : ErrCode = RWBERR_NCSM_AlreadySet; break;
+ case mmdb::Error_NCSM_WrongSerial : ErrCode = RWBERR_NCSM_WrongSerial; break;
+ case mmdb::Error_NCSM_UnmatchIG : ErrCode = RWBERR_NCSM_UnmatchIG; break;
+ case mmdb::Error_NoModel : ErrCode = RWBERR_NoModel; break;
+ case mmdb::Error_NoSheetID : ErrCode = RWBERR_NoSheetID; break;
+ case mmdb::Error_WrongSheetID : ErrCode = RWBERR_WrongSheetID; break;
+ case mmdb::Error_WrongStrandNo : ErrCode = RWBERR_WrongStrandNo; break;
+ case mmdb::Error_WrongNumberOfStrands : ErrCode = RWBERR_WrongNofStrands; break;
+ case mmdb::Error_WrongSheetOrder : ErrCode = RWBERR_WrongSheetOrder; break;
+ case mmdb::Error_HBondInconsistency : ErrCode = RWBERR_HBondInconsis; break;
+ case mmdb::Error_EmptyResidueName : ErrCode = RWBERR_EmptyResidueName; break;
+ case mmdb::Error_DuplicateSeqNum : ErrCode = RWBERR_DuplicateSeqNum; break;
+ case mmdb::Error_NoLogicalName : ErrCode = RWBERR_NoLogicalName; break;
+ case mmdb::Error_GeneralError1 : ErrCode = RWBERR_GeneralError1; break;
+
+ default : ;
+ }
+
+
+}
+
+bool Channel::EndOfFile() {
+int nA;
+ if (MMDBManager) {
+ nA = MMDBManager->GetNumberOfAtoms();
+ if (fPos>nA) {
+ fPos = nA+1;
+ return true;
+ }
+ } else
+ return true;
+ return false;
+}
+
+mmdb::PAtom * Channel::GetAtomArray() {
+ if (MMDBManager) return MMDBManager->GetAtomArray();
+ else return NULL;
+}
+
+mmdb::PAtom Channel::GetAtomI ( int index ) {
+// returns index-th atom, as counted from the
+// top of file
+ if (MMDBManager) return MMDBManager->GetAtomI ( index );
+ else return NULL;
+}
+
+mmdb::PCryst Channel::GetCryst() {
+ if (MMDBManager) return MMDBManager->GetCrystData();
+ else return NULL;
+}
+
+bool Channel::areCrystMatrices() {
+ if (MMDBManager) return MMDBManager->isTransfMatrix();
+ else return false;
+}
+
+void Channel::Frac2Orth (
+ mmdb::realtype x, mmdb::realtype y, mmdb::realtype z,
+ mmdb::realtype & xx, mmdb::realtype & yy, mmdb::realtype & zz ) {
+ if (MMDBManager)
+ MMDBManager->Frac2Orth ( x,y,z,xx,yy,zz );
+ else {
+ xx = x;
+ yy = y;
+ zz = z;
+ }
+}
+
+void Channel::Orth2Frac (
+ mmdb::realtype x, mmdb::realtype y, mmdb::realtype z,
+ mmdb::realtype & xx, mmdb::realtype & yy, mmdb::realtype & zz ) {
+ if (MMDBManager)
+ MMDBManager->Orth2Frac ( x,y,z,xx,yy,zz );
+ else {
+ xx = x;
+ yy = y;
+ zz = z;
+ }
+}
+
+void Channel::Cryst2Orth ( mmdb::rvector U ) {
+ if (MMDBManager)
+ MMDBManager->GetCrystData()->Cryst2Orth ( U );
+}
+
+void Channel::Orth2Cryst ( mmdb::rvector U ) {
+ if (MMDBManager)
+ MMDBManager->GetCrystData()->Orth2Cryst ( U );
+}
+
+
+int Channel::PutCell ( mmdb::realtype cell_a,
+ mmdb::realtype cell_b,
+ mmdb::realtype cell_c,
+ mmdb::realtype cell_alpha,
+ mmdb::realtype cell_beta,
+ mmdb::realtype cell_gamma,
+ int OrthCode ) {
+
+ if (MMDBManager) {
+ mmdb::PCryst cryst = MMDBManager->GetCrystData();
+
+ cryst->PutCell ( cell_a,cell_b,cell_c,
+ cell_alpha,cell_beta,cell_gamma,
+ OrthCode );
+
+ if ((cell_a!=0.0) || (OrthCode>0)) {
+ if (cryst->CellCheck & mmdb::CCHK_Disagreement)
+ return RWBERR_Disagreement;
+ if (cryst->CellCheck & mmdb::CCHK_NoOrthCode)
+ return RWBERR_NoOrthCode;
+ if (cryst->CellCheck & mmdb::CCHK_Unchecked)
+ return RWBERR_NoCheck;
+ }
+
+ return RWBERR_Ok;
+
+ } else
+
+ return RWBERR_NoFile;
+
+}
+
+
+int Channel::SetCell ( mmdb::realtype cell_a,
+ mmdb::realtype cell_b,
+ mmdb::realtype cell_c,
+ mmdb::realtype cell_alpha,
+ mmdb::realtype cell_beta,
+ mmdb::realtype cell_gamma,
+ int OrthCode ) {
+
+ if (MMDBManager) {
+ mmdb::PCryst cryst = MMDBManager->GetCrystData();
+
+ cryst->SetCell ( cell_a,cell_b,cell_c,
+ cell_alpha,cell_beta,cell_gamma,
+ OrthCode );
+
+ if (cryst->CellCheck & mmdb::CCHK_Disagreement)
+ return RWBERR_Disagreement;
+ if (cryst->CellCheck & mmdb::CCHK_NoOrthCode)
+ return RWBERR_NoOrthCode;
+ if (cryst->CellCheck & mmdb::CCHK_Unchecked)
+ return RWBERR_NoCheck;
+
+ return RWBERR_Ok;
+
+ } else
+
+ return RWBERR_NoFile;
+
+}
+
+
+int Channel::SetSpGroup ( mmdb::pstr spGroup ) {
+ if (MMDBManager) {
+ MMDBManager->SetSpaceGroup(spGroup);
+ return RWBERR_Ok;
+ } else
+ return RWBERR_NoFile;
+}
+
+
+int Channel::GetSpGroup ( mmdb::pstr spGroup ) {
+ if (MMDBManager) {
+ mmdb::PCryst cryst = MMDBManager->GetCrystData();
+ if (cryst->WhatIsSet & mmdb::CSET_SpaceGroup)
+ strcpy ( spGroup,cryst->spaceGroup );
+ else strcpy ( spGroup," " );
+ return RWBERR_Ok;
+ } else
+ return RWBERR_NoFile;
+}
+
+
+int Channel::GetCell ( mmdb::realtype & cell_a,
+ mmdb::realtype & cell_b,
+ mmdb::realtype & cell_c,
+ mmdb::realtype & cell_alpha,
+ mmdb::realtype & cell_beta,
+ mmdb::realtype & cell_gamma,
+ mmdb::realtype & cell_v,
+ int & OrthCode ) {
+
+ if (MMDBManager) {
+ mmdb::PCryst cryst = MMDBManager->GetCrystData();
+ cell_a = cryst->a;
+ cell_b = cryst->b;
+ cell_c = cryst->c;
+ cell_alpha = cryst->alpha;
+ cell_beta = cryst->beta;
+ cell_gamma = cryst->gamma;
+ cell_v = cryst->Vol;
+ OrthCode = cryst->NCode;
+ if (!(cryst->WhatIsSet & mmdb::CSET_CellParams))
+ return RWBERR_NoCellParams;
+ if (!(cryst->WhatIsSet & mmdb::CSET_Transforms))
+ return RWBERR_NoCheck;
+// if (MMDBManager->Cryst.CellCheck & mmdb::CCHK_NoOrthCode)
+// return RWBERR_NoOrthCode;
+
+ return RWBERR_Ok;
+
+ } else
+
+ return RWBERR_NoFile;
+
+}
+
+int Channel::GetRCell ( mmdb::realtype & cell_as,
+ mmdb::realtype & cell_bs,
+ mmdb::realtype & cell_cs,
+ mmdb::realtype & cell_alphas,
+ mmdb::realtype & cell_betas,
+ mmdb::realtype & cell_gammas,
+ mmdb::realtype & cell_vs ) {
+ if (MMDBManager) {
+ mmdb::PCryst cryst = MMDBManager->GetCrystData();
+ cryst->GetRCell ( cell_as,cell_bs,cell_cs,
+ cell_alphas,cell_betas,cell_gammas,
+ cell_vs );
+ if (!(cryst->WhatIsSet & mmdb::CSET_CellParams))
+ return RWBERR_NoCellParams;
+ if (!(cryst->WhatIsSet & mmdb::CSET_Transforms))
+ return RWBERR_NoCheck;
+ return RWBERR_Ok;
+ } else
+ return RWBERR_NoFile;
+}
+
+void Channel::GetInputBuffer ( mmdb::pstr Line, int & count ) {
+ if (MMDBManager)
+ MMDBManager->GetInputBuffer ( Line,count );
+ else {
+ strcpy ( Line,"" );
+ count = -1;
+ }
+}
+
+
+
+// ======================== static data ===========================
+
+static int nChannels; // number of channels in processing
+static PChannel * channel; // array of channels in processing
+
+static bool FAutoSer; // flag to automatically generate
+ // serial numbers at reading PDB files
+static bool FReadCoords; // flag to read coordinates; if set to
+ // false, only the header of PDB file
+ // is read
+static bool FSimRWBROOK; // flag to simulate old RWBROOK printout
+ // as closely as possible
+
+static char LastFunc[80]; // name of the last called function
+static int LastUnit; // number of the last unit called
+static int LastRC; // last return code
+static int LastSer; // last serial number kept for
+ // certain warnings
+
+
+// ======================== RWBrook API ===========================
+
+
+FORTRAN_SUBR ( MMDB_F_INIT, mmdb_f_init,(),(),() ) {
+ mmdb::InitMatType();
+ nChannels = 0;
+ channel = NULL;
+ strcpy ( LastFunc,"MMDB_F_Init" );
+ LastUnit = -1;
+ LastRC = 0;
+ LastSer = 0;
+ FAutoSer = false;
+ FReadCoords = true;
+ FSimRWBROOK = false;
+}
+
+
+FORTRAN_SUBR ( MMDB_F_QUIT, mmdb_f_quit,(),(),() ) {
+int i;
+ for (i=0;i<nChannels;i++)
+ if (channel[i]) delete channel[i];
+ if (channel) delete[] channel;
+ channel = NULL;
+ nChannels = 0;
+ strcpy ( LastFunc,"MMDB_F_Quit" );
+ LastUnit = -1;
+ LastRC = 0;
+ LastSer = 0;
+ FAutoSer = false;
+}
+
+
+FORTRAN_SUBR ( AUTOSERIALS, autoserials,
+ ( int * iOnOff ),
+ ( int * iOnOff ),
+ ( int * iOnOff ) ) {
+ FAutoSer = (*iOnOff!=0);
+}
+
+
+FORTRAN_SUBR ( SETREADCOORDS,setreadcoords,
+ ( int * iOnOff ),
+ ( int * iOnOff ),
+ ( int * iOnOff ) ) {
+ FReadCoords = (*iOnOff!=0);
+}
+
+
+FORTRAN_SUBR ( SIMRWBROOK,simrwbrook,
+ ( int * iOnOff ),
+ ( int * iOnOff ),
+ ( int * iOnOff ) ) {
+ FSimRWBROOK = (*iOnOff!=0);
+}
+
+
+int GetChannel ( int iUnit ) {
+// Returns serial number of the channle associated with
+// unit iUnit.
+// If the channel is not found, returns -1
+int i;
+ for (i=0;i<nChannels;i++)
+ if (channel[i]) {
+ if (channel[i]->nUnit==iUnit)
+ return i;
+ }
+ return -1;
+}
+
+
+int MakeChannel ( int iUnit ) {
+// If iUnit-th unit already exists, it is
+// reinitialized. Otherwise the function looks
+// for a not used channel, and if there is one,
+// associates the new iUnit-th unit with it.
+// If there is no unused channels, the new one
+// is created and the new iUnit-th unit is
+// associated with it.
+// Returns serial number of the channel
+// associated with the newly reinitialized
+// or created unit.
+int i,m;
+PChannel * channel1;
+
+ m = GetChannel ( iUnit );
+
+ if (m>=0) { // such channel already exists
+ channel[m]->Dispose(); // clear it first
+ channel[m]->Init(); // reinitialize it
+ channel[m]->nUnit = iUnit;
+ return m;
+ }
+
+ for (i=0;i<nChannels;i++) // look for free channel
+ if (!channel[i]) {
+ m = i; // found!
+ break;
+ }
+
+ if (m<0) { // no free channel
+ // create new channel place
+ channel1 = new PChannel[nChannels+1];
+ for (i=0;i<nChannels;i++)
+ channel1[i] = channel[i];
+ if (channel) delete[] channel;
+ channel = channel1;
+ m = nChannels;
+ nChannels++; // increase number of channels
+ }
+
+ channel[m] = new Channel(); // create new channel
+ channel[m]->nUnit = iUnit;
+
+ return m;
+
+}
+
+FORTRAN_SUBR ( MMDB_F_OPEN, mmdb_f_open,
+ ( // lengths-at-end list
+ mmdb::machine::fpstr FName, // file name
+ mmdb::machine::fpstr RWStat, // "INPUT" or "OUTPUT"
+ mmdb::machine::fpstr FType, // "PDB", "CIF", "BIN" or " "
+ int * iUnit, // channel number
+ int * iRet, // returns error code
+ int FName_len, // fortran-hidden length of FName
+ int RWStat_len, // fortran-hidden length of RWStat
+ int FType_len // fortran-hidden length of FType
+ ), ( // lengths-in-structure list
+ mmdb::machine::fpstr FName, mmdb::machine::fpstr RWStat, mmdb::machine::fpstr FType,
+ int * iUnit, int * iRet
+ ), ( // lengths-follow list
+ mmdb::machine::fpstr FName, int FName_len,
+ mmdb::machine::fpstr RWStat, int RWStat_len,
+ mmdb::machine::fpstr FType, int FType_len,
+ int * iUnit, int * iRet
+ ) ) {
+
+UNUSED_ARGUMENT(RWStat_len);
+UNUSED_ARGUMENT(FType_len);
+
+int k;
+char L[500];
+
+#ifdef WIN32
+ mmdb::GetStrTerWin32File ( L,FTN_STR(FName),0,sizeof(L),FTN_LEN(FName) );
+#else
+ mmdb::GetStrTer ( L,FTN_STR(FName),0,sizeof(L),FTN_LEN(FName) );
+#endif
+
+ strcpy ( LastFunc,"MMDB_F_Open" );
+ LastUnit = *iUnit;
+
+ if (*iUnit==0) { // generate unit number
+ *iUnit = 1;
+ do {
+ k = GetChannel ( *iUnit );
+ if (k>=0) *iUnit = *iUnit+1;
+ } while (k>=0);
+ }
+
+ // create channel
+ k = MakeChannel ( *iUnit );
+
+ if (k>=0) {
+
+ if (FTN_STR(RWStat)[0]=='I') {
+ channel[k]->nRead = 0;
+ channel[k]->FAutoSer = FAutoSer;
+ channel[k]->FReadCoords = FReadCoords;
+ channel[k]->FSimRWBROOK = FSimRWBROOK;
+ } else
+ channel[k]->nRead = 1;
+
+ // store file name
+ channel[k]->SetFileName ( L,sizeof(L) );
+
+ // store unit type
+ channel[k]->SetFileType ( FTN_STR(FType) );
+ channel[k]->IdentifyFile( L );
+
+ if (FSimRWBROOK) {
+ switch (channel[k]->nType) {
+ default : printf ( " unknown-format" ); break;
+ case 0 : printf ( " PDB" ); break;
+ case 1 : printf ( " mmCIF" ); break;
+ case 2 : printf ( " MMDB BINARY" );
+ }
+ printf ( " file is being opened on unit %i",*iUnit );
+ if (FTN_STR(RWStat)[0]=='I') printf ( " for INPUT.\n\n" );
+ else printf ( " for OUTPUT.\n\n" );
+ }
+
+ if (FTN_STR(RWStat)[0]=='I') {
+ channel[k]->Read();
+ *iRet = channel[k]->ErrCode;
+ } else {
+ channel[k]->MakeCoordStructure();
+ channel[k]->fPos = 1;
+ *iRet = RWBERR_Ok;
+ }
+
+ } else
+ *iRet = RWBERR_NoChannel;
+
+ LastRC = *iRet;
+
+}
+
+FORTRAN_SUBR ( MMDB_F_OPENL, mmdb_f_openl,
+ ( // lengths-at-end list
+ mmdb::machine::fpstr LName, // logical name
+ mmdb::machine::fpstr RWStat, // "INPUT" or "OUTPUT"
+ mmdb::machine::fpstr FType, // "PDB", "CIF", "BIN" or " "
+ int * iUnit, // channel number
+ int * iRet, // returns error code
+ int LName_len, // fortran-hidden length of LName
+ int RWStat_len, // fortran-hidden length of RWStat
+ int FType_len // fortran-hidden length of FType
+ ), ( // lengths-in-structure list
+ mmdb::machine::fpstr LName, mmdb::machine::fpstr RWStat, mmdb::machine::fpstr FType,
+ int * iUnit, int * iRet
+ ), ( // lengths-follow list
+ mmdb::machine::fpstr LName, int LName_len,
+ mmdb::machine::fpstr RWStat, int RWStat_len,
+ mmdb::machine::fpstr FType, int FType_len,
+ int * iUnit, int * iRet
+ ) ) {
+char L[200];
+mmdb::pstr S;
+char_struct(FName)
+
+ strcpy ( LastFunc,"MMDB_F_Openl" );
+
+ mmdb::GetStrTer ( L,FTN_STR(LName),0,sizeof(L),FTN_LEN(LName) );
+
+ S = getenv ( L );
+
+ if (S) {
+
+ fill_char_struct(FName,S)
+
+ } else if (FTN_STR(RWStat)[0]=='O') {
+
+ // The user may not have assigned a logical
+ // for output, so that the program should write file "XYZOUT". This
+ // is allowed as a convenience when user is not really interested
+ // in output file.
+ fill_char_struct(FName,L)
+
+ } else {
+ *iRet = RWBERR_NoLogicalName;
+ return;
+ }
+
+ printf ( "\n Logical name: %s File name: %s\n",L,FName );
+
+ FORTRAN_CALL ( MMDB_F_OPEN, mmdb_f_open,
+ ( FName,RWStat,FType,iUnit,iRet,
+ FName_len,RWStat_len,FType_len ),
+ ( &FName,RWStat,FType,iUnit,iRet ),
+ ( FName,FName_len,RWStat,RWStat_len,
+ FType,FType_len,iUnit,iRet ) );
+
+}
+
+FORTRAN_SUBR ( MMDB_F_COPY, mmdb_f_copy,
+ ( // lengths-at-end list
+ int * iUnit1, // destination unit
+ int * iUnit2, // source unit
+ int * copyKey, // copy key:
+ // = 1 copy all
+ // = 2 copy all except coordinates
+ // = 3 copy title section only
+ // = 4 copy crystallographic
+ // section only
+ // = 5 copy coordinate section only
+ // any other value does not do anything
+ int * iRet // return code:
+ // =0 if success
+ // =RWBERR_NoChannel if a unit
+ // does not exist
+ ), ( // lengths-in-structure list
+ int * iUnit1, int * iUnit2,
+ int * copyKey, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit1, int * iUnit2,
+ int * copyKey, int * iRet
+ ) ) {
+int k1,k2;
+mmdb::COPY_MASK copyMask;
+
+ strcpy ( LastFunc,"MMDB_F_Copy" );
+
+ LastUnit = *iUnit1;
+ k1 = GetChannel ( LastUnit );
+
+ if (k1>=0) {
+ if (channel[k1]->MMDBManager) {
+ LastUnit = *iUnit2;
+ k2 = GetChannel ( LastUnit );
+ if (k2>=0) {
+ if (channel[k2]->MMDBManager) {
+ switch (*copyKey) {
+ case 1 : copyMask = mmdb::MMDBFCM_All; break;
+ case 2 : copyMask = mmdb::MMDBFCM_Top; break;
+ case 3 : copyMask = mmdb::MMDBFCM_Title; break;
+ case 4 : copyMask = mmdb::MMDBFCM_Cryst; break;
+ case 5 : copyMask = mmdb::MMDBFCM_Coord; break;
+ default : copyMask = mmdb::MMDBFCM_None;
+ }
+ channel[k1]->MMDBManager->Copy ( channel[k2]->MMDBManager,
+ copyMask );
+ *iRet = RWBERR_Ok;
+ } else
+ *iRet = RWBERR_NoFile;
+ } else
+ *iRet = RWBERR_NoChannel;
+ } else
+ *iRet = RWBERR_NoFile;
+ } else
+ *iRet = RWBERR_NoChannel;
+
+ LastRC = *iRet;
+
+}
+
+
+FORTRAN_SUBR ( MMDB_F_DELETE, mmdb_f_delete,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ int * delKey, // delete key:
+ // = 1 delete all
+ // = 2 delete all except coordinates
+ // = 3 delete title section only
+ // = 4 delete crystallographic
+ // section only
+ // = 5 delete coordinate section only
+ // any other value does not do anything
+ int * iRet // return code:
+ // =0 if success
+ // =RWBERR_NoChannel if a unit
+ // does not exist
+ // =RWBERR_NoFile if a unit
+ // was not opened
+ ), ( // lengths-in-structure list
+ int * iUnit, int * delKey, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, int * delKey, int * iRet
+ ) ) {
+int k;
+mmdb::word delMask;
+
+ strcpy ( LastFunc,"MMDB_F_Delete" );
+
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+ k = GetChannel ( LastUnit );
+
+ if (k>=0) {
+ if (channel[k]->MMDBManager) {
+ switch (*delKey) {
+ case 1 : delMask = mmdb::MMDBFCM_All; break;
+ case 2 : delMask = mmdb::MMDBFCM_Top; break;
+ case 3 : delMask = mmdb::MMDBFCM_Title; break;
+ case 4 : delMask = mmdb::MMDBFCM_Cryst; break;
+ case 5 : delMask = mmdb::MMDBFCM_Coord; break;
+ default : delMask = 0x0000;
+ }
+ channel[k]->MMDBManager->Delete ( delMask );
+ *iRet = RWBERR_Ok;
+ } else
+ *iRet = RWBERR_NoFile;
+ } else
+ *iRet = RWBERR_NoChannel;
+
+ LastRC = *iRet;
+
+}
+
+
+FORTRAN_SUBR ( MMDB_F_SETTYPE, mmdb_f_settype,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::fpstr FType, // "PDB", "CIF", "BIN" or " "
+ mmdb::machine::fpstr RWStat, // "INPUT" or "OUTPUT"
+ int * iRet, // returns -1 if unit not found,
+ // otherwise 0
+ int FType_len, // fortran-hidden length of FType
+ int RWStat_len // fortran-hidden length of RWStat
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr FType,
+ mmdb::machine::fpstr RWStat, int * iRet
+ ), ( // length-follow list
+ int * iUnit,
+ mmdb::machine::fpstr FType, int FType_len,
+ mmdb::machine::fpstr RWStat, int RWStat_len,
+ int * iRet
+ ) ) {
+UNUSED_ARGUMENT(FType_len);
+UNUSED_ARGUMENT(RWStat_len);
+
+int k;
+
+ strcpy ( LastFunc,"MMDB_F_SetType" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+
+ if (k>=0) {
+ // store unit type
+ channel[k]->SetFileType ( FTN_STR(FType) );
+ // store unit mode
+ if (FTN_STR(RWStat)[0]=='I') channel[k]->nRead = 0;
+ else channel[k]->nRead = 1;
+ *iRet = RWBERR_Ok;
+ } else
+ *iRet = RWBERR_NoChannel;
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_SETNAME, mmdb_f_setname,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::fpstr FName, // file name
+ int * iRet, // returns -1 if unit not found,
+ // otherwise 0
+ int FName_len // fortran-hidden length of FName
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr FName, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::fpstr FName, int FName_len,
+ int * iRet
+ ) ) {
+
+int k;
+
+ strcpy ( LastFunc,"MMDB_F_SetName" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+
+ if (k<0)
+ *iRet = RWBERR_NoChannel;
+ else {
+ // store file name
+ channel[k]->SetFileName ( FTN_STR(FName),FTN_LEN(FName) );
+ *iRet = RWBERR_Ok;
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+FORTRAN_SUBR ( MMDB_F_WRITE, mmdb_f_write,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) ) {
+int k;
+
+ strcpy ( LastFunc,"MMDB_F_Write" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+
+ if (k<0)
+ *iRet = RWBERR_NoChannel;
+ else {
+ channel[k]->Write();
+ *iRet = channel[k]->ErrCode;
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+FORTRAN_SUBR ( MMDB_F_CLOSE, mmdb_f_close,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) ) {
+int k;
+
+ strcpy ( LastFunc,"MMDB_F_Close" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+
+ if (k<0)
+ *iRet = RWBERR_NoChannel;
+ else if (channel[k]->nRead==1) {
+ channel[k]->Write();
+ *iRet = channel[k]->ErrCode;
+ if (!(*iRet)) {
+ delete channel[k];
+ channel[k] = NULL;
+ }
+ } else {
+ delete channel[k];
+ channel[k] = NULL;
+ *iRet = RWBERR_Ok;
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_ADVANCE, mmdb_f_advance,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ int * iOut, // output echo file
+ int * iTer, // FLAG =1, return iRet=1 if 'ter' card found
+ // =0, do not return on 'ter' card
+ int * iRet // =0 if normal return
+ // =1 if return on 'ter' card (iTer=1)
+ // =2 if return on end of file
+ // =3 if return on 'hetatm' card
+ // =RWBERR_NoChannel if unit does not exist
+ // =RWBERR_NoAdvance if pointer was not
+ // advanced
+ ), ( // lengths-in-structure list
+ int * iUnit, int * iOut, int * iTer, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, int * iOut, int * iTer, int * iRet
+ ) ) {
+
+UNUSED_ARGUMENT(iOut);
+
+int k;
+mmdb::PAtom atom;
+
+ strcpy ( LastFunc,"mmdb_f_advance" );
+ LastUnit = *iUnit;
+
+ k = GetChannel ( *iUnit );
+
+ if (k<0)
+
+ *iRet = RWBERR_NoChannel;
+
+ else if (channel[k]->nRead==0) {
+
+ // in the input file, try to get pointer on the next atom
+
+ do {
+ channel[k]->fPos++; // advance the pointer on Atom array
+ if (channel[k]->EndOfFile()) {
+ atom = NULL;
+ break;
+ }
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+ if (atom) {
+ if ((atom->Ter) && (*iTer==0)) {
+ // ignore 'ter' card if iTer is set to 0
+ atom = NULL;
+ }
+ }
+ } while (!atom);
+
+ if (!atom) *iRet = 2; // no atom found == end of file
+ else if (atom->Ter) *iRet = 1; // 'ter' card encountered
+ else if (atom->Het) *iRet = 3; // 'hetatm' card encountered
+ else *iRet = 0; // advance ok; normal return
+
+ } else {
+
+ // in the output file, just advance the pointer
+
+ if (channel[k]->fPos==0) {
+ channel[k]->fPos++;
+ *iRet = 0;
+ } else {
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+ if (atom) {
+ // the previous atom was set -- advance the pointer
+ channel[k]->fPos++;
+ *iRet = 0;
+ } else
+ // no atom was set; make no advancement
+ *iRet = RWBERR_NoAdvance;
+ }
+
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_REWD, mmdb_f_rewd,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) ) {
+int k;
+
+ strcpy ( LastFunc,"MMDB_F_Rewd" );
+ LastUnit = *iUnit;
+
+ k = GetChannel ( *iUnit );
+ if (k>=0) {
+ channel[k]->fPos = 0;
+ if (channel[k]->nRead!=0) *iRet = RWBWAR_RewOutput;
+ else *iRet = RWBERR_Ok;
+ } else
+ *iRet = RWBERR_NoChannel;
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_BKSP, mmdb_f_bksp,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) ) {
+int k;
+
+ strcpy ( LastFunc,"MMDB_F_BkSp" );
+ LastUnit = *iUnit;
+
+ k = GetChannel ( *iUnit );
+ if (k>=0) {
+ *iRet = RWBERR_Ok;
+ if (channel[k]->fPos==0) *iRet |= RWBWAR_FileTop;
+ else channel[k]->fPos--;
+ if (channel[k]->nRead!=0) *iRet |= RWBWAR_RewOutput;
+ } else
+ *iRet = RWBERR_NoChannel;
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_SEEK, mmdb_f_seek,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ int * fPos, // position to set
+ int * iRet // return code:
+ // 0 Ok
+ // 1 'ter' card met
+ // 2 end of file
+ // 3 'hetatm' card met
+ // <0 error:
+ // RWBERR_NoChannel
+ // iUnit was not
+ // initialized
+ // RWBERR_EmptyPointer
+ // fPos-th position
+ ), ( // lengths-in-structure list
+ int * iUnit, int * fPos, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, int * fPos, int * iRet
+ ) ) {
+int k;
+mmdb::PAtom atom;
+
+ strcpy ( LastFunc,"MMDB_F_Seek" );
+ LastUnit = *iUnit;
+
+ k = GetChannel ( *iUnit );
+
+ if (k<0)
+
+ *iRet = RWBERR_NoChannel;
+
+ else {
+
+ // set the pointer
+ channel[k]->fPos = mmdb::IMax(0,*fPos);
+ if (*fPos==0) *iRet = RWBWAR_FileTop;
+ else *iRet = RWBERR_Ok;
+
+ if (channel[k]->nRead==0) {
+
+ // in the input file, check the end-of-file state
+ // and analyze the atom
+
+ if (channel[k]->EndOfFile()) *iRet = 2;
+
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+
+ if (!atom) *iRet = RWBERR_EmptyPointer; // empty place
+ else if (atom->Ter) *iRet = 1; // 'ter' card encountered
+ else if (atom->Het) *iRet = 3; // 'hetatm' card encountered
+
+ }
+
+ // in the output file, there is nothing to do
+
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+void Make_AN_ID_IZ ( mmdb::PAtom atom, mmdb::pstr AtNam, int AtNam_L,
+ mmdb::pstr ID, int ID_L, int * IZ, int * iRet ) {
+char chrg[10];
+int i,k;
+
+ if (atom->Ter) {
+
+ mmdb::strcpy_ns ( AtNam,mmdb::pstr(" "),AtNam_L );
+ mmdb::strcpy_ns ( ID ,mmdb::pstr(" "),ID_L );
+ *IZ = 7;
+
+ } else {
+
+ if (atom->name[0]==' ') mmdb::strcpy_ns ( AtNam,&(atom->name[1]),4 );
+ else mmdb::strcpy_ns ( AtNam,atom->name,4 );
+
+ // first try to identify the atom with the element name
+ mmdb::strcpy_ns ( ID,atom->element,ID_L ); // not more than ID_L symbols
+ // from element until but not including
+ // the terminated null are copied into
+ // ID, and the latter is padded with
+ // spaces up to the length of ID_L
+
+ if (ID_L>3) { // if length permits, add ID with atom charge
+ // (always 2 symbols).
+ atom->GetAtomCharge(chrg);
+ ID[2] = chrg[0];
+ ID[3] = chrg[1];
+ }
+
+ k = 0;
+ while ((k<mmdb::nElementNames) &&
+ ((atom->element[0]!=mmdb::ElementName[k][0]) ||
+ (atom->element[1]!=mmdb::ElementName[k][1]))) k++;
+
+ if (k>=mmdb::nElementNames) {
+
+ // no match for atom ID -- make sure to set it blank
+ mmdb::strcpy_ns ( ID,mmdb::pstr(" "),ID_L );
+
+ // try to identify the atom using the atom name
+ k = 0;
+ while ((k<mmdb::nElementNames) &&
+ ((atom->name[0]!=mmdb::ElementName[k][0]) ||
+ (atom->name[1]!=mmdb::ElementName[k][1]))) k++;
+
+ // try to identify a heteroatom
+ i = 0;
+ while ((i<mmdb::nHydAtomNames) && (k>=mmdb::nElementNames)) {
+ if ((atom->name[0]==mmdb::HydAtomName[i][0]) &&
+ (atom->name[1]==mmdb::HydAtomName[i][1]))
+ k = 0;
+ i++;
+ }
+
+ if (k>=mmdb::nElementNames) {
+ // unknown or ambiguous formfactor
+ k = -1;
+ if ((atom->name[0]==' ') &&
+ (atom->name[1]=='A')) k = 6;
+ if (k==-1) *iRet |= RWBWAR_UnkFormFactor;
+ else *iRet |= RWBWAR_AmbFormFactor;
+ }
+
+ }
+
+ *IZ = k+1;
+ if (*IZ==0)
+ mmdb::strcpy_ns ( ID,mmdb::pstr(" "),ID_L );
+ else {
+ if (ID_L>3) {
+ if (ID[0]==' ') {
+ if ((AtNam[2]=='+') ||
+ (AtNam[2]=='-')) {
+ ID[2] = AtNam[2];
+ ID[3] = AtNam[3];
+ }
+ } else if ((ID[2]!='+') && (ID[2]!='-')) {
+ ID[2] = ' ';
+ ID[3] = ' ';
+ }
+ }
+ mmdb::strcpy_ns ( ID,mmdb::ElementName[k],mmdb::IMin(2,ID_L) );
+ }
+
+ }
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_ATOM, mmdb_f_atom,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ int * iSer, // atom serial number
+ mmdb::machine::fpstr AtNam, // atom name (left justified)
+ mmdb::machine::fpstr ResNam, // residue name
+ mmdb::machine::fpstr ChnNam, // chain name
+ int * iResN, // residue number as an integer
+ mmdb::machine::fpstr ResNo, // residue number as character (input only)
+ mmdb::machine::fpstr InsCod, // the insertion code
+ mmdb::machine::fpstr AltCod, // the alternate conformation code
+ mmdb::machine::fpstr segID, // segment ID
+ int * IZ, // atomic number (input only, returned as
+ // 7 from ambiguous atoms)
+ mmdb::machine::fpstr ID, // atomic ID related to atomic number
+ // (element symbol right justified), plus
+ // the ionic state +2, +3 etc..
+ //
+ int * iRet, // returns
+ // RWBERR_NoChannel if iUnit was not
+ // initialized
+ // RWBERR_EmptyPointer if atom was not
+ // advanced
+ // RWBERR_Error1 internal error #1
+ // RWBERR_Error2 internal error #2
+ // RWBERR_Error3 internal error #3
+ //
+ // >=0 : success, warning flags:
+ // RWBWAR_WrongSerial if serial number
+ // differs from the position
+ // number in the file
+ // RWBWAR_UnkFormFactor unknown formfactor
+ // RWBWAR_AmbFormFactor ambiguous formfactor
+ //
+ int AtNam_len, // fortran-hidden length of AtNam
+ int ResNam_len, // fortran-hidden length of ResNam
+ int ChnNam_len, // fortran-hidden length of ChnNam
+ int ResNo_len, // fortran-hidden length of ResNo
+ int InsCod_len, // fortran-hidden length of InsCod
+ int AltCod_len, // fortran-hidden length of AltCod
+ int segID_len, // fortran-hidden length of SegID
+ int ID_len // fortran-hidden length of ID
+ ), ( // lengths-in-structure list
+ int * iUnit, int * iSer, mmdb::machine::fpstr AtNam, mmdb::machine::fpstr ResNam,
+ mmdb::machine::fpstr ChnNam, int * iResN, mmdb::machine::fpstr ResNo, mmdb::machine::fpstr InsCod,
+ mmdb::machine::fpstr AltCod, mmdb::machine::fpstr segID, int * IZ, mmdb::machine::fpstr ID,
+ int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, int * iSer,
+ mmdb::machine::fpstr AtNam, int AtNam_len,
+ mmdb::machine::fpstr ResNam, int ResNam_len,
+ mmdb::machine::fpstr ChnNam, int ChnNam_len,
+ int * iResN,
+ mmdb::machine::fpstr ResNo, int ResNo_len,
+ mmdb::machine::fpstr InsCod, int InsCod_len,
+ mmdb::machine::fpstr AltCod, int AltCod_len,
+ mmdb::machine::fpstr segID, int segID_len,
+ int * IZ,
+ mmdb::machine::fpstr ID, int ID_len,
+ int * iRet
+ ) ) {
+int k,RC;
+mmdb::ChainID chainID;
+mmdb::ResName resName;
+mmdb::InsCode insCode;
+mmdb::AtomName atomName;
+mmdb::AltLoc altLoc;
+mmdb::SegID sgID;
+mmdb::Element element;
+mmdb::PAtom atom;
+char charge[10];
+
+ strcpy ( LastFunc,"MMDB_F_Atom" );
+ LastUnit = *iUnit;
+
+ k = GetChannel ( *iUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ *iRet = RWBERR_Ok;
+
+ if (channel[k]->nRead==0) {
+
+ // reading the atom characteristics
+
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+ if (!atom) {
+ // atom position was not advanced properly
+ *iRet = RWBERR_EmptyPointer;
+ LastRC = *iRet;
+ return;
+ }
+
+ *iSer = atom->serNum;
+ if (*iSer!=channel[k]->fPos) *iRet |= RWBWAR_WrongSerial;
+ LastSer = *iSer;
+ Make_AN_ID_IZ ( atom,FTN_STR(AtNam),FTN_LEN(AtNam),
+ FTN_STR(ID),FTN_LEN(ID),IZ,iRet );
+ if (atom->residue) {
+ mmdb::strcpy_ns ( FTN_STR(ResNam),atom->residue->name,FTN_LEN(ResNam) );
+ *iResN = atom->residue->seqNum;
+ mmdb::PutInteger ( FTN_STR(ResNo),*iResN,mmdb::IMin(4,FTN_LEN(ResNo)) );
+ mmdb::strcpy_ns ( FTN_STR(InsCod),atom->residue->insCode,FTN_LEN(InsCod) );
+ mmdb::strcpy_ns ( &(FTN_STR(ResNo)[4]),FTN_STR(InsCod),FTN_LEN(ResNo)-4 );
+ mmdb::strcpy_ns ( FTN_STR(ChnNam),atom->GetChainID(),FTN_LEN(ChnNam) );
+ } else {
+ mmdb::strcpy_ns ( FTN_STR(ResNam),mmdb::pstr(" "),FTN_LEN(ResNam) );
+ mmdb::strcpy_ns ( FTN_STR(ChnNam),mmdb::pstr(" ") ,FTN_LEN(ChnNam) );
+ *iResN = 0;
+ mmdb::strcpy_ns ( FTN_STR(ResNo) ,mmdb::pstr("0") ,FTN_LEN(ResNo) );
+ mmdb::strcpy_ns ( FTN_STR(InsCod),mmdb::pstr(" ") ,FTN_LEN(InsCod) );
+ }
+ mmdb::strcpy_ns ( FTN_STR(AltCod),atom->altLoc,FTN_LEN(AltCod) );
+ mmdb::strcpy_ns ( FTN_STR(segID) ,atom->segID ,FTN_LEN(segID) );
+
+ } else {
+
+ // storing the atom characteristics
+
+ if (!channel[k]->MMDBManager) {
+ *iRet = RWBERR_Error1; // should never happen
+ LastRC = *iRet;
+ return;
+ }
+
+ mmdb::GetStrTer ( chainID,FTN_STR(ChnNam),1,sizeof(chainID),FTN_LEN(ChnNam) );
+ mmdb::GetStrTer ( resName,FTN_STR(ResNam),3,sizeof(resName),FTN_LEN(ResNam) );
+ mmdb::GetStrTer ( insCode,FTN_STR(InsCod),1,sizeof(insCode),FTN_LEN(InsCod) );
+ mmdb::GetStrTer ( altLoc ,FTN_STR(AltCod),1,sizeof(altLoc) ,FTN_LEN(AltCod) );
+ mmdb::GetStrTer ( sgID ,FTN_STR(segID) ,4,sizeof(sgID) ,FTN_LEN(segID) );
+ element[0] = FTN_STR(ID)[0];
+ element[1] = FTN_STR(ID)[1];
+ element[2] = char(0);
+ if (FTN_LEN(ID)>3) {
+ charge [0] = FTN_STR(ID)[2];
+ charge [1] = FTN_STR(ID)[3];
+ charge [2] = char(0);
+ } else
+ charge [0] = char(0);
+
+ if (FTN_STR(ID)[0]==' ') {
+ atomName[0] = char(0);
+// if ((FTN_STR(AtNam)[1]=='H') ||
+// ((FTN_STR(AtNam)[1]=='D') && (FTN_STR(ID)[2]=='D'))) {
+// int i = 0;
+// while ((i<nHydAtomNames) &&
+// (FTN_STR(AtNam)[0]!=HydAtomName[i][0])) i++;
+// if (i<nHydAtomNames)
+// GetStrTer ( atomName,FTN_STR(AtNam),4,5,FTN_LEN(AtNam) );
+// }
+ if ((FTN_STR(AtNam)[0]=='H') && (FTN_STR(AtNam)[3]!=' '))
+ mmdb::GetStrTer ( atomName,FTN_STR(AtNam),4,5,FTN_LEN(AtNam) );
+ if (!atomName[0]) {
+ atomName[0] = ' ';
+ mmdb::GetStrTer ( &(atomName[1]),FTN_STR(AtNam),3,4,FTN_LEN(AtNam) );
+ }
+ } else
+ mmdb::GetStrTer ( atomName,FTN_STR(AtNam),4,5,4 );
+
+ RC = channel[k]->MMDBManager->PutAtom ( channel[k]->fPos,*iSer,
+ atomName,resName,chainID,*iResN,
+ insCode,altLoc,sgID,element );
+
+ if (RC) {
+ *iRet = RWBERR_Error2; // should never happen
+ LastRC = *iRet;
+ return;
+ }
+
+ mmdb::DelSpaces ( charge );
+ if (charge[0]) {
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+ if (!atom) {
+ *iRet = RWBERR_EmptyPointer; // should never be so
+ LastRC = *iRet;
+ return;
+ }
+ atom->SetCharge ( charge );
+ }
+
+ if (*iSer!=channel[k]->fPos) {
+ *iRet |= RWBWAR_WrongSerial; // this is not the right thing at all
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+ if (!atom) {
+ *iRet = RWBERR_EmptyPointer; // should never be so
+ LastRC = *iRet;
+ return;
+ }
+ // atom->serNum = *iSer; // - we allow for a mess in serials
+ }
+
+ LastSer = *iSer;
+
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_SETTER, mmdb_f_setter,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) ) {
+int k;
+mmdb::PAtom atom;
+
+ strcpy ( LastFunc,"MMDB_F_SetTer" );
+ LastUnit = *iUnit;
+
+ k = GetChannel ( *iUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+ *iRet = RWBERR_Ok;
+
+ if (!atom) {
+ *iRet = RWBERR_EmptyPointer; // atom position was not advanced properly
+ LastRC = *iRet;
+ return;
+ }
+
+ atom->Ter = true;
+ atom->WhatIsSet |= mmdb::ASET_Coordinates;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_SETHET, mmdb_f_sethet,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) ) {
+int k;
+mmdb::PAtom atom;
+
+ strcpy ( LastFunc,"MMDB_F_SetHet" );
+ LastUnit = *iUnit;
+
+ k = GetChannel ( *iUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+ *iRet = RWBERR_Ok;
+
+ if (!atom) {
+ *iRet = RWBERR_EmptyPointer; // atom position was not advanced properly
+ LastRC = *iRet;
+ return;
+ }
+
+ atom->Het = true;
+ atom->WhatIsSet |= mmdb::ASET_Coordinates;
+
+}
+
+FORTRAN_SUBR ( MMDB_F_GETHET, mmdb_f_gethet,
+ ( int * iUnit, int * isHet, int * iRet ),
+ ( int * iUnit, int * isHet, int * iRet ),
+ ( int * iUnit, int * isHet, int * iRet ) ) {
+int k;
+mmdb::PAtom atom;
+
+ strcpy ( LastFunc,"MMDB_F_GetHet" );
+ LastUnit = *iUnit;
+
+ *isHet = 0; // no HETATM record
+
+ k = GetChannel ( *iUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+ *iRet = RWBERR_Ok;
+
+ if (!atom) {
+ *iRet = RWBERR_EmptyPointer; // atom position was not advance properly
+ LastRC = *iRet;
+ return;
+ }
+
+ if (atom->Het) *isHet = 1; // HETATM
+
+}
+
+
+FORTRAN_SUBR ( MMDB_F_COPYATOM, mmdb_f_copyatom,
+ ( int * iUnit1, int * iUnit2, int * iRet ),
+ ( int * iUnit1, int * iUnit2, int * iRet ),
+ ( int * iUnit1, int * iUnit2, int * iRet ) ) {
+int k1,k2,RC;
+mmdb::PAtom atom;
+
+ strcpy ( LastFunc,"mmdb_f_copyatom" );
+ LastUnit = *iUnit1;
+
+ k1 = GetChannel ( *iUnit1 );
+ if (k1<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ k2 = GetChannel ( *iUnit2 );
+ if (k2<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ atom = channel[k1]->GetAtomI ( channel[k1]->fPos );
+ *iRet = RWBERR_Ok;
+
+ if (!atom) {
+ *iRet = RWBERR_EmptyPointer; // atom position was not advanced
+ // properly
+ LastRC = *iRet;
+ return;
+ }
+
+ RC = channel[k2]->MMDBManager->PutAtom ( channel[k2]->fPos,atom,
+ atom->serNum );
+ if (RC) {
+ *iRet = RWBERR_Error2; // should never happen
+ LastRC = *iRet;
+ return;
+ }
+
+ LastSer = atom->serNum;
+
+}
+
+
+FORTRAN_SUBR ( MMDB_F_COORD, mmdb_f_coord,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::fpstr XFlag, // "F" or "O" flag for the fractional
+ // or orthogonal coordinates x,y,z
+ // for output files XFlag may also be
+ // set to "HF" or "HO", where "F" and
+ // "O" have the same meaning as before
+ // and "H" indicates that the atom
+ // should be marked as heteroatom
+ mmdb::machine::fpstr BFlag , // "F" or "O" flag for temperature
+ // factor in fractional or orthogonal
+ // Us
+ mmdb::machine::apireal * x, // x-coordinate
+ mmdb::machine::apireal * y, // y-coordinate
+ mmdb::machine::apireal * z, // z-coordinate
+ mmdb::machine::apireal * occ, // occupancy
+ mmdb::machine::apireal * BIso, // isotropic temperature factor
+ mmdb::machine::apireal * U, // array(6) of the anisotr. t-factor
+ int * iRet, // returns
+ // RWBERR_NoChannel if iUnit was not
+ // initialized
+ // RWBERR_EmptyPointer if atom was not
+ // advanced
+ // RWBERR_NoMatrices if transformation
+ // matrices are
+ // undefined
+ // RWBERR_NoCoordinates if coordinates were
+ // not set in the atom
+ //
+ // >=0 : success, warning flags:
+ // RWBERR_NoOccupancy if occupancy was
+ // not set in the atom
+ // RWBERR_NoTempFactor if temp. factor was
+ // not set in the atom
+ //
+ int XFlag_len, // fortran-hidden length of XFlag
+ int BFlag_len // fortran-hidden length of BFlag
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr XFlag, mmdb::machine::fpstr BFlag,
+ mmdb::machine::apireal * x, mmdb::machine::apireal * y, mmdb::machine::apireal * z,
+ mmdb::machine::apireal * occ, mmdb::machine::apireal * BIso, mmdb::machine::apireal * U,
+ int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::fpstr XFlag, int XFlag_len,
+ mmdb::machine::fpstr BFlag, int BFlag_len,
+ mmdb::machine::apireal * x, mmdb::machine::apireal * y, mmdb::machine::apireal * z,
+ mmdb::machine::apireal * occ, mmdb::machine::apireal * BIso, mmdb::machine::apireal * U,
+ int * iRet
+ ) ) {
+
+UNUSED_ARGUMENT(XFlag_len);
+UNUSED_ARGUMENT(BFlag_len);
+
+mmdb::realtype AU[6];
+mmdb::realtype xx,yy,zz;
+int k,i,m;
+mmdb::PAtom atom;
+
+ strcpy ( LastFunc,"MMDB_F_Coord" );
+ LastUnit = *iUnit;
+
+ k = GetChannel ( *iUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ atom = channel[k]->GetAtomI ( channel[k]->fPos );
+ *iRet = RWBERR_Ok;
+
+ if (!atom) {
+ *iRet = RWBERR_EmptyPointer; // atom position was not advanced properly
+ LastRC = *iRet;
+ return;
+ }
+
+ if ((FTN_STR(XFlag)[0]=='H') ||
+ (FTN_STR(XFlag)[0]=='h')) m = 1;
+ else m = 0;
+
+ if (channel[k]->nRead==0) {
+
+ // reading the atomic coordinates
+
+ if (atom->Ter) {
+ *x = 0.0;
+ *y = 0.0;
+ *z = 0.0;
+ *occ = 1.0;
+ *BIso = 1.0;
+ U[0] = 1.0;
+ U[1] = 0.0;
+ U[2] = 0.0;
+ U[3] = 0.0;
+ U[4] = 0.0;
+ U[5] = 0.0;
+ } else {
+
+ if (atom->WhatIsSet & mmdb::ASET_Coordinates) {
+ if ((FTN_STR(XFlag)[m]=='F') ||
+ (FTN_STR(XFlag)[m]=='f')) {
+ // receive fractional coordinates
+ if (channel[k]->areCrystMatrices()) {
+ channel[k]->Orth2Frac ( atom->x,atom->y,atom->z,xx,yy,zz );
+ *x = (mmdb::machine::apireal)xx;
+ *y = (mmdb::machine::apireal)yy;
+ *z = (mmdb::machine::apireal)zz;
+ } else {
+ *x = (mmdb::machine::apireal)atom->x;
+ *y = (mmdb::machine::apireal)atom->y;
+ *z = (mmdb::machine::apireal)atom->z;
+ *iRet = RWBERR_NoMatrices;
+ }
+ } else {
+ // receive orthogonal coordinates
+ *x = (mmdb::machine::apireal)atom->x;
+ *y = (mmdb::machine::apireal)atom->y;
+ *z = (mmdb::machine::apireal)atom->z;
+ }
+ } else {
+ *x = 0.0;
+ *y = 0.0;
+ *z = 0.0;
+ *iRet = RWBERR_NoCoordinates;
+ }
+
+ // calculate isotropic Uf from Uo, and convert it
+ // if necessary
+ if (atom->WhatIsSet & mmdb::ASET_Anis_tFac) {
+ AU[0] = atom->u11; // this intermediate array is
+ AU[1] = atom->u22; // required because of possible
+ AU[2] = atom->u33; // type difference between
+ AU[3] = atom->u12; // 'mmdb::machine::apireal' and 'realtype'
+ AU[4] = atom->u13;
+ AU[5] = atom->u23;
+ *BIso = (mmdb::machine::apireal)(8.0*mmdb::Pi*mmdb::Pi*(AU[0]+AU[1]+AU[2])/3.0);
+ if ((FTN_STR(BFlag)[0]=='F') ||
+ (FTN_STR(BFlag)[0]=='f')) {
+ if (channel[k]->areCrystMatrices())
+ channel[k]->Orth2Cryst ( AU );
+ else if (*iRet==RWBERR_Ok)
+ *iRet = RWBERR_NoMatrices;
+ }
+ for (i=0;i<6;i++)
+ U[i] = (mmdb::machine::apireal)AU[i];
+ } else {
+ for (i=0;i<6;i++)
+ U[i] = 0.0;
+ if (atom->WhatIsSet & mmdb::ASET_tempFactor)
+ U[0] = (mmdb::machine::apireal)atom->tempFactor;
+ else if (*iRet>=RWBERR_Ok)
+ *iRet |= RWBWAR_NoTempFactor;
+ *BIso = U[0];
+ }
+
+ // get occupancy now
+ if (atom->WhatIsSet & mmdb::ASET_Occupancy)
+ *occ = (mmdb::machine::apireal)atom->occupancy;
+ else {
+ *occ = 0.0;
+ if (*iRet>=RWBERR_Ok) *iRet |= RWBWAR_NoOccupancy;
+ }
+
+ }
+
+ } else {
+
+ // storing the atomic coordinates
+
+ if (atom->Ter) {
+ atom->x = 0.0;
+ atom->y = 0.0;
+ atom->z = 0.0;
+ atom->WhatIsSet |= mmdb::ASET_Coordinates;
+ atom->occupancy = 1.0;
+ atom->tempFactor = 1.0;
+ atom->u11 = 0.0;
+ atom->u22 = 0.0;
+ atom->u33 = 0.0;
+ atom->u12 = 0.0;
+ atom->u13 = 0.0;
+ atom->u23 = 0.0;
+ } else {
+
+ if ((FTN_STR(XFlag)[m]=='F') ||
+ (FTN_STR(XFlag)[m]=='f')) {
+ // convert fractional coordinates
+ if (channel[k]->areCrystMatrices()) {
+ xx = *x;
+ yy = *y;
+ zz = *z;
+ channel[k]->Frac2Orth ( xx,yy,zz,atom->x,atom->y,atom->z );
+ atom->WhatIsSet |= mmdb::ASET_Coordinates;
+ } else {
+ atom->x = *x;
+ atom->y = *y;
+ atom->z = *z;
+ *iRet = RWBERR_NoMatrices;
+ atom->WhatIsSet &= ~mmdb::ASET_Coordinates;
+ }
+ } else {
+ // store orthogonal coordinates
+ atom->x = *x;
+ atom->y = *y;
+ atom->z = *z;
+ atom->WhatIsSet |= mmdb::ASET_Coordinates;
+ }
+
+ atom->Het = (m>0);
+
+ // calculate isotropic Uf from Uo, and convert it
+ // if necessary
+ if ((U[1]!=0.0) || (U[2]!=0.0)) {
+ for (i=0;i<6;i++)
+ AU[i] = U[i];
+ if ((FTN_STR(BFlag)[0]=='F') ||
+ (FTN_STR(BFlag)[0]=='f')) {
+ if (channel[k]->areCrystMatrices())
+ channel[k]->Cryst2Orth ( AU );
+ else *iRet = RWBERR_NoMatrices;
+ }
+ *BIso = (mmdb::machine::apireal)(8.0*mmdb::Pi*mmdb::Pi*(AU[0]+AU[1]+AU[2])/3.0);
+ atom->tempFactor = *BIso;
+ atom->u11 = AU[0];
+ atom->u22 = AU[1];
+ atom->u33 = AU[2];
+ atom->u12 = AU[3];
+ atom->u13 = AU[4];
+ atom->u23 = AU[5];
+ atom->WhatIsSet |= mmdb::ASET_tempFactor | mmdb::ASET_Anis_tFac;
+ } else {
+ *BIso = U[0];
+ atom->tempFactor = *BIso;
+ atom->u11 = 0.0;
+ atom->u22 = 0.0;
+ atom->u33 = 0.0;
+ atom->u12 = 0.0;
+ atom->u13 = 0.0;
+ atom->u23 = 0.0;
+ atom->WhatIsSet |= mmdb::ASET_tempFactor;
+ }
+
+ // store occupancy now
+ atom->occupancy = *occ;
+ atom->WhatIsSet |= mmdb::ASET_Occupancy;
+
+ }
+
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_SETCELL, mmdb_f_setcell,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::apireal * a, // cell parameter a, angstroms
+ mmdb::machine::apireal * b, // cell parameter b, angstroms
+ mmdb::machine::apireal * c, // cell parameter c, angstroms
+ mmdb::machine::apireal * alpha, // cell parameter alpha, degrees
+ mmdb::machine::apireal * beta, // cell parameter beta, degrees
+ mmdb::machine::apireal * gamma, // cell parameter gamma, degrees
+ int * ArgNCode, // orthogonalization code, 1-6
+ int * iRet // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_Disagreement if a
+ // disagreement in
+ // cell parameters
+ // was found
+ // RWBERR_NoOrthCode if no
+ // orthogonalization
+ // code was found
+ // RWBERR_NoCheck if check
+ // of cell parameters
+ // has failed.
+ // The last three returns would
+ // rather indicate a programming
+ // error in mmdb_rwbrook.cpp
+ ), ( // lengths-in-structure list
+ int * iUnit,
+ mmdb::machine::apireal * a, mmdb::machine::apireal * b, mmdb::machine::apireal * c,
+ mmdb::machine::apireal * alpha, mmdb::machine::apireal * beta, mmdb::machine::apireal * gamma,
+ int * ArgNCode, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::apireal * a, mmdb::machine::apireal * b, mmdb::machine::apireal * c,
+ mmdb::machine::apireal * alpha, mmdb::machine::apireal * beta, mmdb::machine::apireal * gamma,
+ int * ArgNCode, int * iRet
+ ) ) {
+int k;
+
+ strcpy ( LastFunc,"MMDB_F_SetCell" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0)
+ *iRet = RWBERR_NoChannel;
+ else
+ *iRet = channel[k]->SetCell ( *a,*b,*c,*alpha,*beta,*gamma,
+ *ArgNCode );
+
+ LastRC = *iRet;
+
+}
+
+
+FORTRAN_SUBR ( MMDB_F_WBSPGRP, mmdb_f_wbspgrp,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::fpstr spGroup, // space group
+ int * iRet, // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ int spGroup_len // fortran-hidden length of spGroup
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr spGroup, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::fpstr spGroup, int spGroup_len,
+ int * iRet
+ )
+ ) {
+int k;
+mmdb::SymGroup spaceGroup;
+
+ strcpy ( LastFunc,"MMDB_F_WBSpGrp" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0)
+ *iRet = RWBERR_NoChannel;
+ else {
+// GetStrTer ( spaceGroup,FTN_STR(spGroup),0,
+// sizeof(spaceGroup),FTN_LEN(spGroup) );
+ mmdb::strcpy_ncss(spaceGroup,FTN_STR(spGroup),mmdb::IMin(FTN_LEN(spGroup),
+ sizeof(spaceGroup)-1) );
+ *iRet = channel[k]->SetSpGroup ( spaceGroup );
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_RBSPGRP, mmdb_f_rbspgrp,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::fpstr spGroup, // space group
+ int * iRet, // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ int spGroup_len // fortran-hidden length of spGroup
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr spGroup, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::fpstr spGroup, int spGroup_len,
+ int * iRet
+ )
+ ) {
+int k;
+char SpaceGroup[100];
+
+ strcpy ( LastFunc,"MMDB_F_RBSpGrp" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ SpaceGroup[0] = char(0);
+ k = GetChannel ( LastUnit );
+ if (k<0) *iRet = RWBERR_NoChannel;
+ else *iRet = channel[k]->GetSpGroup ( SpaceGroup );
+
+// all extra "superficial spaces" are killed in the following
+ mmdb::CutSpaces ( SpaceGroup,mmdb::SCUTKEY_BEGEND );
+ mmdb::strcpy_ns ( FTN_STR(spGroup),SpaceGroup,FTN_LEN(spGroup) );
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_WBCELL , mmdb_f_wbcell,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * ArgCell, // array to accept the cell parameters
+ // if ArgCell(1) is set to 0, then
+ // the cell does not change
+ int * ArgNCode, // orthogonalisation code
+ // if ArgNCode is set to 0, then
+ // the orthogonalisation matrices
+ // do not change
+ int * iRet // return code
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::apireal * ArgCell,
+ int * ArgNCode, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::apireal * ArgCell,
+ int * ArgNCode, int * iRet
+ )
+ ) {
+int k;
+
+ strcpy ( LastFunc,"MMDB_F_WBCell" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0)
+ *iRet = RWBERR_NoChannel;
+ else
+ *iRet = channel[k]->PutCell ( ArgCell[0],ArgCell[1],ArgCell[2],
+ ArgCell[3],ArgCell[4],ArgCell[5],
+ *ArgNCode );
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_RBCELL, mmdb_f_rbcell,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::apireal * celld, // array to accept the cell parameters
+ mmdb::machine::apireal * cvol, // returns the cell volume
+ int * iRet // return code
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_Parameters if the
+ // cell parameters
+ // were not set
+ // RWBERR_NoOrthCode if no
+ // orthogonalization
+ // code was found
+ // RWBERR_NoCheck if check
+ // of cell parameters
+ // has failed.
+ // The last three returns would
+ // rather indicate a programming
+ // error in mmdb_rwbrook.cpp
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::apireal * celld,
+ mmdb::machine::apireal * cvol, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::apireal * celld,
+ mmdb::machine::apireal * cvol, int * iRet
+ ) ) {
+mmdb::realtype p[6];
+mmdb::realtype v;
+int k,i,nc;
+
+ strcpy ( LastFunc,"MMDB_F_RBCell" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ *iRet = channel[k]->GetCell ( p[0],p[1],p[2],p[3],p[4],p[5],v,nc );
+
+ if (*iRet==RWBERR_Ok) {
+ for (i=0;i<6;i++)
+ celld[i] = (mmdb::machine::apireal)p[i];
+ *cvol = (mmdb::machine::apireal)v;
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_RBCELLN, mmdb_f_rbcelln,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::apireal * celld, // array to accept the cell parameters
+ mmdb::machine::apireal * cvol, // returns the cell volume
+ int * ArgNCode, // returns the orthogonalization code, 1-6
+ int * iRet // return code
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_Parameters if the
+ // cell parameters
+ // were not set
+ // RWBERR_NoOrthCode if no
+ // orthogonalization
+ // code was found
+ // RWBERR_NoCheck if check
+ // of cell parameters
+ // has failed.
+ // The last three returns would
+ // rather indicate a programming
+ // error in mmdb_rwbrook.cpp
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::apireal * celld, mmdb::machine::apireal * cvol,
+ int * ArgNCode, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::apireal * celld, mmdb::machine::apireal * cvol,
+ int * ArgNCode, int * iRet
+ ) ) {
+mmdb::realtype p[6];
+mmdb::realtype v;
+int k,i,nc;
+
+ strcpy ( LastFunc,"MMDB_F_RBCellN" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ *iRet = channel[k]->GetCell ( p[0],p[1],p[2],p[3],p[4],p[5],v,nc );
+ if (*iRet==RWBERR_Ok) {
+ for (i=0;i<6;i++)
+ celld[i] = (mmdb::machine::apireal)p[i];
+ *cvol = (mmdb::machine::apireal)v;
+ *ArgNCode = nc;
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_RBRCEL, mmdb_f_rbrcel,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::apireal * rcell, // array to accept the reciprocal
+ // cell parameters
+ mmdb::machine::apireal * rvol, // returns the reciprocal cell volume
+ int * iRet // return code
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_Parameters if the
+ // cell parameters
+ // were not set
+ // RWBERR_NoOrthCode if no
+ // orthogonalization
+ // code was found
+ // RWBERR_NoCheck if check
+ // of cell parameters
+ // has failed.
+ // The last three returns would
+ // rather indicate a programming
+ // error in mmdb_rwbrook.cpp
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::apireal * rcell, mmdb::machine::apireal * rvol,
+ int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::apireal * rcell, mmdb::machine::apireal * rvol,
+ int * iRet
+ ) ) {
+mmdb::realtype p[6];
+mmdb::realtype v;
+int k,i;
+
+ strcpy ( LastFunc,"MMDB_F_RBRCel" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ *iRet = channel[k]->GetRCell ( p[0],p[1],p[2],p[3],p[4],p[5],v );
+ if (*iRet==RWBERR_Ok) {
+ for (i=0;i<6;i++)
+ rcell[i] = (mmdb::machine::apireal)p[i];
+ *rvol = (mmdb::machine::apireal)v;
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_RBORF, mmdb_f_rborf,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::apireal * RO, // array for orthogonalising matrix
+ mmdb::machine::apireal * RF, // array for fractionalising matrix
+ int * LCode, // buffer for orthogonalisation code
+ int * iRet // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_NoMatrices if the
+ // orthogonalisation
+ // matrices were not
+ // calculated
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::apireal * RO, mmdb::machine::apireal * RF,
+ int * LCode, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::apireal * RO, mmdb::machine::apireal * RF,
+ int * LCode, int * iRet )
+ ) {
+int i,j,k,l;
+mmdb::PCryst Cryst;
+
+ strcpy ( LastFunc,"MMDB_F_RBORF" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ Cryst = channel[k]->GetCryst();
+ if (Cryst==NULL) {
+ *iRet = RWBERR_NoFile;
+ LastRC = *iRet;
+ return;
+ }
+
+ *iRet = RWBERR_Ok;
+
+ l = 0;
+
+ if (RO[0]<=0.0000000001) {
+ for (j=0;j<4;j++)
+ for (i=0;i<4;i++) {
+ RF[l] = (mmdb::machine::apireal)Cryst->RF[i][j];
+ RO[l] = (mmdb::machine::apireal)Cryst->RO[i][j];
+ l++;
+ }
+ *LCode = Cryst->NCode;
+ if (!(Cryst->WhatIsSet & mmdb::CSET_Transforms))
+ *iRet = RWBERR_NoMatrices;
+ } else {
+ for (j=0;j<4;j++)
+ for (i=0;i<4;i++) {
+ Cryst->RF[i][j] = RF[l];
+ Cryst->RO[i][j] = RO[l];
+ l++;
+ }
+ Cryst->NCode = *LCode;
+ Cryst->WhatIsSet |= mmdb::CSET_Transforms;
+ }
+
+ LastRC = *iRet;
+
+}
+
+
+FORTRAN_SUBR ( MMDB_F_ORTHMAT, mmdb_f_orthmat,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * Cell, // array of cell parameters:
+ // Cell(1) - a Cell(4) - alpha
+ // Cell(2) - b Cell(5) - beta
+ // Cell(3) - c Cell(6) - gamma
+ mmdb::machine::apireal * Vol, // returns cell volume
+ mmdb::machine::apireal * RRR, // array (3,3,6), returns
+ // orthogonalisation matrices
+ int * iRet // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_NoMatrices if the
+ // orthogonalisation
+ // matrices were not
+ // calculated
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::apireal * Cell, mmdb::machine::apireal * Vol,
+ mmdb::machine::apireal * RRR, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::apireal * Cell, mmdb::machine::apireal * Vol,
+ mmdb::machine::apireal * RRR, int * iRet
+ )
+ ) {
+int i,j,k,l,m;
+mmdb::PCryst Cryst;
+mmdb::realtype CelDel;
+
+ strcpy ( LastFunc,"MMDB_F_OrthMat" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ Cryst = channel[k]->GetCryst();
+ if (Cryst==NULL) {
+ *iRet = RWBERR_NoFile;
+ LastRC = *iRet;
+ return;
+ }
+
+ CelDel = 0.0;
+ if (Cell[0]>0.0) {
+ if ((Cryst->WhatIsSet & mmdb::CSET_CellParams)==mmdb::CSET_CellParams) {
+ CelDel = fabs((Cell[0]-Cryst->a)/Cell[0]);
+ if (Cell[1]!=0.0)
+ CelDel = mmdb::RMax(CelDel,fabs((Cell[1]-Cryst->b)/Cell[1]));
+ if (Cell[2]!=0.0)
+ CelDel = mmdb::RMax(CelDel,fabs((Cell[2]-Cryst->c)/Cell[2]));
+ if (Cell[3]!=0.0)
+ CelDel = mmdb::RMax(CelDel,fabs((Cell[3]-Cryst->alpha)/Cell[3]));
+ if (Cell[4]!=0.0)
+ CelDel = mmdb::RMax(CelDel,fabs((Cell[4]-Cryst->beta )/Cell[4]));
+ if (Cell[5]!=0.0)
+ CelDel = mmdb::RMax(CelDel,fabs((Cell[5]-Cryst->gamma)/Cell[5]));
+ if (FSimRWBROOK && (CelDel>0.01))
+ printf ( "\n Inconsistency in Cell Dimensions"
+ " - replacing old:\n"
+ " Old cell: "
+ "%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f\n"
+ " New cell: "
+ "%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f\n",
+ Cryst->a,Cryst->b,Cryst->c,
+ Cryst->alpha,Cryst->beta,Cryst->gamma,
+ Cell[0],Cell[1],Cell[2],Cell[3],Cell[4],Cell[5] );
+ }
+ Cryst->a = Cell[0];
+ Cryst->b = Cell[1];
+ Cryst->c = Cell[2];
+ Cryst->alpha = Cell[3];
+ Cryst->beta = Cell[4];
+ Cryst->gamma = Cell[5];
+ Cryst->WhatIsSet |= mmdb::CSET_CellParams;
+ } else {
+ Cell[0] = (mmdb::machine::apireal)Cryst->a;
+ Cell[1] = (mmdb::machine::apireal)Cryst->b;
+ Cell[2] = (mmdb::machine::apireal)Cryst->c;
+ Cell[3] = (mmdb::machine::apireal)Cryst->alpha;
+ Cell[4] = (mmdb::machine::apireal)Cryst->beta;
+ Cell[5] = (mmdb::machine::apireal)Cryst->gamma;
+ }
+
+ if ((Cryst->WhatIsSet & mmdb::CSET_CellParams)!=mmdb::CSET_CellParams) {
+ *iRet = RWBERR_NoCellParams;
+ LastRC = *iRet;
+ return;
+ }
+
+ *iRet = RWBERR_Ok;
+
+ // Cryst->CalcOrthMatrices(); <-- old version, changed 09.01.2004
+ Cryst->CalcCoordTransforms();
+ Cryst->WhatIsSet |= mmdb::CSET_Transforms;
+
+ if (CelDel>0.01) *Vol = -(mmdb::machine::apireal)Cryst->Vol;
+ else *Vol = (mmdb::machine::apireal)Cryst->Vol;
+
+ l = 0;
+ for (j=0;j<3;j++)
+ for (i=0;i<3;i++)
+ for (m=0;m<6;m++)
+ RRR[l++] = (mmdb::machine::apireal)Cryst->RR[m][j][i];
+
+ LastRC = *iRet;
+
+}
+
+
+FORTRAN_SUBR ( MMDB_F_CVANISOU, mmdb_f_cvanisou,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * U, // array of coordinates to convert
+ int * iFlag, // =0: convert from fract. to orthog.
+ // =1: convert from orthog. to fract.
+ int * iRet // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_NoMatrices if the
+ // orthogonalisation
+ // matrices were not
+ // calculated
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::apireal * U, int * iFlag, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::apireal * U, int * iFlag, int * iRet
+ )
+ ) {
+int k,i;
+mmdb::PCryst Cryst;
+mmdb::realtype U1[6];
+
+ strcpy ( LastFunc,"MMDB_F_CVAnisou" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ Cryst = channel[k]->GetCryst();
+ if (Cryst==NULL) {
+ *iRet = RWBERR_NoFile;
+ LastRC = *iRet;
+ return;
+ }
+
+ *iRet = RWBERR_Ok;
+ for (i=0;i<6;i++)
+ U1[i] = U[i];
+
+ if (iFlag==0) {
+ if (!Cryst->Cryst2Orth(U1)) *iRet = RWBERR_NoMatrices;
+ } else {
+ if (!Cryst->Orth2Cryst(U1)) *iRet = RWBERR_NoMatrices;
+ }
+
+ if (*iRet==RWBERR_Ok)
+ for (i=0;i<6;i++)
+ U[i] = (mmdb::machine::apireal)U1[i];
+
+ LastRC = *iRet;
+
+}
+
+
+
+FORTRAN_SUBR ( MMDB_F_WREMARK, mmdb_f_wremark,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::fpstr Line, // line to be added
+ int * iRet, // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // other return codea are those
+ // returned by xyzopen1_(..)
+ int Line_len // fortran-hidden length of Line
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr Line, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::fpstr Line, int Line_len, int *iRet
+ )
+ ) {
+int k;
+char S[500];
+
+ strcpy ( LastFunc,"MMDB_F_WRemark" );
+ if (*iUnit>0)
+ LastUnit = *iUnit;
+
+ k = GetChannel ( LastUnit );
+ if (k<0) {
+ *iRet = RWBERR_NoChannel;
+ LastRC = *iRet;
+ return;
+ }
+
+ if (channel[k]->MMDBManager) {
+ mmdb::GetStrTer ( S,FTN_STR(Line),FTN_LEN(Line),sizeof(S),FTN_LEN(Line) );
+ *iRet = channel[k]->MMDBManager->PutPDBString ( S );
+ } else
+ *iRet = RWBERR_NoFile;
+
+ LastRC = *iRet;
+
+}
+
+
+/*
+FORTRAN_SUBR ( RBRINV, rbrinv,
+ ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ),
+ ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ),
+ ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ) ) {
+mat44 A1,AI1;
+int i,j,k;
+
+ k = 0;
+ for (j=0;j<4;j++)
+ for (i=0;i<4;i++)
+ A1[j][i] = A[k++];
+
+ Mat4Inverse ( A1,AI1 );
+
+ k = 0;
+ for (j=0;j<4;j++)
+ for (i=0;i<4;i++)
+ AI[k++] = AI1[j][i];
+
+}
+*/
+/*
+FORTRAN_SUBR ( RES3TO1, res3to1,
+ ( // lengths-at-end list
+ mmdb::machine::fpstr ResNm3, // 3-char name, 4th char
+ // will be set blank
+ mmdb::machine::fpstr ResNm1, // 1-char name
+ int ResNm3_len, // fortran-hidden length of ResNm3
+ int ResNm1_len // fortran-hidden length of ResNm3
+ ), ( // lengths-in-structure list
+ mmdb::machine::fpstr ResNm3, mmdb::machine::fpstr ResNm1
+ ), ( // lengths-follow list
+ mmdb::machine::fpstr ResNm3, int ResNm3_len,
+ mmdb::machine::fpstr ResNm1, int ResNm1_len
+ )
+ ) {
+int i;
+
+ if (FTN_STR(ResNm3)[0]==' ') {
+ for (i=0;i<nResNames;i++)
+ if ((FTN_STR(ResNm3)[0]==ResidueName[i][0]) &&
+ (FTN_STR(ResNm3)[1]==ResidueName[i][1]) &&
+ (FTN_STR(ResNm3)[2]==ResidueName[i][2])) {
+ FTN_STR(ResNm1)[0] = ResidueName1[i];
+ return;
+ }
+ FTN_STR(ResNm1)[0] = ResidueName1[nResNames-1];
+ return;
+ }
+
+ if (FTN_STR(ResNm1)[0]==' ') {
+ for (i=0;i<nResNames;i++)
+ if (FTN_STR(ResNm1)[0]==ResidueName1[i]) {
+ FTN_STR(ResNm3)[0] = ResidueName[i][0];
+ FTN_STR(ResNm3)[1] = ResidueName[i][1];
+ FTN_STR(ResNm3)[2] = ResidueName[i][2];
+ FTN_STR(ResNm3)[3] = ' ';
+ return;
+ }
+ FTN_STR(ResNm3)[0] = ResidueName[nResNames-1][0];
+ FTN_STR(ResNm3)[1] = ResidueName[nResNames-1][1];
+ FTN_STR(ResNm3)[2] = ResidueName[nResNames-1][2];
+ FTN_STR(ResNm3)[3] = ' ';
+ return;
+ }
+
+}
+*/
+
+static mmdb::pstr MSG_NoChannel = mmdb::pstr("unassigned unit");
+static mmdb::pstr MSG_NoFile = mmdb::pstr("unassigned unit or disposed file");
+static mmdb::pstr MSG_NoLogicalName = mmdb::pstr("logical name does not exist");
+
+static mmdb::pstr MSG_CantOpenFile = mmdb::pstr("cannot open a file");
+static mmdb::pstr MSG_WrongInteger = mmdb::pstr("unrecognized integer at reading a file");
+static mmdb::pstr MSG_WrongModelNo = mmdb::pstr("wrong model number read from a file");
+static mmdb::pstr MSG_DuplicatedModel = mmdb::pstr("duplicated model number");
+static mmdb::pstr MSG_ForeignFile = mmdb::pstr("unknown file format");
+static mmdb::pstr MSG_WrongEdition = mmdb::pstr("unknown file version");
+
+static mmdb::pstr MSG_ATOM_Unrecognd = mmdb::pstr("unrecognized data in coordinate section");
+static mmdb::pstr MSG_ATOM_AlreadySet = mmdb::pstr("duplicate atom serial number");
+static mmdb::pstr MSG_ATOM_NoResidue = mmdb::pstr("residue for atom cannot be found");
+static mmdb::pstr MSG_ATOM_Unmatch = mmdb::pstr("ambiguous data in coordinate section");
+
+static mmdb::pstr MSG_NoAdvance = mmdb::pstr("atom position was not advanced");
+static mmdb::pstr MSG_EmptyPointer = mmdb::pstr("atom was not allocated");
+static mmdb::pstr MSG_NoMatrices = mmdb::pstr("no coordinate transformation matrices");
+
+static mmdb::pstr MSG_NoCoordinates = mmdb::pstr("no atom coordinates set");
+
+static mmdb::pstr MSG_Disagreement = mmdb::pstr("ambiguous cell parameters");
+static mmdb::pstr MSG_NoOrthCode = mmdb::pstr("no orthogonalization code");
+static mmdb::pstr MSG_NoCheck = mmdb::pstr("missing check of cell parameters");
+
+static mmdb::pstr MSG_NoCellParams = mmdb::pstr("no cell parameters");
+
+static mmdb::pstr MSG_NotACIFFile = mmdb::pstr("not a CIF file: 'data_' tag missing");
+static mmdb::pstr MSG_NoData = mmdb::pstr("expected data is not met at reading a file");
+static mmdb::pstr MSG_UnrecognCIFItems = mmdb::pstr("unrecognized CIF items (syntax error?)");
+static mmdb::pstr MSG_MissingCIFField = mmdb::pstr("missing CIF data field");
+static mmdb::pstr MSG_EmptyCIFLoop = mmdb::pstr("CIF loop does not contain any data");
+static mmdb::pstr MSG_UnexpEndOfCIF = mmdb::pstr("unexpected end of CIF file");
+static mmdb::pstr MSG_MissgCIFLoopField = mmdb::pstr("CIF loop is incomplete");
+static mmdb::pstr MSG_NotACIFStructure = mmdb::pstr("wrong use of CIF structure (as a loop?)");
+static mmdb::pstr MSG_NotACIFLoop = mmdb::pstr("wrong use of CIF loop (as a structure?)");
+static mmdb::pstr MSG_WrongReal = mmdb::pstr("unrecognized real at reading a file");
+
+static mmdb::pstr MSG_WrongChainID = mmdb::pstr("Wrong or inconsistent chain ID");
+static mmdb::pstr MSG_WrongEntryID = mmdb::pstr("Wrong or insonsistent entry ID");
+static mmdb::pstr MSG_SEQRES_serNum = mmdb::pstr("Wrong serial number in SEQRES");
+static mmdb::pstr MSG_SEQRES_numRes = mmdb::pstr("Wrong number of residues in SEQRES");
+static mmdb::pstr MSG_SEQRES_extraRes = mmdb::pstr("Extra residues in SEQRES");
+static mmdb::pstr MSG_NCSM_Unrecogn = mmdb::pstr("Unrecognized item in NCSM cards");
+static mmdb::pstr MSG_NCSM_AlreadySet = mmdb::pstr("Attempt to reset NCSM");
+static mmdb::pstr MSG_NCSM_WrongSerial = mmdb::pstr("Wrong serial number in NCSM cards");
+static mmdb::pstr MSG_NCSM_UnmatchIG = mmdb::pstr("Unmatched IG parameter in NCSM cards");
+static mmdb::pstr MSG_NoModel = mmdb::pstr("MMDB's error in structuring models");
+static mmdb::pstr MSG_NoSheetID = mmdb::pstr("No sheet ID on SHEET card(s)");
+static mmdb::pstr MSG_WrongSheetID = mmdb::pstr("Wrong sheet ID on SHEET card(s)");
+static mmdb::pstr MSG_WrongStrandNo = mmdb::pstr("Wrong strand no. on SHEET card(s)");
+static mmdb::pstr MSG_WrongNofStrands = mmdb::pstr("Wrong number of strands in sheet");
+static mmdb::pstr MSG_WrongSheetOrder = mmdb::pstr("Wrong sheet ordering");
+static mmdb::pstr MSG_HBondInconsistency = mmdb::pstr("Inconsistency in H-bonds");
+static mmdb::pstr MSG_EmptyResidueName = mmdb::pstr("No (blank) residue name");
+static mmdb::pstr MSG_DuplicateSeqNum = mmdb::pstr("Duplicated sequence number and insertion code");
+static mmdb::pstr MSG_GeneralError1 = mmdb::pstr("MMDB's general error #1");
+
+
+static mmdb::pstr MSG_Error1 = mmdb::pstr("internal error #1 -- report to developer");
+static mmdb::pstr MSG_Error2 = mmdb::pstr("internal error #2 -- report to developer");
+static mmdb::pstr MSG_Error3 = mmdb::pstr("internal error #3 -- report to developer");
+
+static mmdb::pstr MSG_Unknown = mmdb::pstr("unknown return code");
+
+
+#define nWarnings 7
+
+static int RWBWarCode[nWarnings] = {
+ RWBWAR_RewOutput,
+ RWBWAR_FileTop,
+ RWBWAR_WrongSerial,
+ RWBWAR_UnkFormFactor,
+ RWBWAR_AmbFormFactor,
+ RWBWAR_NoOccupancy,
+ RWBWAR_NoTempFactor
+};
+
+static mmdb::pstr RWBWarning[nWarnings] = {
+ mmdb::pstr("output file rewind"),
+ mmdb::pstr("rewind or backspace at top of file"),
+ mmdb::pstr("atom serial number does not match position"),
+ mmdb::pstr("unknown form factor encountered"),
+ mmdb::pstr("ambiguous form factor encountered"),
+ mmdb::pstr("occupancy was not set"),
+ mmdb::pstr("temperature factor was not set")
+};
+
+
+
+FORTRAN_SUBR ( RBERRSTOP, rberrstop,
+ ( // lengths-at-end list
+ int * iPlace, // (unique) identificator inside an application
+ int * iRet, // return code to check
+ int * iUnit, // unit number
+ int * iStop // if 0 then stop if error
+ ), ( // lengths-in-structure list
+ int * iPlace, int * iRet,
+ int * iUnit, int * iStop
+ ), ( // lengths-follow list
+ int * iPlace, int * iRet,
+ int * iUnit, int * iStop
+ ) ) {
+int i,k,lcount;
+mmdb::pstr Msg;
+char ErrLine[500];
+
+ strcpy ( ErrLine,"" );
+ lcount = -11;
+ k = GetChannel(*iUnit);
+
+ switch (*iRet) {
+
+ case RWBERR_Ok : return;
+
+ case RWBERR_NoChannel : Msg = MSG_NoChannel; break;
+ case RWBERR_NoFile : Msg = MSG_NoFile; break;
+ case RWBERR_NoLogicalName : Msg = MSG_NoLogicalName; break;
+ case RWBERR_CantOpenFile : Msg = MSG_CantOpenFile; break;
+
+
+ case RWBERR_WrongInteger : Msg = MSG_WrongInteger; break;
+ case RWBERR_WrongModelNo : Msg = MSG_WrongModelNo; break;
+ case RWBERR_DuplicatedModel : Msg = MSG_DuplicatedModel; break;
+
+ case RWBERR_ForeignFile : Msg = MSG_ForeignFile; break;
+ case RWBERR_WrongEdition : Msg = MSG_WrongEdition; break;
+
+ case RWBERR_ATOM_Unrecognd : Msg = MSG_ATOM_Unrecognd; break;
+ case RWBERR_ATOM_AlreadySet : Msg = MSG_ATOM_AlreadySet; break;
+ case RWBERR_ATOM_NoResidue : Msg = MSG_ATOM_NoResidue; break;
+ case RWBERR_ATOM_Unmatch : Msg = MSG_ATOM_Unmatch; break;
+
+ case RWBERR_NoAdvance : Msg = MSG_NoAdvance; break;
+ case RWBERR_EmptyPointer : Msg = MSG_EmptyPointer; break;
+ case RWBERR_NoMatrices : Msg = MSG_NoMatrices; break;
+
+ case RWBERR_NoCoordinates : Msg = MSG_NoCoordinates; break;
+
+ case RWBERR_Disagreement : Msg = MSG_Disagreement; break;
+ case RWBERR_NoOrthCode : Msg = MSG_NoOrthCode; break;
+ case RWBERR_NoCheck : Msg = MSG_NoCheck; break;
+
+ case RWBERR_NoCellParams : Msg = MSG_NoCellParams; break;
+
+ case RWBERR_NotACIFFile : Msg = MSG_NotACIFFile; break;
+ case RWBERR_NoData : Msg = MSG_NoData; break;
+ case RWBERR_UnrecognCIFItems : Msg = MSG_UnrecognCIFItems; break;
+ case RWBERR_MissingCIFField : Msg = MSG_MissingCIFField; break;
+ case RWBERR_EmptyCIFLoop : Msg = MSG_EmptyCIFLoop; break;
+ case RWBERR_UnexpEndOfCIF : Msg = MSG_UnexpEndOfCIF; break;
+ case RWBERR_MissgCIFLoopField : Msg = MSG_MissgCIFLoopField; break;
+ case RWBERR_NotACIFStructure : Msg = MSG_NotACIFStructure; break;
+ case RWBERR_NotACIFLoop : Msg = MSG_NotACIFLoop; break;
+ case RWBERR_WrongReal : Msg = MSG_WrongReal; break;
+
+ case RWBERR_WrongChainID : Msg = MSG_WrongChainID; break;
+ case RWBERR_WrongEntryID : Msg = MSG_WrongEntryID; break;
+ case RWBERR_SEQRES_serNum : Msg = MSG_SEQRES_serNum; break;
+ case RWBERR_SEQRES_numRes : Msg = MSG_SEQRES_numRes; break;
+ case RWBERR_SEQRES_exraRes : Msg = MSG_SEQRES_extraRes; break;
+ case RWBERR_NCSM_Unrecogn : Msg = MSG_NCSM_Unrecogn; break;
+ case RWBERR_NCSM_AlreadySet : Msg = MSG_NCSM_AlreadySet; break;
+ case RWBERR_NCSM_WrongSerial : Msg = MSG_NCSM_WrongSerial; break;
+ case RWBERR_NCSM_UnmatchIG : Msg = MSG_NCSM_UnmatchIG; break;
+ case RWBERR_NoModel : Msg = MSG_NoModel; break;
+ case RWBERR_NoSheetID : Msg = MSG_NoSheetID; break;
+ case RWBERR_WrongSheetID : Msg = MSG_WrongSheetID; break;
+ case RWBERR_WrongStrandNo : Msg = MSG_WrongStrandNo; break;
+ case RWBERR_WrongNofStrands : Msg = MSG_WrongNofStrands; break;
+ case RWBERR_WrongSheetOrder : Msg = MSG_WrongSheetOrder; break;
+ case RWBERR_HBondInconsis : Msg = MSG_HBondInconsistency; break;
+ case RWBERR_EmptyResidueName : Msg = MSG_EmptyResidueName; break;
+ case RWBERR_DuplicateSeqNum : Msg = MSG_DuplicateSeqNum; break;
+ case RWBERR_GeneralError1 : Msg = MSG_GeneralError1; break;
+
+ case RWBERR_Error1 : Msg = MSG_Error1; break;
+ case RWBERR_Error2 : Msg = MSG_Error2; break;
+ case RWBERR_Error3 : Msg = MSG_Error3; break;
+
+ default :
+ if ((*iRet & RWBWAR_Warning)==RWBWAR_Warning) {
+ Msg = NULL;
+ printf ( "\n\n *** Warning(s): point code unit function\n" );
+ printf ( " *** %5i %4i %4i %s\n",
+ *iPlace,*iRet,*iUnit,LastFunc );
+ if (k>=0)
+ printf ( " *** file : %s\n",channel[k]->FName );
+ for (i=0;i<nWarnings;i++)
+ if ((*iRet & RWBWarCode[i])==RWBWarCode[i]) {
+ Msg = RWBWarning[i];
+ printf ( " *** warning: %s\n",Msg );
+ if ((*iRet & RWBWAR_WrongSerial)==RWBWAR_WrongSerial) {
+ if (k>0)
+ printf ( " *** position %i, serial number %i\n",
+ channel[k]->fPos,LastSer );
+ else
+ printf ( " *** position unavailable, serial number %i\n",
+ LastSer );
+ }
+ }
+ if (!Msg)
+ printf ( " *** warning: unknown warning code" );
+ return;
+ } else
+ Msg = MSG_Unknown;
+ }
+
+ if ((k>=0) && (
+ ((*iRet<=RWBERR_WrongInteger) && (*iRet>=RWBERR_DuplicatedModel)) ||
+ ((*iRet<=RWBERR_ATOM_Unrecognd) && (*iRet>=RWBERR_ATOM_Unmatch)) ||
+ ((*iRet<=RWBERR_NoData) && (*iRet>=RWBERR_DuplicateSeqNum))
+ ))
+ channel[k]->GetInputBuffer ( ErrLine,lcount );
+
+ printf ( " \n *** RWBROOK error: point code unit function\n" );
+ printf ( " *** %5i %4i %4i %s\n",*iPlace,*iRet,
+ *iUnit,LastFunc );
+ k = GetChannel(*iUnit);
+ if (k>=0)
+ printf ( " *** file : %s\n",channel[k]->FName );
+
+ printf ( " *** reason : %s\n",Msg );
+ if (lcount>=0)
+ printf ( " *** at input line #%i:\n"
+ " %s\n",lcount,ErrLine );
+ else if (lcount==-1)
+ printf ( " *** at taking the following data from CIF:\n"
+ " %s\n",ErrLine );
+
+ if (*iStop==0) { // will stop it
+ printf ( " *** Execution stopped.\n \n" );
+ FORTRAN_CALL ( MMDB_F_QUIT, mmdb_f_quit,(),(),() );
+ // xyzquit_();
+ exit(0);
+ } else // just warn, but no guarantee that it will not crash
+ printf ( " *** continue running, may crash ...\n \n" );
+
+}
+
+
+
+FORTRAN_SUBR ( RBCHECKERR, rbcheckerr,
+ ( // lengths-at-end list
+ int * iPlace, // (unique) identificator inside an application
+ int * iStop // if 0 then stop if error
+ ), ( // lengths-in-structure list
+ int * iPlace, int * iStop
+ ), ( // lengths-follow list
+ int * iPlace, int * iStop
+ ) ) {
+ FORTRAN_CALL ( RBERRSTOP, rberrstop,
+ ( iPlace,&LastRC,&LastUnit,iStop ),
+ ( iPlace,&LastRC,&LastUnit,iStop ),
+ ( iPlace,&LastRC,&LastUnit,iStop ) );
+}
+
+
+/* hybrid-36 encoder: converts integer value to string result
+
+ iwidth: must be 4 (e.g. for residue sequence numbers)
+ or 5 (e.g. for atom serial numbers)
+
+ value: integer value to be converted
+
+ strval: char array containing string result
+*/
+
+FORTRAN_SUBR ( HY36ENCODE_F, hy36encode_f,
+ (const int *iwidth, int *value,
+ mmdb::machine::fpstr strval, int strval_len),
+ (const int *iwidth, int *value,
+ mmdb::machine::fpstr strval),
+ (const int *iwidth, int *value,
+ mmdb::machine::fpstr strval, int strval_len))
+{
+ unsigned width;
+ char result[6];
+
+ width = (unsigned) *iwidth;
+
+ if (hy36encode(width, *value, result)) {
+ printf("problem in hy36encode_f! \n");
+ }
+ mmdb::strcpy_ns(FTN_STR(strval),result,FTN_LEN(strval));
+
+}
+
+/* hybrid-36 decoder: converts string s to integer result
+
+ iwidth: must be 4 (e.g. for residue sequence numbers)
+ or 5 (e.g. for atom serial numbers)
+
+ strval: string to be converted
+
+ value: integer holding the conversion result
+*/
+
+
+FORTRAN_SUBR ( HY36DECODE_F, hy36decode_f,
+ (const int *iwidth,
+ mmdb::machine::fpstr strval, int *value, int strval_len),
+ (const int *iwidth,
+ mmdb::machine::fpstr strval, int *value),
+ (const int *iwidth,
+ mmdb::machine::fpstr strval, int strval_len, int *value))
+{ UNUSED_ARGUMENT(strval);
+ unsigned width;
+ size_t length = FTN_LEN(strval);
+ char* s;
+
+ width = (unsigned) *iwidth;
+ s = (char *) malloc((length+1)*sizeof(char));
+ s[length] = '\0';
+
+ if (hy36decode(width, s, width, value)) {
+ printf("problem in hy36decode_f! \n");
+ }
+
+}
+
diff --git a/mmdb2/mmdb_rwbrook.h b/mmdb2/mmdb_rwbrook.h
new file mode 100644
index 0000000..2f59f5f
--- /dev/null
+++ b/mmdb2/mmdb_rwbrook.h
@@ -0,0 +1,1600 @@
+// $Id: mmdb_rwbrook.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 16.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_RWBrook <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB), "new rwbrook"
+// ~~~~~~~~~
+// **** Functions : mmdb_f_init_ ( initializer )
+// ~~~~~~~~~~~ mmdb_f_quit_ ( disposer )
+// autoserials_ ( switch to the autoserials regime )
+// setreadcoords_ ( switch for reading coordinates )
+// simrwbrook_ ( simulates old RWBROOK printout )
+// mmdb_f_openl_ ( associates a unit with a file )
+// mmdb_f_open_ ( associates a unit with a file )
+// mmdb_f_copy_ ( copies contents of units )
+// mmdb_f_delete_ ( deletes part of a unit )
+// mmdb_f_settype_ ( changes type of file and r/w mode )
+// mmdb_f_setname_ ( changes file name )
+// mmdb_f_write_ ( writes a data structure into file )
+// mmdb_f_close_ ( closes and disposes a data str-re )
+// mmdb_f_advance_ ( advances the internal pointer )
+// mmdb_f_rewd_ ( sets internal pointer on the top )
+// mmdb_f_bksp_ ( shifts int-l pointer 1 atom back )
+// mmdb_f_atom_ ( reads/writes atom properties )
+// mmdb_f_coord_ ( reads/writes atom coordinates )
+// mmdb_f_setcell_ ( sets the crystal cell parameters )
+// mmdb_f_wbspgrp_ ( sets the space group )
+// mmdb_f_rbspgrp_ ( gets the space group )
+// mmdb_f_wbcell_ ( sets the crystal cell parameters )
+// mmdb_f_rbcell_ ( gets the crystal cell parameters )
+// mmdb_f_rbcelln_ ( gets the crystal cell parameters )
+// mmdb_f_rbrcel_ ( gets the recipricol cell )
+// mmdb_f_rborf_ ( returns or fill transf. matrices )
+// mmdb_f_orthmat_ ( calc. standard othogonalisations )
+// mmdb_f_cvanisou_ ( converts between cryst-c units )
+// mmdb_f_wremark_ ( writes a remark statement )
+// mmdb_f_setter
+// mmdb_f_sethet
+// rberrstop_ ( error messenger )
+// rbcheckerr_ ( a simple error messenger )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+
+#ifndef __MMDB_RWBrook__
+#define __MMDB_RWBrook__
+
+#include "mmdb_mattype.h"
+#include "mmdb_machine_.h"
+
+
+// ****** mmdb_rwbrook error codes
+
+enum RWB_ERROR {
+
+ RWBERR_Ok = 0,
+ RWBERR_NoChannel = -1,
+ RWBERR_NoFile = -2,
+ RWBERR_NoLogicalName = -3,
+
+ RWBERR_CantOpenFile = -4,
+ RWBERR_WrongInteger = -5,
+ RWBERR_WrongModelNo = -6,
+ RWBERR_DuplicatedModel = -7,
+ RWBERR_ForeignFile = -8,
+ RWBERR_WrongEdition = -9,
+
+ RWBERR_ATOM_Unrecognd = -10,
+ RWBERR_ATOM_AlreadySet = -11,
+ RWBERR_ATOM_NoResidue = -12,
+ RWBERR_ATOM_Unmatch = -13,
+
+ RWBERR_NoAdvance = -14,
+ RWBERR_EmptyPointer = -15,
+ RWBERR_NoMatrices = -16,
+
+ RWBERR_NoCoordinates = -17,
+
+ RWBERR_Disagreement = -18,
+ RWBERR_NoOrthCode = -19,
+ RWBERR_NoCheck = -20,
+
+ RWBERR_NoCellParams = -21,
+
+ RWBERR_NotACIFFile = -22,
+ RWBERR_NoData = -23,
+ RWBERR_UnrecognCIFItems = -24,
+ RWBERR_MissingCIFField = -25,
+ RWBERR_EmptyCIFLoop = -26,
+ RWBERR_UnexpEndOfCIF = -27,
+ RWBERR_MissgCIFLoopField = -28,
+ RWBERR_NotACIFStructure = -29,
+ RWBERR_NotACIFLoop = -30,
+ RWBERR_WrongReal = -31,
+
+ RWBERR_WrongChainID = -32,
+ RWBERR_WrongEntryID = -33,
+ RWBERR_SEQRES_serNum = -34,
+ RWBERR_SEQRES_numRes = -35,
+ RWBERR_SEQRES_exraRes = -36,
+ RWBERR_NCSM_Unrecogn = -37,
+ RWBERR_NCSM_AlreadySet = -38,
+ RWBERR_NCSM_WrongSerial = -39,
+ RWBERR_NCSM_UnmatchIG = -40,
+ RWBERR_NoModel = -41,
+ RWBERR_NoSheetID = -42,
+ RWBERR_WrongSheetID = -43,
+ RWBERR_WrongStrandNo = -44,
+ RWBERR_WrongNofStrands = -45,
+ RWBERR_WrongSheetOrder = -46,
+ RWBERR_HBondInconsis = -47,
+ RWBERR_EmptyResidueName = -48,
+ RWBERR_DuplicateSeqNum = -49,
+ RWBERR_GeneralError1 = -50,
+
+ RWBERR_Error1 = -101,
+ RWBERR_Error2 = -102,
+ RWBERR_Error3 = -103
+
+};
+
+// ***** mmdb_rwbrook warning flags
+// 0x00004000 means "it's a warning"
+
+enum RWB_WARNING {
+ RWBWAR_Warning = 0x00004000,
+ RWBWAR_RewOutput = 0x00004010,
+ RWBWAR_FileTop = 0x00004020,
+ RWBWAR_WrongSerial = 0x00004040,
+ RWBWAR_UnkFormFactor = 0x00004080,
+ RWBWAR_AmbFormFactor = 0x00004100,
+ RWBWAR_NoOccupancy = 0x00004200,
+ RWBWAR_NoTempFactor = 0x00004400
+};
+
+// ------------------------------------------------------------------
+
+// mmdb_f_init_() makes a general initialization of the file system.
+// It must be called ONLY ONCE from the top of an application.
+
+// FORTRAN equivalent: subroutine MMDB_F_Init
+// ~~~~~~~~~~~~~~~~~~~
+
+FORTRAN_SUBR ( MMDB_F_INIT, mmdb_f_init, (),(),() );
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_quit_() disposes the file system. A correct use assumes that
+// it will be called before an application quits.
+
+// FORTRAN equivalent: subroutine MMDB_F_Quit
+// ~~~~~~~~~~~~~~~~~~~
+
+FORTRAN_SUBR ( MMDB_F_QUIT, mmdb_f_quit, (),(),() );
+
+
+// ------------------------------------------------------------------
+
+// autoserials_(..) switches On/Off the regime of automatical
+// generation of atom serial numbers at reading from PDB ASCII file.
+// The autoserials regime is On if iOnOff parameter is set to
+// non-zero, and the regime is turned Off otherwise. The setting
+// will last until next call to autoserials_(..)
+//
+// When this regime is Off (default state), all atom serial
+// numbers are expected to be in strictly incremental order and
+// any deviation from this rule will cause end of reading and
+// MMDB_F_Open_(..) will issue the RWBERR_AlreadySet error code. If
+// this code is then passed to error messengers (rberrstop_(..) or
+// rbcheckerr_(..)) the application will stop. It is Ok, however,
+// for serial numbers to increment by 2 or more.
+//
+// When the autoserials regime is On, MMDB_F_Open_(..) does not pay
+// attention to the serial numbers and generates them for each
+// atom in strict incremental-by-one. This will work correctly only
+// if all atom records ("ATOM"/"HETATM", "SIGATM", "ANISOU" and
+// "SIGUIJ") are grouped, for every atom, as they should (precisely,
+// "ATOM" or "HETATM" opens the group, then "SIGATM", "ANISOU" and
+// "SIGUIJ" should follow until next "ATOM"/"HETATM" is met).
+
+// FORTRAN equivalent: subroutine AutoSerials ( iOnOff )
+// ~~~~~~~~~~~~~~~~~~~ integer iOnOff
+
+FORTRAN_SUBR ( AUTOSERIALS,autoserials,
+ ( int * iOnOff ),
+ ( int * iOnOff ),
+ ( int * iOnOff ) );
+
+
+// ------------------------------------------------------------------
+
+// setreadcoords_(..) switches On/Off the reading of atomic
+// coordinates when mmdb_f_open_ is called for input. The coordinates
+// will be read if iOnOff parameter is set to non-zero, otherwise
+// the reading will stop on the coordinate section of PDB file.
+// The setting will last until the next call to setreadcoords_(..).
+//
+// By default, the coordinates are read.
+//
+// FORTRAN equivalent: subroutine SetReadCoords ( iOnOff )
+// ~~~~~~~~~~~~~~~~~~~ integer iOnOff
+
+FORTRAN_SUBR ( SETREADCOORDS,setreadcoords,
+ ( int * iOnOff ),
+ ( int * iOnOff ),
+ ( int * iOnOff ) );
+
+
+// ------------------------------------------------------------------
+
+// simrwbrook_(..) switches On/Off the regime of exact following
+// the old fortran RWBROOK's way of issuing messages and warnings.
+//
+// By default, this regime is switched off, which supresses all
+// messages from mmdb_rwbrook unless directly ordered or catastrophic.
+// Switching this regime on will make the printout of converted
+// programs significantly closer to that resulting from the use of
+// old fortran RWBROOK package. The setting will last until the
+// next call to simrwbrook_(..).
+//
+// FORTRAN equivalent: subroutine SimRWBROOK ( iOnOff )
+// ~~~~~~~~~~~~~~~~~~~ integer iOnOff
+
+FORTRAN_SUBR ( SIMRWBROOK,simrwbrook,
+ ( int * iOnOff ),
+ ( int * iOnOff ),
+ ( int * iOnOff ) );
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_open_(..) associates a coordinate file with channel number
+// given in iUnit. If iUnit was previously associated with another
+// or the same file, the file gets complete logical reinitialization
+// which means that all previous modifications to the file are lost
+// unless stored on disk with mmdb_f_write_(..) or mmdb_f_close_(..).
+//
+// If the file is to be opened for input (RWStat is set to
+// "INPUT"), all contents of the file is read into memory. It may be
+// then modified and written back into a file (same or different).
+//
+// If the file is to be opened for output (RWStat is set to
+// "OUTPUT"), no file is physically opened, and only empty data
+// structure is created in the memory. It may then be added with the
+// data and stored in a disk file.
+//
+// If FType is set to "PDB" or " ", the physical file is assumed
+// to be read or written in the PDB format. "CIF" option is reserved
+// for mmCIF files and is not realized at present. "BIN" means
+// binary format. Note that both file name and file type may be
+// changed before writting the file (see mmdb_f_setname_(..) and
+// mmdb_f_settype_(..)).
+//
+// mmdb_f_open(..) sets an internal pointer to "before the first"
+// atom in the file (therefore it should be advanced to get access
+// to the first atom, see mmdb_f_advance1_(..)). This pointer is used
+// for getting atomic coordinates and other atomic characteristics
+// from the file structure or for storing them into the structure.
+// The pointer may be advanced, backspaced or set to a specific
+// position in the file structure (see below).
+//
+// iRet returns the error code (defined above). Extended
+// information on the error may be then obtained through the
+// geterror_(..) function immediately after return from
+// mmdb_f_open_(..).
+
+// FORTRAN equivalent: subroutine MMDB_F_Open ( LName,RWStat,FType,
+// ~~~~~~~~~~~~~~~~~~~ iUnit,iRet )
+// character*(*) LName,RWStat,FType
+// integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_OPEN, mmdb_f_open,
+ ( // lengths-at-end list
+ mmdb::machine::fpstr LName, // logical name
+ mmdb::machine::fpstr RWStat, // "INPUT" or "OUTPUT"
+ mmdb::machine::fpstr FType, // "PDB", "CIF", "BIN" or " "
+ int * iUnit, // channel number
+ int * iRet, // returns error code
+ int LName_len, // fortran-hidden length of LName
+ int RWStat_len, // fortran-hidden length of RWStat
+ int FType_len // fortran-hidden length of FType
+ ), ( // lengths-in-structure list
+ mmdb::machine::fpstr LName,
+ mmdb::machine::fpstr RWStat,
+ mmdb::machine::fpstr FType,
+ int * iUnit, int * iRet
+ ), ( // lengths-follow list
+ mmdb::machine::fpstr LName, int LName_len,
+ mmdb::machine::fpstr RWStat, int RWStat_len,
+ mmdb::machine::fpstr FType, int FType_len,
+ int * iUnit, int * iRet
+ ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_open1_(..) is equivalent to mmdb_f_open_(..) but takes directly
+// the file name (FName) instead of logical name (LName).
+//
+// FORTRAN equivalent: subroutine MMDB_F_Open1 ( FName,RWStat,FType,
+// ~~~~~~~~~~~~~~~~~~~ iUnit,iRet )
+// character*(*) FName,RWStat,FType
+// integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_OPEN1, mmdb_f_open1,
+ ( // lengths-at-end list
+ mmdb::machine::fpstr FName, // file name
+ mmdb::machine::fpstr RWStat, // "INPUT" or "OUTPUT"
+ mmdb::machine::fpstr FType, // "PDB", "CIF", "BIN" or " "
+ int * iUnit, // channel number
+ int * iRet, // returns error code
+ int FName_len, // fortran-hidden length of FName
+ int RWStat_len, // fortran-hidden length of RWStat
+ int FType_len // fortran-hidden length of FType
+ ), ( // lengths-in-structure list
+ mmdb::machine::fpstr FName,
+ mmdb::machine::fpstr RWStat,
+ mmdb::machine::fpstr FType,
+ int * iUnit, int * iRet
+ ), ( // lengths-follow list
+ mmdb::machine::fpstr FName, int FName_len,
+ mmdb::machine::fpstr RWStat, int RWStat_len,
+ mmdb::machine::fpstr FType, int FType_len,
+ int * iUnit, int * iRet
+ ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_copy_(..) copies the specified part(s) of iUnit2 into iUnit1.
+// All data which contained in the corresponding part(s) of iUnit1
+// before the copying, is destroyed.
+//
+// FORTRAN equivalent: subroutine MMDB_F_Copy ( iUnit1,iUnit2,
+// ~~~~~~~~~~~~~~~~~~~ copyKey,iRet )
+// integer iUnit1,iUnit2,copyKey,iRet
+
+FORTRAN_SUBR ( MMDB_F_COPY, mmdb_f_copy,
+ ( // lengths-at-end list
+ int * iUnit1, // destination unit
+ int * iUnit2, // source unit
+ int * copyKey, // copy key:
+ // = 1 copy all
+ // = 2 copy all except coordinates
+ // = 3 copy title section only
+ // = 4 copy crystallographic
+ // section only
+ // = 5 copy coordinate section only
+ // any other value does not do anything
+ int * iRet // return code:
+ // =0 if success
+ // =RWBERR_NoChannel if a unit
+ // does not exist
+ // =RWBERR_NoFile if a unit
+ // was not opened
+ ), ( // lengths-in-structure list
+ int * iUnit1, int * iUnit2,
+ int * copyKey, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit1, int * iUnit2,
+ int * copyKey, int * iRet
+ ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_delete_(..) deletes the specified parts of iUnit-th unit.
+// The delete keys are exactly the same as copy keys in mmdb_f_copy_(..).
+//
+// FORTRAN equivalent: subroutine MMDB_F_Delete ( iUnit1,iUnit2,
+// ~~~~~~~~~~~~~~~~~~~ CopyAtoms,iRet )
+// integer iUnit1,iUnit2,CopyAtoms,iRet
+
+FORTRAN_SUBR ( MMDB_F_DELETE, mmdb_f_delete,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ int * delKey, // delete key:
+ // = 1 delete all
+ // = 2 delete all except coordinates
+ // = 3 delete title section only
+ // = 4 delete crystallographic
+ // section only
+ // = 5 delete coordinate section only
+ // any other value does not do anything
+ int * iRet // return code:
+ // =0 if success
+ // =RWBERR_NoChannel if a unit
+ // does not exist
+ // =RWBERR_NoFile if a unit
+ // was not opened
+ ), ( // lengths-in-structure list
+ int * iUnit, int * delKey, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, int * delKey, int * iRet
+ ) );
+
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_settype_(..) changes the type and/or the read/write mode of
+// a unit iUnit, previously initialized with mmdb_f_open_(..). The file
+// is not read from or purged onto disk, no data change occurs.
+//
+// iRet returns either RWBERR_NoChannel if the unit was not
+// previously initialized by mmdb_f_open_(..), or RWBERR_Ok in the case
+// of success.
+
+// FORTRAN equivalent: subroutine MMDB_F_SetType ( iUnit,FType,
+// ~~~~~~~~~~~~~~~~~~~ RWState,iRet )
+// character*(*) FType,RWState
+// integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_SETTYPE, mmdb_f_settype,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::fpstr FType, // "PDB", "CIF", "BIN" or " "
+ mmdb::machine::fpstr RWStat, // "INPUT" or "OUTPUT"
+ int * iRet, // returns -1 if unit not found,
+ // otherwise 0
+ int FType_len, // fortran-hidden length of FType
+ int RWStat_len // fortran-hidden length of RWStat
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr FType,
+ mmdb::machine::fpstr RWStat, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::fpstr FType, int FType_len,
+ mmdb::machine::fpstr RWStat, int RWStat_len,
+ int * iRet
+ ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_setname_(..) changes the file name for a unit iUnit,
+// previously initialized with mmdb_f_open_(..). The file is not
+// read from or purged onto disk, no data change occurs.
+//
+// iRet returns either RWBERR_NoChannel if the unit was not
+// previously initialized by mmdb_f_open_(..), or RWBERR_Ok in the case
+// of success.
+
+// FORTRAN equivalent: subroutine MMDB_F_SetName ( iUnit,FName,
+// ~~~~~~~~~~~~~~~~~~~ iRet )
+// character*(*) FName
+// integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_SETNAME, mmdb_f_setname,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::fpstr FName, // file name
+ int * iRet, // returns -1 if unit not found,
+ // otherwise 0
+ int FName_len // fortran-hidden length of FName
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr FName, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::fpstr FName, int FName_len,
+ int * iRet
+ ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_write_(..) writes content of unit iUnit into a disk file.
+// iRet will be set to -1 if the unit was not previously opened with
+// mmdb_f_open_(..). If writting was successful, iRet is set to 0,
+// otherwise geterror(..) will return an information about the
+// error occured.
+//
+// Note that you may write even units associated with input in
+// call to mmdb_f_open(..). The file type does not change unless
+// explicitely changed with mmdb_f_settype_(..).
+
+// FORTRAN equivalent: subroutine MMDB_F_Write ( iUnit,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_WRITE, mmdb_f_write,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) );
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_close_(..) acts as mmdb_f_write_(..) if unit iUnit has been
+// associated with output in mmdb_f_open_(..) or in the call to
+// mmdb_f_settype(..). After writing the file, the unit iUnit is
+// completely disposed.
+// If unit iUnit is associated with input, mmdb_f_close_(..) merely
+// disposes it and all the information contained will be lost.
+
+// FORTRAN equivalent: subroutine MMDB_F_Close ( iUnit,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_CLOSE, mmdb_f_close,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) );
+
+
+// ------------------------------------------------------------------
+
+// If unit iUnit is associated with input, mmdb_f_advance_(..) sets
+// the internal pointer on the next atom in the file. The atom
+// properties may then be retrieved using mmdb_f_atom_(..) and
+// mmdb_f_coord_(..). If iTer is set to 0, then 'ter' cards are
+// completely ignored. If iTer is set to 1, then 'ter' card will
+// cause return with iRet=1 with internal pointer left on this 'ter'
+// card. iRet=2 mean end of file, and iRet=0 means that the pointer
+// was successfully advanced to the next atom.
+//
+// If unit iUnit is associated with output, mmdb_f_advance_(..)
+// merely advances the pointer. No actual change in the data
+// structure or on disk occurs. The new position will be filled with
+// atom data after execution of mmdb_f_atom_(..) and/or mmdb_f_coord_(..).
+// The pointer WILL NOT be advanced if none of these functions were
+// called since last advancement, in which case iRet will return
+// RWBERR_NoAdvance. After successfull advancement, iRet will
+// return 0.
+
+// FORTRAN equivalent: subroutine MMDB_F_Advance ( iUnit,iOut,iTer,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iOut,iTer,iRet
+
+// Relation to the former XYZAdvance fortran subroutione:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// subroutine XYZAdvance ( iUnit,iOut,iTer,*,* )
+// integer iRet
+// character*80 ErrLin
+// call MMDB_F_Advance ( iUnit,iOut,iTer,iRet )
+// if (iRet.eq.1) return 1
+// if (iRet.eq.2) return 2
+// if (iRet.eq.RWBERR_NoChannel) then
+// ErrLin = ' ERROR: in MMDB_F_ADVANCE file has not been opened'
+// call CCPErr ( 1,ErrLin )
+// endif
+// return
+// end
+//
+// where parameter iOut IS NOT USED.
+
+FORTRAN_SUBR ( MMDB_F_ADVANCE, mmdb_f_advance,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ int * iOut, // output echo file
+ int * iTer, // FLAG =1, return iRet=1 if 'ter' card found
+ // =0, do not return on 'ter' card
+ int * iRet // =0 if normal return
+ // =1 if return on 'ter' card (iTer=1)
+ // =2 if return on end of file
+ // =3 if return on 'hetatm' card
+ // =RWBERR_NoChannel if unit does not exist
+ // =RWBERR_NoAdvance if pointer was not
+ // advanced
+ ), ( // lengths-in-structure list
+ int * iUnit, int * iOut, int * iTer, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, int * iOut, int * iTer, int * iRet
+ ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_rewd_(..) sets the internal pointer to the "begining" of
+// the data structure associated with unit *iUnit. This means that
+// one should the "advance" it with mmdb_f_advance_(..) in order
+// to get access to the first atom.
+// iRet returns RWBERR_NoChannel if iUnit-th unit was not
+// initialized, RWBWAR_RewOutput if the unit was associated with
+// output, and 0 otherwise.
+
+// FORTRAN equivalent: subroutine MMDB_F_Rewd ( iUnit,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_REWD, mmdb_f_rewd,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_bksp_(..) shifts the internal pointer for one atom back in
+// the data structure associated with unit *iUnit. This means that
+// the combination of mmdb_f_advance1_(..) and mmdb_f_bksp_(..) leaves the
+// pointer unchanged.
+// iRet returns RWBERR_NoChannel if iUnit-th unit was not
+// initialized, and sets bit RWBWAR_RewOutput if the unit was
+// associated with output, RWBWAR_FileTop if the pointer is already
+// on the top of the structure, and 0 otherwise.
+
+// FORTRAN equivalent: subroutine MMDB_F_Bksp ( iUnit,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_BKSP, mmdb_f_bksp,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_seek_(..) sets the internal pointer to the specified
+// position. If fPos==0, *iRet will return bit RWBWAR_FileTop.
+// If unit iUnit is associated with input, iRet will return 2 if
+// fPos is given a value outside the file range, 1 if a 'ter' card
+// is met and 3 if a 'hetatm' card is met.
+// iRet returns RWBERR_NoChannel if iUnit-th unit was not
+// initialized, and RWBERR_EmptyPointer if fPos-th position in the
+// input file is not occupied.
+
+// FORTRAN equivalent: subroutine MMDB_F_Seek ( iUnit,fPos,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,fPos,iRet
+
+FORTRAN_SUBR ( MMDB_F_SEEK, mmdb_f_seek,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ int * fPos, // position to set
+ int * iRet // return code:
+ // 0 Ok
+ // 1 'ter' card met
+ // 2 end of file
+ // 3 'hetatm' card met
+ // <0 error:
+ // RWBERR_NoChannel
+ // iUnit was not
+ // initialized
+ // RWBERR_EmptyPointer
+ // fPos-th position
+ ), ( // lengths-in-structure list
+ int * iUnit, int * fPos, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, int * fPos, int * iRet
+ ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_atom_(..) reads or writes the atom name, residue name,
+// chain name and other parameters listed from/into the
+// data structure associated with the unit number iUnit (cf.
+// mmdb_f_open_(..)). The position in the structure is adjusted
+// with the help of mmdb_f_advance_(..), mmdb_f_rewd_(..) or
+// mmdb_f_bksp_(..).
+
+// FORTRAN equivalent: subroutine MMDB_F_Atom ( iUnit,iSer,AtNam,
+// ~~~~~~~~~~~~~~~~~~~ ResNam,ChnNam,iResN,ResNo,
+// InsCod,AltCod,SegID,IZ,ID,
+// iRet )
+// integer iUnit,iSer,iResN,IZ,iRet
+// character*(*) AtNam,ResNam,ChnNam,ResNo
+// character*(*) InsCod,AltCod,SegID,ID
+
+FORTRAN_SUBR ( MMDB_F_ATOM, mmdb_f_atom,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ int * iSer, // atom serial number
+ mmdb::machine::fpstr AtNam, // atom name (left justified)
+ mmdb::machine::fpstr ResNam, // residue name
+ mmdb::machine::fpstr ChnNam, // chain name
+ int * iResN, // residue number as an integer
+ mmdb::machine::fpstr ResNo, // residue number as character (input only)
+ mmdb::machine::fpstr InsCod, // the insertion code
+ mmdb::machine::fpstr AltCod, // the alternate conformation code
+ mmdb::machine::fpstr segID, // segment ID
+ int * IZ, // atomic number (input only, returned as
+ // 7 from ambiguous atoms)
+ mmdb::machine::fpstr ID, // atomic ID related to atomic number
+ // (element symbol right justified), plus
+ // the ionic state +2, +3 etc..
+ //
+ int * iRet, // returns
+ // RWBERR_NoChannel if iUnit was not
+ // initialized
+ // RWBERR_EmptyPointer if atom was not
+ // advanced
+ // RWBERR_Error1 internal error #1
+ // RWBERR_Error2 internal error #2
+ // RWBERR_Error3 internal error #3
+ //
+ // >=0 : success, warning flags:
+ // RWBWAR_WrongSerial if serial number
+ // differs from the position
+ // number in the file
+ // RWBWAR_UnkFormFactor unknown formfactor
+ // RWBWAR_AmbFormFactor ambiguous formfactor
+ //
+ int AtNam_len, // fortran-hidden length of AtNam
+ int ResNam_len, // fortran-hidden length of ResNam
+ int ChnNam_len, // fortran-hidden length of ChnNam
+ int ResNo_len, // fortran-hidden length of ResNo
+ int InsCod_len, // fortran-hidden length of InsCod
+ int AltCod_len, // fortran-hidden length of AltCod
+ int segID_len, // fortran-hidden length of SegID
+ int ID_len // fortran-hidden length of ID
+ ), ( // lengths-in-structure list
+ int * iUnit, int * iSer,
+ mmdb::machine::fpstr AtNam,
+ mmdb::machine::fpstr ResNam,
+ mmdb::machine::fpstr ChnNam, int * iResN,
+ mmdb::machine::fpstr ResNo,
+ mmdb::machine::fpstr InsCod,
+ mmdb::machine::fpstr AltCod,
+ mmdb::machine::fpstr segID, int * IZ,
+ mmdb::machine::fpstr ID,
+ int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, int * iSer,
+ mmdb::machine::fpstr AtNam, int AtNam_len,
+ mmdb::machine::fpstr ResNam, int ResNam_len,
+ mmdb::machine::fpstr ChnNam, int ChnNam_len,
+ int * iResN,
+ mmdb::machine::fpstr ResNo, int ResNo_len,
+ mmdb::machine::fpstr InsCod, int InsCod_len,
+ mmdb::machine::fpstr AltCod, int AltCod_len,
+ mmdb::machine::fpstr segID, int segID_len,
+ int * IZ,
+ mmdb::machine::fpstr ID, int ID_len,
+ int * iRet
+ ) );
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_copyatom_(..) copies atom from current position in
+// channel iUnit1 to current position in channel iUnit2.
+
+// FORTRAN equivalent: subroutine MMDB_F_CopyAtom ( iUnit1,
+// ~~~~~~~~~~~~~~~~~~~ iUnit2,iRet )
+// integer iUnit1,iUnit2,iRet
+
+FORTRAN_SUBR ( MMDB_F_COPYATOM, mmdb_f_copyatom,
+ ( // length-at-end list
+ int * iUnit1, // source channel number
+ int * iUnit2, // destination channel number
+ int * iRet // returns
+ // RWBERR_NoChannel if iUnit was not
+ // initialized
+ // RWBERR_EmptyPointer if atom was not
+ // advanced
+ // >=0 : success
+ ), ( // length-in-structure list
+ int * iUnit1, int * iUnit2, int * iRet
+ ), ( // length-follow list
+ int * iUnit1, int * iUnit2, int * iRet
+ ) );
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_coord_(..) reads or writes the atom coordinates, occupancy
+// and temperature factor from/into the data structure associated
+// with the unit number iUnit (cf. mmdb_f_open_(..)). The position in
+// the structure is adjusted with the help of mmdb_f_advance_(..),
+// mmdb_f_rewd_(..) or mmdb_f_bksp_(..).
+// It is important that mmdb_f_coord_(..) was called AFTER
+// mmdb_f_atom_(..) if channel iUnit is associated with output
+// (otherwise iRet will return RWBERR_EmptyPointer).
+
+// FORTRAN equivalent: subroutine MMDB_F_Coord ( iUnit,XFlag,BFlag,
+// ~~~~~~~~~~~~~~~~~~~ x,y,z,occ,BIso,U,iRet )
+// integer iUnit,iRet
+// character*(*) XFlag,BFlag
+// real x,y,z,occ,BIso,U(6)
+
+// Be sure that real-type parameters of mmdb_f_coord_(..) match those
+// of FORTRAN call. The real type is set with typedef apireal
+// statement in the begining of this file.
+
+FORTRAN_SUBR ( MMDB_F_COORD, mmdb_f_coord,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::fpstr XFlag, // "F" or "O" flag for the fractional
+ // or orthogonal coordinates x,y,z
+ // for output files XFlag may also be
+ // set to "HF" or "HO", where "F" and
+ // "O" have the same meaning as before
+ // and "H" indicates that the atom
+ // should be marked as heteroatom
+ mmdb::machine::fpstr BFlag , // "F" or "O" flag for temperature
+ // factor in fractional or orthogonal
+ // Us
+ mmdb::machine::apireal * x, // x-coordinate
+ mmdb::machine::apireal * y, // y-coordinate
+ mmdb::machine::apireal * z, // z-coordinate
+ mmdb::machine::apireal * occ, // occupancy
+ mmdb::machine::apireal * BIso, // isotropic temperature factor
+ mmdb::machine::apireal * U, // array(6) of the anisotr. t-factor
+ int * iRet, // returns
+ // RWBERR_NoChannel if iUnit was not
+ // initialized
+ // RWBERR_EmptyPointer if atom was not
+ // advanced
+ // RWBERR_NoMatrices if transformation
+ // matrices are
+ // undefined
+ // RWBERR_NoCoordinates if coordinates were
+ // not set in the atom
+ //
+ // >=0 : success, warning flags:
+ // RWBERR_NoOccupancy if occupancy was
+ // not set in the atom
+ // RWBERR_NoTempFactor if temp. factor was
+ // not set in the atom
+ //
+ int XFlag_len, // fortran-hidden length of XFlag
+ int BFlag_len // fortran-hidden length of BFlag
+ ), ( // lengths-in-structure list
+ int * iUnit,
+ mmdb::machine::fpstr XFlag,
+ mmdb::machine::fpstr BFlag,
+ mmdb::machine::apireal * x,
+ mmdb::machine::apireal * y,
+ mmdb::machine::apireal * z,
+ mmdb::machine::apireal * occ,
+ mmdb::machine::apireal * BIso,
+ mmdb::machine::apireal * U,
+ int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::fpstr XFlag, int XFlag_len,
+ mmdb::machine::fpstr BFlag, int BFlag_len,
+ mmdb::machine::apireal * x,
+ mmdb::machine::apireal * y,
+ mmdb::machine::apireal * z,
+ mmdb::machine::apireal * occ,
+ mmdb::machine::apireal * BIso,
+ mmdb::machine::apireal * U,
+ int * iRet
+ ) );
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_setter_(..) sets the termination flag, so that the current
+// atom will be converted into terminator of a chain and appear as
+// 'ter' card in the output. The atom should be set by mmdb_f_atom_
+// first, but the coordinates (mmdb_f_coord_(..)) do not have to be
+// specified.
+
+// FORTRAN equivalent: subroutine MMDB_F_SetTer ( iUnit,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_SETTER, mmdb_f_setter,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) );
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_sethet_(..) sets the heteroatom flag, so that the current
+// atom will appear as 'hetatm' card in the output. The atom should
+// be set by mmdb_f_atom_ first and then mmdb_f_coord_(..) and
+// mmdb_f_sethet_(..) should be called to specify its coordinates and
+// heteroatom status.
+
+// FORTRAN equivalent: subroutine MMDB_F_SetHet ( iUnit,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+
+FORTRAN_SUBR ( MMDB_F_SETHET, mmdb_f_sethet,
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ),
+ ( int * iUnit, int * iRet ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_setcell_(..) sets the crystal cell properties and calculates
+// the orthogonal-fractional transformation matrices for unit iUnit.
+
+// FORTRAN equivalent: subroutine MMDB_F_SetCell ( iUnit,a,b,c,
+// ~~~~~~~~~~~~~~~~~~~ alpha,beta,gamma,
+// ArgNCode,iRet )
+// integer iUnit,ArgNCode,iRet
+// real a,b,c,alpha,beta,gamma
+
+
+// Relation to the former RBFRAC2 FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine RBFRAC2 ( a,b,c,alpha,beta,gamma,ArgNCode )
+//
+// ** the unit number iUnit and buffer for the return code iRet
+// have to be supplied.
+
+FORTRAN_SUBR ( MMDB_F_SETCELL, mmdb_f_setcell,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * a, // cell parameter a, angstroms
+ mmdb::machine::apireal * b, // cell parameter b, angstroms
+ mmdb::machine::apireal * c, // cell parameter c, angstroms
+ mmdb::machine::apireal * alpha, // cell parameter alpha, degrees
+ mmdb::machine::apireal * beta, // cell parameter beta, degrees
+ mmdb::machine::apireal * gamma, // cell parameter gamma, degrees
+ int * ArgNCode, // orthogonalization code, 1-6
+ int * iRet // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_Disagreement if a
+ // disagreement in
+ // cell parameters
+ // was found
+ // RWBERR_NoOrthCode if no
+ // orthogonalization
+ // code was found
+ // RWBERR_NoCheck if check
+ // of cell parameters
+ // has failed.
+ // The last three returns would
+ // rather indicate a programming
+ // error in mmdb_rwbrook.cpp
+ ), ( // lengths-in-structure list
+ int * iUnit,
+ mmdb::machine::apireal * a,
+ mmdb::machine::apireal * b,
+ mmdb::machine::apireal * c,
+ mmdb::machine::apireal * alpha,
+ mmdb::machine::apireal * beta,
+ mmdb::machine::apireal * gamma,
+ int * ArgNCode, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::apireal * a,
+ mmdb::machine::apireal * b,
+ mmdb::machine::apireal * c,
+ mmdb::machine::apireal * alpha,
+ mmdb::machine::apireal * beta,
+ mmdb::machine::apireal * gamma,
+ int * ArgNCode, int * iRet
+ )
+ );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_wbspgrp_(..) sets the space group
+
+// FORTRAN equivalent: subroutine MMDB_F_WBSpGrp ( iUnit,spGroup,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+// character*(*) spGroup
+
+
+// Relation to the former WBSpGrp FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine WBSpGrp ( spGroup )
+//
+// ** the unit number iUnit and buffer for the return code iRet
+// have to be supplied.
+
+FORTRAN_SUBR ( MMDB_F_WBSPGRP, mmdb_f_wbspgrp,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::fpstr spGroup, // space group
+ int * iRet, // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ int spGroup_len // fortran-hidden length of spGroup
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr spGroup, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::fpstr spGroup, int spGroup_len,
+ int * iRet
+ )
+ );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_rbspgrp_(..) retrieves the space group
+
+// FORTRAN equivalent: subroutine MMDB_F_RBSpGrp ( iUnit,spGroup,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+// character*(*) spGroup
+
+
+// Relation to the former RBSpGrp FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine RBSpGrp ( spGroup )
+//
+// ** the unit number iUnit and buffer for the return code iRet
+// have to be supplied.
+
+FORTRAN_SUBR ( MMDB_F_RBSPGRP, mmdb_f_rbspgrp,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::fpstr spGroup, // space group
+ int * iRet, // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ int spGroup_len // fortran-hidden length of spGroup
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::fpstr spGroup, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::fpstr spGroup, int spGroup_len,
+ int * iRet
+ )
+ );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_wbcell_(..) sets the crystal cell properties into the
+// channel iUnit.
+
+// FORTRAN equivalent: subroutine MMDB_F_WBCell ( iUnit,ArgCell,
+// ~~~~~~~~~~~~~~~~~~~ ArgNCode,iRet )
+// integer iUnit,ArgNCode,iRet
+// real ArgCell(6)
+//
+
+// Relation to the former WBCELL FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine WBCELL ( iUnit,ArgCell,ArgNCode )
+//
+// ** the buffer for the return code iRet has to be supplied
+
+FORTRAN_SUBR ( MMDB_F_WBCELL, mmdb_f_wbcell,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * ArgCell, // array to accept the cell parameters
+ // if ArgCell(1) is set to 0, then
+ // the cell does not change
+ int * ArgNCode, // orthogonalisation code
+ // if ArgNCode is set to 0, then
+ // the orthogonalisation matrices
+ // do not change
+ int * iRet // return code
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::apireal * ArgCell,
+ int * ArgNCode, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::apireal * ArgCell,
+ int * ArgNCode, int * iRet
+ )
+ );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_rbcell_(..) retrieves the crystal cell properties from the
+// channel iUnit.
+
+// FORTRAN equivalent: subroutine MMDB_F_RBCell ( iUnit,celld,cvol,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+// real celld(6),cvol
+// character*(*) spGroup
+
+// Relation to the former RBCELL FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine RBCELL ( celld,cvol )
+//
+// ** the unit number iUnit and buffer for the return code iRet
+// have to be supplied.
+
+FORTRAN_SUBR ( MMDB_F_RBCELL, mmdb_f_rbcell,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * celld, // array to accept the cell parameters
+ mmdb::machine::apireal * cvol, // returns the cell volume
+ int * iRet // return code
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_Parameters if the
+ // cell parameters
+ // were not set
+ // RWBERR_NoOrthCode if no
+ // orthogonalization
+ // code was found
+ // RWBERR_NoCheck if check
+ // of cell parameters
+ // has failed.
+ // The last three returns would
+ // rather indicate a programming
+ // error in mmdb_rwbrook.cpp
+ ), ( // lengths-in-structure list
+ int * iUnit, mmdb::machine::apireal * celld,
+ mmdb::machine::apireal * cvol, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit, mmdb::machine::apireal * celld,
+ mmdb::machine::apireal * cvol, int * iRet
+ ) );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_rbcelln_(..) retrieves the crystal cell properties from the
+// channel iUnit.
+
+// FORTRAN equivalent: subroutine MMDB_F_RBCellN ( iUnit,celld,cvol,
+// ~~~~~~~~~~~~~~~~~~~ ArgNCode,iRet )
+// integer iUnit,ArgNCode,iRet
+// real celld(6),cvol
+
+// Relation to the former RBCELL FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine RBCELL ( celld,cvol )
+//
+// ** the unit number iUnit, buffer for orthogonalization code
+// ArgNCode and for the return code iRet have to be supplied.
+
+FORTRAN_SUBR ( MMDB_F_RBCELLN, mmdb_f_rbcelln,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * celld, // array to accept the cell parameters
+ mmdb::machine::apireal * cvol, // returns the cell volume
+ int * ArgNCode, // returns the orthogonalization code, 1-6
+ int * iRet // return code
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_Parameters if the
+ // cell parameters
+ // were not set
+ // RWBERR_NoOrthCode if no
+ // orthogonalization
+ // code was found
+ // RWBERR_NoCheck if check
+ // of cell parameters
+ // has failed.
+ // The last three returns would
+ // rather indicate a programming
+ // error in mmdb_rwbrook.cpp
+ ), ( // lengths-in-structure list
+ int * iUnit,
+ mmdb::machine::apireal * celld,
+ mmdb::machine::apireal * cvol,
+ int * ArgNCode, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::apireal * celld,
+ mmdb::machine::apireal * cvol,
+ int * ArgNCode, int * iRet
+ )
+ );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_rbrcel_(..) retrieves the reciprocal cell dimensions and
+// reciprocal cell volume from the channel iUnit.
+
+// FORTRAN equivalent: subroutine MMDB_F_RBRCel ( iUnit,rcell,rvol,
+// ~~~~~~~~~~~~~~~~~~~ iRet )
+// integer iUnit,iRet
+// real rcell(6),rvol
+
+// Relation to the former RBRCEL FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine RBRCEL ( rcell,rvol )
+//
+// ** the unit number iUnit and buffer for the return code iRet
+// have to be supplied.
+
+FORTRAN_SUBR ( MMDB_F_RBRCEL, mmdb_f_rbrcel,
+ ( // lengths-at-end list
+ int * iUnit, // unit number
+ mmdb::machine::apireal * rcell, // array to accept the reciprocal
+ // cell parameters
+ mmdb::machine::apireal * rvol, // returns the reciprocal cell volume
+ int * iRet // return code
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_Parameters if the
+ // cell parameters
+ // were not set
+ // RWBERR_NoOrthCode if no
+ // orthogonalization
+ // code was found
+ // RWBERR_NoCheck if check
+ // of cell parameters
+ // has failed.
+ // The last three returns would
+ // rather indicate a programming
+ // error in mmdb_rwbrook.cpp
+ ), ( // lengths-in-structure list
+ int * iUnit,
+ mmdb::machine::apireal * rcell,
+ mmdb::machine::apireal * rvol,
+ int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::apireal * rcell,
+ mmdb::machine::apireal * rvol,
+ int * iRet
+ ) );
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_rborf_(..) fills or retrieves the fractionalising (RF) and
+// orthogonalising (RO) 4x4 matrices, as well as the orthogonalisation
+// code (LCode) in/from unit iUnit.
+// If RO[1][1] (fortran notations, or RO[0] in C/C++) is set to 0.0
+// then the matrices are retrieved and returned in RF and RO;
+// otherwise RF and RO are stored in the unit.
+
+// FORTRAN equivalent: subroutine MMDB_F_RBORF ( iUnit,RO,RF,
+// ~~~~~~~~~~~~~~~~~~~ LCode,iRet )
+// integer iUnit,LCode,iRet
+// real RO(4,4),RF(4,4)
+
+// Relation to the former RBRORF2 FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine RBRORF2 ( RO,RF,LCode )
+//
+// ** the unit number iUnit and buffer for the return code iRet
+// have to be supplied.
+
+FORTRAN_SUBR ( MMDB_F_RBORF, mmdb_f_rborf,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * RO, // array for orthogonalising matrix
+ mmdb::machine::apireal * RF, // array for fractionalising matrix
+ int * LCode, // buffer for orthogonalisation code
+ int * iRet // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_NoMatrices if the
+ // orthogonalisation
+ // matrices were not
+ // calculated
+ ), ( // lengths-in-structure list
+ int * iUnit,
+ mmdb::machine::apireal * RO,
+ mmdb::machine::apireal * RF,
+ int * LCode, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::apireal * RO,
+ mmdb::machine::apireal * RF,
+ int * LCode, int * iRet
+ )
+ );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_orthmat_(..) calculates matrices for standard orthogonalisations
+// and cell volume.
+// If Cell(1) is greater then zero, the existing cell parameters
+// will be substituted. If new cell parameters differ substantially
+// from the old ones, the returned value of Vol will be negative.
+
+// FORTRAN equivalent: subroutine MMDB_F_OrthMat ( iUnit,Cell,Vol,
+// ~~~~~~~~~~~~~~~~~~~ RRR,iRet
+// integer iUnit,iRet
+// real Cell(6),Vol,RRR(3,3,6)
+
+// Relation to the former RBFRO1 FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine RBFRO1 ( Cell,Vol,RRR )
+//
+// ** the unit number iUnit and buffer for the return code iRet
+// have to be supplied.
+
+FORTRAN_SUBR ( MMDB_F_ORTHMAT, mmdb_f_orthmat,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * Cell, // array of cell parameters:
+ // Cell(1) - a Cell(4) - alpha
+ // Cell(2) - b Cell(5) - beta
+ // Cell(3) - c Cell(6) - gamma
+ mmdb::machine::apireal * Vol, // returns cell volume
+ mmdb::machine::apireal * RRR, // array (3,3,6), returns
+ // orthogonalisation matrices
+ int * iRet // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_NoMatrices if the
+ // orthogonalisation
+ // matrices were not
+ // calculated
+ ), ( // lengths-in-structure list
+ int * iUnit,
+ mmdb::machine::apireal * Cell,
+ mmdb::machine::apireal * Vol,
+ mmdb::machine::apireal * RRR, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::apireal * Cell,
+ mmdb::machine::apireal * Vol,
+ mmdb::machine::apireal * RRR, int * iRet
+ )
+ );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_cvanisou_(..) converts between crystallographic bs and
+// orthogonal Us or the other way round.
+
+// FORTRAN equivalent: subroutine MMDB_F_CVAnisou ( iUnit,U,iFlag,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iFlag,iRet
+// real U(6)
+
+// Relation to the former CVANISOU FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine CVANISOU ( U,iFlag )
+//
+// ** the unit number iUnit and buffer for the return code iRet
+// have to be supplied.
+
+FORTRAN_SUBR ( MMDB_F_CVANISOU, mmdb_f_cvanisou,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::apireal * U, // array of coordinates to convert
+ int * iFlag, // =0: convert from fract. to orthog.
+ // =1: convert from orthog. to fract.
+ int * iRet // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // RWBERR_NoMatrices if the
+ // orthogonalisation
+ // matrices were not
+ // calculated
+ ), ( // lengths-in-structure list
+ int * iUnit,
+ mmdb::machine::apireal * U, int * iFlag, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::apireal * U, int * iFlag, int * iRet
+ )
+ );
+
+
+
+// ------------------------------------------------------------------
+
+// mmdb_f_wremark_(..) writes a remark line into data structure.
+// Generally, it puts the line on its place according to a PDB
+// keyword which should start the line. The line will be always the
+// last one in its group (last remark with given number or without
+// it, last JRNL record, last ATOM etc.). If the keyword is not
+// recognized, the line is appended after the coordinate section.
+// iRet will return same codes as those in mmdb_f_open1_(..) plus
+// additional ones specified below.
+
+// FORTRAN equivalent: subroutine MMDB_F_WRemark ( iUnit,Line,iRet )
+// ~~~~~~~~~~~~~~~~~~~ integer iUnit,iRet
+// character*(*) Line
+
+// Relation to the former WRemark FORTRAN subroutine:
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// subroutine WRemark ( iUnit,Line )
+//
+// ** the buffer for return code iRet has to be supplied
+
+FORTRAN_SUBR ( MMDB_F_WREMARK, mmdb_f_wremark,
+ ( // lengths-at-end list
+ int * iUnit, // unit number; *iUnit<=0 means
+ // "the last mentioned unit"
+ mmdb::machine::fpstr Line, // line to be added
+ int * iRet, // return code:
+ // RWBERR_Ok - success
+ // RWBERR_NoChannel if unit
+ // iUnit was not
+ // initialized
+ // RWBERR_NoFile if unit
+ // has been disposed
+ // other return codea are those
+ // returned by mmdb_f_open1_(..)
+ int Line_len // fortran-hidden length of Line
+ ), ( // lengths-in-structure list
+ int * iUnit,
+ mmdb::machine::fpstr Line, int * iRet
+ ), ( // lengths-follow list
+ int * iUnit,
+ mmdb::machine::fpstr Line, int Line_len, int *iRet
+ )
+ );
+
+
+/*
+// ------------------------------------------------------------------
+
+// rbrinv_(..) takes 4x4 real matrix A and returns its inverse in
+// matrix AI.
+
+// FORTRAN equivalent: subroutine RBRInv ( A,AI )
+// ~~~~~~~~~~~~~~~~~~~ real A(4,4),AI(4,4)
+
+FORTRAN_SUBR ( RBRINV, rbrinv,
+ ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ),
+ ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ),
+ ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI )
+ );
+
+*/
+/*
+
+// ------------------------------------------------------------------
+
+// res3to1_(..) returns the 3-character or 1-character residue
+// codes. One of them should be supplied (with the other one set
+// blank), the routine returns the other one.
+
+// FORTRAN equivalent: subroutine Res3to1 ( ResNm3,resNm1 )
+// ~~~~~~~~~~~~~~~~~~~ character*4 ResNm3
+// cgaracter*1 ResNm1
+
+FORTRAN_SUBR ( RES3TO1, res3to1,
+ ( // lengths-at-end list
+ mmdb::machine::fpstr ResNm3, // 3-char name, 4th char
+ // will be set blank
+ mmdb::machine::fpstr ResNm1, // 1-char name
+ int ResNm3_len, // fortran-hidden length of ResNm3
+ int ResNm1_len // fortran-hidden length of ResNm3
+ ), ( // lengths-in-structure list
+ mmdb::machine::fpstr ResNm3, mmdb::machine::fpstr ResNm1
+ ), ( // lengths-follow list
+ mmdb::machine::fpstr ResNm3, int ResNm3_len,
+ mmdb::machine::fpstr ResNm1, int ResNm1_len
+ )
+ );
+
+*/
+
+// ------------------------------------------------------------------
+
+// rberrstop_(..) checks the return code got from one of the above
+// functions, and if it indicates an error, it issues the following
+// type of message (example)
+//
+// *** RWBROOK error: point code unit function
+// *** 12 -3 3 MMDB_F_Open
+// *** file : input.pdb
+// *** reason : cannot open a file
+// *** Execution stopped.
+//
+// if iStop is set to 0, and one of the following type
+//
+// *** RWBROOK error: point code unit function
+// *** 12 -3 3 MMDB_F_Open
+// *** file : input.pdb
+// *** reason : cannot open a file
+// *** continue running, may crash ...
+//
+// if iStop is not null.
+//
+// iPlace (12 in the above samples) should be given a number which
+// is unique through an application; it serves to the identifying
+// the particular call which caused the problem. The return code
+// (-3 in the above samples) is that what is back in the iRet
+// parameter to the above functions. If iRet is set to RWBERR_Ok,
+// rberrstop_(..) makes no action. If rberrstop_(..) is called
+// immediately after a call to an RWBROOK function, e.g.
+//
+// call MMDB_F_Open ( FName,RWStat,FType,iUnit,iRet )
+// call RBErrStop ( 12,iRet,iUnit,0 )
+//
+// then the name of the misfunctioned call (MMDB_F_Open in the above
+// samples) will be identified automatically and correctly.
+
+// FORTRAN equivalent: subroutine RBErrStop ( iPlace,iRet,
+// ~~~~~~~~~~~~~~~~~~~ iUnit ,iStop )
+// integer iUnit,iPlace,iRet,iStop
+
+FORTRAN_SUBR ( RBERRSTOP, rberrstop,
+ ( // lengths-at-end list
+ int * iPlace, // (unique) identificator inside an application
+ int * iRet, // return code to check
+ int * iUnit, // unit number
+ int * iStop // if 0 then stop if error
+ ), ( // lengths-in-structure list
+ int * iPlace, int * iRet,
+ int * iUnit, int * iStop
+ ), ( // lengths-follow list
+ int * iPlace, int * iRet,
+ int * iUnit, int * iStop
+ ) );
+
+
+
+// ------------------------------------------------------------------
+
+// rbcheckerr_(..) represents a simplified call to rberrstop_(..).
+// It will work properly only if rbcheckerr_(..) is called
+// immediately after an API function to be checked:
+//
+// call MMDB_F_Open ( FName,RWStat,FType,iUnit,iRet )
+// call RBCheckErr ( 12,0 )
+//
+
+// FORTRAN equivalent: subroutine RBCheckErr ( iPlace,iStop )
+// ~~~~~~~~~~~~~~~~~~~ integer iPlace,iStop
+
+FORTRAN_SUBR ( RBCHECKERR, rbcheckerr,
+ ( // lengths-at-end list
+ int * iPlace, // (unique) identificator inside an application
+ int * iStop // if 0 then stop if error
+ ), ( // lengths-in-structure list
+ int * iPlace, int * iStop
+ ), ( // lengths-follow list
+ int * iPlace, int * iStop
+ ) );
+
+
+#endif
diff --git a/mmdb2/mmdb_selmngr.cpp b/mmdb2/mmdb_selmngr.cpp
new file mode 100644
index 0000000..3aeec25
--- /dev/null
+++ b/mmdb2/mmdb_selmngr.cpp
@@ -0,0 +1,3421 @@
+// $Id: mmdb_selmngr.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 15.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_selmngr <implementation>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Manager ( MMDB atom selection manager )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "mmdb_selmngr.h"
+
+
+namespace mmdb {
+
+ const int ANY_RES = MinInt4;
+
+ // ==================== SelManager =====================
+
+ SelManager::SelManager() : CoorManager() {
+ InitSelManager();
+ }
+
+ SelManager::SelManager ( io::RPStream Object )
+ : CoorManager(Object) {
+ InitSelManager();
+ }
+
+ SelManager::~SelManager() {
+ DeleteAllSelections();
+ }
+
+ void SelManager::ResetManager() {
+ CoorManager::ResetManager();
+ DeleteAllSelections();
+ InitSelManager ();
+ }
+
+ void SelManager::InitSelManager() {
+ nSelections = 0; // number of selections
+ mask = NULL; // vector of selections
+ selType = NULL; // vector of selection types
+ nSelItems = NULL; // numbers of selected items
+ selection = NULL; // vector of selected items
+ }
+
+
+ // ------------------------ Selection -----------------------------
+
+ int SelManager::NewSelection() {
+ PMask M;
+ PPMask Mask1;
+ PPMask * Selection1;
+ ivector nSelItems1;
+ SELECTION_TYPE * SelType1;
+ int i,l;
+
+ M = new Mask();
+ M->NewMask ( mask,nSelections );
+
+ i = 0;
+ while (i<nSelections)
+ if (!mask[i]) break;
+ else i++;
+
+ if (i>=nSelections) {
+ l = nSelections+10;
+ Mask1 = new PMask [l];
+ Selection1 = new PPMask[l];
+ nSelItems1 = new int[l];
+ SelType1 = new SELECTION_TYPE[l];
+ for (i=0;i<nSelections;i++) {
+ Mask1 [i] = mask [i];
+ Selection1[i] = selection[i];
+ nSelItems1[i] = nSelItems[i];
+ SelType1 [i] = selType [i];
+ }
+ for (i=nSelections;i<l;i++) {
+ Mask1 [i] = NULL;
+ Selection1[i] = NULL;
+ nSelItems1[i] = 0;
+ SelType1 [i] = STYPE_UNDEFINED;
+ }
+ if (mask) delete[] mask;
+ if (selection) delete[] selection;
+ if (nSelItems) delete[] nSelItems;
+ if (selType) delete[] selType;
+ mask = Mask1;
+ selection = Selection1;
+ nSelItems = nSelItems1;
+ selType = SelType1;
+ i = nSelections;
+ nSelections = l;
+ }
+
+ mask[i] = M;
+ if (selection[i]) delete[] selection[i];
+ selection[i] = NULL;
+ nSelItems[i] = 0;
+ selType [i] = STYPE_UNDEFINED;
+
+ return i+1;
+
+ }
+
+ int SelManager::GetSelType ( int selHnd ) {
+ int k;
+ if ((selHnd>0) && (selHnd<=nSelections)) {
+ k = selHnd-1;
+ if (mask[k]) return selType[k];
+ }
+ return STYPE_INVALID;
+ }
+
+ void SelManager::DeleteSelection ( int selHnd ) {
+ int i,k;
+ if ((selHnd>0) && (selHnd<=nSelections)) {
+ k = selHnd-1;
+ if (mask[k]) {
+ for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+
+ // for (i=0;i<nAtoms;i++)
+ // if (atom[i])
+ // atom[i]->RemoveMask ( mask[k] );
+
+ delete mask[k];
+ }
+ mask[k] = NULL;
+ if (selection[k]) delete[] selection[k];
+ selection[k] = NULL;
+ nSelItems[k] = 0;
+ selType [k] = STYPE_UNDEFINED;
+ }
+ }
+
+
+ PMask SelManager::GetSelMask ( int selHnd ) {
+ if ((selHnd>0) && (selHnd<=nSelections))
+ return mask[selHnd-1];
+ else return NULL;
+ }
+
+ void SelManager::DeleteAllSelections() {
+ PResidue res ,res1;
+ PChain chain,chain1;
+ PModel model,model1;
+ int i;
+
+ if (mask) {
+ res = NULL;
+ chain = NULL;
+ model = NULL;
+ if (atom)
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ atom[i]->ClearMask();
+ res1 = atom[i]->GetResidue();
+ if (res1!=res) {
+ res = res1;
+ res->ClearMask();
+ chain1 = res->GetChain();
+ if (chain1!=chain) {
+ chain = chain1;
+ chain->ClearMask();
+ model1 = chain->GetModel();
+ if (model1!=model) {
+ model = model1;
+ model->ClearMask();
+ }
+ }
+ }
+ }
+ for (i=0;i<nSelections;i++) {
+ if (mask [i]) delete mask[i];
+ if (selection[i]) delete[] selection[i];
+ }
+ delete[] mask;
+ if (selection) delete[] selection;
+ if (nSelItems) delete[] nSelItems;
+ if (selType) delete[] selType;
+ }
+
+ nSelections = 0;
+ mask = NULL;
+ selection = NULL;
+ nSelItems = NULL;
+ selType = NULL;
+
+ }
+
+ void SelManager::SelectAtoms ( int selHnd, int iSer1, int iSer2,
+ SELECTION_KEY sKey ) {
+ // SelectAtoms(..) selects atoms in the serial number range
+ // of iSer1 to iSer2 by adding them to the set of atoms
+ // marked by the given mask. If iSer1=iSer2=0 then all atoms
+ // are selected. Each atom may be selected by a number of masks
+ // simultaneously
+ int i,s1,s2,k,nsel;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0)) return;
+
+ k = selHnd-1;
+ sk = sKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = STYPE_ATOM;
+ else if (selType[k]!=STYPE_ATOM) return;
+
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nAtoms;i++)
+ if (atom[i]) atom[i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : nsel = 0; break;
+ case SKEY_XOR : nsel = nSelItems[k]; break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ case SKEY_XAND: nsel = 0; break;
+ }
+
+ if ((iSer1==0) && (iSer2==0)) {
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter)
+ SelectAtom ( atom[i],k,sk,nsel );
+ }
+ } else {
+ if (iSer1<=iSer2) {
+ s1 = iSer1;
+ s2 = iSer2;
+ } else {
+ s1 = iSer2;
+ s2 = iSer1;
+ }
+ // for a very general use, we allow the serial number
+ // to differ from the atom's index, although this is
+ // against PDB format. Therefore we apply here the most
+ // primitive and less efficient way of selection
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter) {
+ if ((s1<=atom[i]->serNum) && (atom[i]->serNum<=s2))
+ SelectAtom ( atom[i],k,sk,nsel );
+ else if (sk==SKEY_AND)
+ atom[i]->RemoveMask ( mask[k] );
+ }
+ }
+ }
+
+ MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
+
+ }
+
+
+ void SelManager::SelectAtoms ( int selHnd, ivector asn, int nsn,
+ SELECTION_KEY selKey ) {
+ // SelectAtoms(..) selects atoms with serial numbers given in
+ // vector asn[0..nsn-1].
+ QuickSort QS;
+ ivector asn1;
+ int i,k,nsn1,j,j1,j2, sn,nsel;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0)) return;
+
+ k = selHnd-1;
+ sk = selKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) ||
+ (selKey==SKEY_NEW)) selType[k] = STYPE_ATOM;
+ else if (selType[k]!=STYPE_ATOM) return;
+
+ switch (selKey) {
+ case SKEY_NEW : for (i=0;i<nAtoms;i++)
+ if (atom[i]) atom[i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : nsel = 0; break;
+ case SKEY_XOR : nsel = nSelItems[k]; break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ case SKEY_XAND: nsel = 0; break;
+ }
+
+ GetVectorMemory ( asn1,nsn,0 );
+ for (i=0;i<nsn;i++)
+ asn1[i] = asn[i];
+
+ QS.Sort ( asn1,nsn );
+ nsn1 = nsn-1;
+
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (!atom[i]->Ter) {
+ sn = atom[i]->serNum;
+ if ((asn1[0]<=sn) && (sn<=asn1[nsn1])) {
+ // binary search
+ j1 = 0;
+ j2 = nsn1;
+ do {
+ j = (j1+j2)/2;
+ if (sn<asn1[j]) j2 = j;
+ else if (sn>asn1[j]) j1 = j;
+ else j1 = j2;
+ } while (j1<j2-1);
+ if ((sn==asn1[j]) || (sn==asn1[j1]) || (sn==asn1[j2]))
+ SelectAtom ( atom[i],k,sk,nsel );
+ else if (sk==SKEY_AND)
+ atom[i]->RemoveMask ( mask[k] );
+ } else if (sk==SKEY_AND)
+ atom[i]->RemoveMask ( mask[k] );
+ }
+ }
+
+ FreeVectorMemory ( asn1,0 );
+
+ MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
+
+ }
+
+
+ void SelManager::UnselectAtoms ( int selHnd, int iSer1, int iSer2 ) {
+ // UnselectAtoms(..) clears the specified mask for atoms in
+ // the serial number range of iSer1 to iSer2. If iSer1=iSer2=0
+ // then all atoms are cleared of the specified mask. If selHnd
+ // is set to 0, then the atoms are cleared of any mask.
+ int i,s1,s2,k;
+
+ if ((selHnd<=nSelections) && (nAtoms>0)) {
+
+ k = selHnd-1;
+
+ if (selType[k]==STYPE_UNDEFINED) selType[k] = STYPE_ATOM;
+ else if (selType[k]!=STYPE_ATOM) return;
+
+ if ((iSer1==0) && (iSer2==0)) {
+ if (k<0) {
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) atom[i]->ClearMask();
+ } else {
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) atom[i]->RemoveMask ( mask[k] );
+ }
+ } else {
+ if (iSer1<=iSer2) {
+ s1 = iSer1;
+ s2 = iSer2;
+ } else {
+ s1 = iSer2;
+ s2 = iSer1;
+ }
+ // for a very general use, we allow the serial number
+ // to differ from the atom's index, although this is
+ // against PDB format. Therefore we apply here the most
+ // primitive and less efficient way of selection
+ if (k<0) {
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if ((s1<=atom[i]->serNum) && (atom[i]->serNum<=s2))
+ atom[i]->ClearMask();
+ }
+ } else {
+ for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if ((s1<=atom[i]->serNum) && (atom[i]->serNum<=s2))
+ atom[i]->RemoveMask ( mask[k] );
+ }
+ }
+ }
+
+ MakeSelIndex ( selHnd,STYPE_ATOM,-1 );
+
+ }
+
+ }
+
+
+ pstr MakeList ( cpstr S ) {
+ // makes the list of selecting items:
+ // 1st character - special use,
+ // then each item from S embraced by commas
+ pstr L;
+ int i,j;
+ i = 0;
+ while (S[i]==' ') i++;
+ if (S[i]!='*') {
+ // compile a searchable list
+ L = new char[strlen(S)+5];
+ if (S[i]=='!') {
+ L[0] = '!';
+ i++;
+ } else
+ L[0] = ' ';
+ if (strchr(S,'[')) L[1] = '"';
+ else L[1] = ' ';
+ L[2] = ',';
+ j = 3;
+ while (S[i]) {
+ while (S[i]==' ') i++;
+ if (S[i]=='[') {
+ while (S[i] && (S[i]!=']'))
+ L[j++] = S[i++];
+ L[j++] = ']';
+ if (S[i]==']') i++;
+ } else
+ while (S[i] && (S[i]!=' ') && (S[i]!=','))
+ L[j++] = S[i++];
+ while (S[i]==' ') i++;
+ L[j++] = ',';
+ if (S[i]==',') {
+ i++;
+ if (!S[i]) L[j++] = ','; // blank chain ID at the end assumed
+ }
+ }
+ if (j==3) L[j++] = ',';
+ L[j] = char(0);
+ } else
+ L = NULL;
+ return L;
+ }
+
+ bool MatchName ( pstr L, pstr N ) {
+ char M[sizeof(maxMMDBName)+5];
+ int i,j;
+ if (L) {
+ i = 0;
+ M[0] = ',';
+ j = 1;
+ while (N[i])
+ if (N[i]==' ') i++;
+ else M[j++] = N[i++];
+ M[j++] = ',';
+ M[j] = char(0);
+ if (strstr(&(L[2]),M)) return (L[0]!='!');
+ else if (L[1]!='"') return (L[0]=='!');
+ else {
+ strcpy ( M,",[" );
+ strcat ( M,N );
+ strcat ( M,"]," );
+ if (strstr(&(L[2]),M)) return (L[0]!='!');
+ else return (L[0]=='!');
+ }
+ } else
+ return true;
+ }
+
+ bool MatchCharge ( pstr L, PAtom atom ) {
+ char N[100];
+ if (L) {
+ if (atom->WhatIsSet & ASET_Charge) {
+ sprintf ( N,"%+2i",mround(atom->charge) );
+ return MatchName ( L,N );
+ } else
+ return false;
+ } else
+ return true;
+ }
+
+
+ void SelManager::SelectAtom ( int selHnd, PAtom A,
+ SELECTION_KEY selKey,
+ bool makeIndex ) {
+ int i, k, nsel;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections)) return;
+
+ k = selHnd-1;
+ sk = selKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) ||
+ (selKey==SKEY_NEW)) selType[k] = STYPE_ATOM;
+ else if (selType[k]!=STYPE_ATOM) return;
+
+ switch (selKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : if (nSelItems[k]==0) return;
+ nsel = 0;
+ break;
+ case SKEY_XOR : nsel = nSelItems[k];
+ break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ case SKEY_XAND: nsel = 0; break;
+ }
+
+ SelectAtom ( A,k,sk,nsel);
+ if (makeIndex) MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
+
+ }
+
+
+ void SelManager::SelectResidue ( int selHnd, PResidue Res,
+ SELECTION_TYPE sType,
+ SELECTION_KEY sKey,
+ bool makeIndex ) {
+ // Selects residue Res or all its atoms depending on selType
+ PPAtom A;
+ int i, k, nsel, nat;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections)) return;
+
+ k = selHnd-1;
+ sk = sKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : if (nSelItems[k]==0) return;
+ nsel = 0;
+ break;
+ case SKEY_XOR : nsel = nSelItems[k];
+ break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ case SKEY_XAND: nsel = 0; break;
+ }
+
+ switch (sType) {
+ case STYPE_ATOM : Res->GetAtomTable ( A,nat );
+ for (i=0;i<nat;i++)
+ if (A[i]) {
+ if (!A[i]->Ter)
+ SelectAtom ( A[i],k,sk,nsel);
+ }
+ break ;
+ case STYPE_RESIDUE : SelectObject ( Res,k,sk,nsel );
+ break ;
+ default : ;
+ }
+
+ if (makeIndex) MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ void SelManager::SelectChain ( int selHnd, PChain Chain,
+ SELECTION_TYPE sType,
+ SELECTION_KEY sKey,
+ bool makeIndex ) {
+ // Selects chain Chain or all its residues or atoms depending on selType
+ PPAtom A;
+ PPResidue Res;
+ int i,j, k, nsel, nat,nres;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections)) return;
+
+ k = selHnd-1;
+ sk = sKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : if (nSelItems[k]==0) return;
+ nsel = 0;
+ break;
+ case SKEY_XOR : nsel = nSelItems[k];
+ break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ case SKEY_XAND: nsel = 0; break;
+ }
+
+ switch (sType) {
+ case STYPE_ATOM : Chain->GetResidueTable ( Res,nres );
+ for (i=0;i<nres;i++)
+ if (Res[i]) {
+ Res[i]->GetAtomTable ( A,nat );
+ for (j=0;j<nat;j++)
+ if (A[j]) {
+ if (!A[j]->Ter)
+ SelectAtom ( A[j],k,sk,nsel);
+ }
+ }
+ break ;
+ case STYPE_RESIDUE : Chain->GetResidueTable ( Res,nres );
+ for (i=0;i<nres;i++)
+ if (Res[i])
+ SelectObject ( Res[i],k,sk,nsel );
+ break ;
+ case STYPE_CHAIN : SelectObject ( Chain,k,sk,nsel );
+ break ;
+ default : ;
+ }
+
+ if (makeIndex) MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ void SelManager::SelectModel ( int selHnd, PModel model,
+ SELECTION_TYPE sType,
+ SELECTION_KEY sKey,
+ bool makeIndex ) {
+ // Selects model or all its chains or residues or atoms depending
+ // on selType
+ PPAtom A;
+ PPResidue Res;
+ PPChain Chain;
+ int i,j,n, k, nsel, nat,nres,nch;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections)) return;
+
+ k = selHnd-1;
+ sk = sKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : if (nSelItems[k]==0) return;
+ nsel = 0;
+ break;
+ case SKEY_XOR : nsel = nSelItems[k];
+ break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ case SKEY_XAND: nsel = 0; break;
+ }
+
+ switch (sType) {
+ case STYPE_ATOM : model->GetChainTable ( Chain,nch );
+ for (i=0;i<nch;i++)
+ if (Chain[i]) {
+ Chain[i]->GetResidueTable ( Res,nres );
+ for (j=0;j<nres;j++)
+ if (Res[j]) {
+ Res[j]->GetAtomTable ( A,nat );
+ for (n=0;n<nat;n++)
+ if (A[n]) {
+ if (!A[n]->Ter)
+ SelectAtom ( A[n],k,sk,nsel);
+ }
+ }
+ }
+ break ;
+ case STYPE_RESIDUE : model->GetChainTable ( Chain,nch );
+ for (i=0;i<nch;i++)
+ if (Chain[i]) {
+ Chain[i]->GetResidueTable ( Res,nres );
+ for (j=0;j<nres;j++)
+ if (Res[j])
+ SelectObject ( Res[j],k,sk,nsel );
+ }
+ break ;
+ case STYPE_CHAIN : model->GetChainTable ( Chain,nch );
+ for (i=0;i<nch;i++)
+ if (Chain[i])
+ SelectObject ( Chain[i],k,sk,nsel );
+ break ;
+ case STYPE_MODEL : SelectObject ( model,k,sk,nsel );
+ break ;
+ default : ;
+ }
+
+ if (makeIndex) MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ int SelManager::MakeSelIndex ( int selHnd ) {
+ int k;
+ if ((selHnd<=0) || (selHnd>nSelections)) return 0;
+ k = selHnd-1;
+ if (selType[k]==STYPE_UNDEFINED) return 0;
+ MakeSelIndex ( selHnd,selType[k],-1 );
+ return nSelItems[k];
+ }
+
+ void SelManager::MakeAllSelIndexes() {
+ int k;
+ for (k=0;k<nSelections;k++)
+ if (selType[k]!=STYPE_UNDEFINED)
+ MakeSelIndex ( k+1,selType[k],-1 );
+ }
+
+ void SelManager::SelectAtoms (
+ int selHnd, // must be obtained from NewSelection()
+ int iModel, // model number; iModel=0 means
+ // 'any models'
+ cpstr Chains, // may be several chains "A,B,W";
+ // "*" means 'any chain' (in model)
+ int ResNo1, // starting residue number
+ cpstr Ins1, // starting residue insertion code;
+ // "*" means 'any code'
+ int ResNo2, // ending residue number.
+ // ResNo1=ResNo2=ANY_RES
+ // means 'any residue number'
+ // (in chain)
+ cpstr Ins2, // ending residue insertion code
+ // "*" means 'any code'
+ cpstr RNames, // may be several residue names
+ // "ALA,GLU,CIS"; "*" means
+ // 'any residue name'
+ cpstr ANames, // may be several names "CA,CB";
+ // "*" means 'any atom' (in residue)
+ cpstr Elements, // may be several element types like
+ // "H,C,O,CU"; "*" means 'any element'
+ cpstr altLocs, // may be several alternative
+ // locations 'A,B'; "*" means 'any
+ // alternative location'
+ cpstr Segments, // may be several segment IDs like
+ // "S1,S2,A234"; "*" means 'any
+ // segment'
+ cpstr Charges, // may be several charges like
+ // "+1,-2, "; "*" means 'any charge'
+ realtype occ1, // lowest occupancy
+ realtype occ2, // highest occupancy;
+ // occ1=occ2<0.0 means
+ // "any occupancy"
+ realtype x0, // reference x-point
+ realtype y0, // reference y-point
+ realtype z0, // reference z-point
+ realtype d0, // selection distance from the reference
+ // reference point; d0<=0.0 means
+ // 'any distance" and values of
+ // x0, y0 and z0 are ignored
+ SELECTION_KEY selKey // selection key
+ ) {
+
+ Select ( selHnd,STYPE_ATOM,iModel,Chains,ResNo1,Ins1,ResNo2,Ins2,
+ RNames,ANames,Elements,altLocs,Segments,Charges,
+ occ1,occ2,x0,y0,z0,d0,selKey );
+
+ }
+
+
+ #define hetIndicator '@'
+
+ void SelManager::Select (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int iModel, // model number; iModel=0 means
+ // 'any models'
+ cpstr Chains, // may be several chains "A,B,W";
+ // "*" means 'any chain' (in model)
+ int ResNo1, // starting residue number
+ cpstr Ins1, // starting residue insertion code;
+ // "*" means 'any code'
+ int ResNo2, // ending residue number.
+ // ResNo1=ResNo2=ANY_RES means 'any
+ // residue number' (in chain)
+ cpstr Ins2, // ending residue insertion code
+ // "*" means 'any code'
+ cpstr RNames, // may be several residue names
+ // "ALA,GLU,CIS"; "*" means 'any
+ // residue name'
+ cpstr ANames, // may be several names "CA,CB";"*"
+ // means 'any atom' (in residue)
+ cpstr Elements, // may be several element types like
+ // "H,C,O,CU"; "*" means 'any element'
+ cpstr altLocs, // may be several alternative
+ // locations 'A,B'; "*" means 'any
+ // alternative location'
+ cpstr Segments, // may be several segment IDs like
+ // "S1,S2,A234"; "*" means 'any
+ // segment'
+ cpstr Charges, // may be several charges like
+ // "+1,-2, "; "*" means 'any charge'
+ realtype occ1, // lowest occupancy
+ realtype occ2, // highest occupancy;
+ // occ1=occ2<0.0 means
+ // "any occupancy"
+ realtype x0, // reference x-point
+ realtype y0, // reference y-point
+ realtype z0, // reference z-point
+ realtype d0, // selection distance from the reference
+ // reference point; d0<=0.0 means
+ // 'any distance" and values of
+ // x0, y0 and z0 are ignored
+ SELECTION_KEY sKey // selection key
+ ) {
+ PModel mdl;
+ PChain chain;
+ PResidue res;
+ PAtom atom;
+ pstr chain_l;
+ pstr res_l;
+ pstr atom_l;
+ pstr elem_l;
+ pstr altLocs1;
+ pstr aloc_l;
+ pstr segm_l;
+ pstr charge_l;
+ realtype dx,dy,dz,d02;
+ int i,j,k,n,m1,m2,c, nsel;
+ bool noRes,Occ,Dist,Sel,selAND;
+ bool modelSel,chainSel,resSel;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0)) return;
+
+ modelSel = false;
+
+ k = selHnd-1;
+ sk = sKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ // if something goes wrong, sk should be assigned SKEY_OR if
+ // selKey is set to SKEY_NEW or SKEY_OR below
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : nsel = 0; break;
+ case SKEY_XOR : nsel = nSelItems[k]; break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ default : return;
+ }
+
+ selAND = (sKey==SKEY_AND);
+
+ altLocs1 = NULL;
+ if (altLocs) {
+ if (strchr(altLocs,hetIndicator)) {
+ CreateCopy ( altLocs1,altLocs );
+ DelSpaces ( altLocs1 );
+ aloc_l = strchr ( altLocs1,hetIndicator );
+ aloc_l[0] = ' ';
+ if (aloc_l[1]) aloc_l[1] = ' '; // instead of comma
+ else if (aloc_l!=altLocs1) {
+ aloc_l--;
+ aloc_l[0] = ' ';
+ }
+ DelSpaces ( altLocs1 );
+ aloc_l = MakeList ( altLocs1 );
+ } else
+ aloc_l = MakeList ( altLocs );
+ } else
+ aloc_l = MakeList ( altLocs );
+
+ chain_l = MakeList ( Chains );
+ res_l = MakeList ( RNames );
+ atom_l = MakeList ( ANames );
+ elem_l = MakeList ( Elements );
+ segm_l = MakeList ( Segments );
+ charge_l = MakeList ( Charges );
+
+ // noRes==true means no residue restrictions
+ noRes = (ResNo1==ResNo2) && (ResNo1==ANY_RES) &&
+ (Ins1[0]==Ins2[0]) && (Ins1[0]=='*');
+
+ Occ = (occ1>=0.0) || (occ2>=0.0);
+ Dist = (d0>0.0);
+ d02 = d0*d0;
+
+ m1 = iModel-1;
+
+ if (m1>=0)
+ m2 = m1+1; // will take only this model
+ else {
+ m1 = 0; // will take
+ m2 = nModels; // all models
+ }
+
+ if (m1>=nModels) return;
+
+ for (n=0;n<nModels;n++) {
+ mdl = model[n];
+ if (mdl) { // check for safety
+ if ((m1<=n) && (n<m2)) {
+ modelSel = false; // will be true on any selection in the model
+ for (c=0;c<mdl->nChains;c++) {
+ chain = mdl->chain[c];
+ if (chain) { // again check for safety
+ if (MatchName(chain_l,chain->chainID)) {
+ // the chain has to be taken
+ i = 0;
+ if (!noRes)
+ while (i<chain->nResidues) {
+ res = chain->residue[i];
+ if (res) {
+ if ((res->seqNum==ResNo1) &&
+ MatchName(res_l,res->name) &&
+ ((Ins1[0]=='*') ||
+ (!strcmp(res->insCode,Ins1))))
+ break;
+ else if (selAND) {
+ if (sType==STYPE_ATOM)
+ res->UnmaskAtoms ( mask[k] );
+ else if (sType==STYPE_RESIDUE)
+ res->RemoveMask ( mask[k] );
+ }
+ }
+ i++;
+ }
+ while (i<chain->nResidues) {
+ res = chain->residue[i];
+ if (res) {
+ resSel = false; // will be true on 1st sel-n in the res-e
+ if (MatchName(res_l,res->name)) {
+ for (j=0;j<res->nAtoms;j++) {
+ atom = res->atom[j];
+ if (atom) {
+ if ((!atom->Ter) &&
+ MatchName(atom_l ,atom->name ) &&
+ MatchName(elem_l ,atom->element) &&
+ MatchName(aloc_l ,atom->altLoc ) &&
+ MatchName(segm_l ,atom->segID ) &&
+ MatchCharge(charge_l,atom ) &&
+ ((!altLocs1) || atom->Het)) {
+ Sel = true;
+ if (Occ)
+ Sel = ((occ1<=atom->occupancy) &&
+ (atom->occupancy<=occ2));
+ if (Dist) {
+ dx = atom->x - x0;
+ dy = atom->y - y0;
+ dz = atom->z - z0;
+ Sel = Sel && ((dx*dx+dy*dy+dz*dz)<=d02);
+ }
+ } else
+ Sel = false;
+ if (Sel) {
+ SelectObject ( sType,atom,k,sk,nsel );
+ resSel = true;
+ chainSel = true;
+ modelSel = true;
+ } else if (selAND && (sType==STYPE_ATOM))
+ atom->RemoveMask ( mask[k] );
+ }
+ if (resSel && (sType!=STYPE_ATOM)) break;
+ }
+ } else if (selAND && (sType==STYPE_ATOM))
+ res->UnmaskAtoms ( mask[k] );
+ if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+ res->RemoveMask ( mask[k] );
+ if (chainSel && (sType>STYPE_RESIDUE)) break;
+ if (!noRes) {
+ if ((res->seqNum==ResNo2) &&
+ ((Ins2[0]=='*') || (!strcmp(res->insCode,Ins2)))
+ ) break;
+ }
+ }
+ i++;
+ }
+ if (selAND) {
+ if (sType==STYPE_ATOM)
+ while (i<chain->nResidues) {
+ res = chain->residue[i];
+ if (res) res->UnmaskAtoms ( mask[k] );
+ i++;
+ }
+ if (sType==STYPE_RESIDUE)
+ while (i<chain->nResidues) {
+ res = chain->residue[i];
+ if (res) res->RemoveMask ( mask[k] );
+ i++;
+ }
+ }
+ } else if (selAND)
+ switch (sType) {
+ case STYPE_ATOM : chain->UnmaskAtoms ( mask[k] ); break;
+ case STYPE_RESIDUE : chain->UnmaskResidues ( mask[k] ); break;
+ case STYPE_CHAIN : chain->RemoveMask ( mask[k] ); break;
+ default : ;
+ }
+ if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+ chain->RemoveMask ( mask[k] );
+ if (modelSel && (sType>STYPE_CHAIN)) break;
+ }
+ }
+ } else if (selAND)
+ switch (sType) {
+ case STYPE_ATOM : mdl->UnmaskAtoms ( mask[k] ); break;
+ case STYPE_RESIDUE : mdl->UnmaskResidues ( mask[k] ); break;
+ case STYPE_CHAIN : mdl->UnmaskChains ( mask[k] ); break;
+ default : ;
+ }
+ if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+ mdl->RemoveMask ( mask[k] );
+ }
+ }
+
+ // release dynamic memory
+ if (chain_l) delete[] chain_l;
+ if (res_l) delete[] res_l;
+ if (atom_l) delete[] atom_l;
+ if (elem_l) delete[] elem_l;
+ if (altLocs1) delete[] altLocs1;
+ if (aloc_l) delete[] aloc_l;
+ if (segm_l) delete[] segm_l;
+ if (charge_l) delete[] charge_l;
+
+ MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
+
+ }
+
+
+ void SelManager::SelectAtoms (
+ int selHnd, // must be obtained from NewSelection()
+ int iModel, // model number; iModel=0 means
+ // 'any models'
+ cpstr Chains, // may be several chains "A,B,W";
+ // "*" means 'any chain' (in model)
+ int ResNo1, // starting residue number
+ cpstr Ins1, // starting residue insertion code;
+ // "*" means 'any code'
+ int ResNo2, // ending residue number.
+ // ResNo1=ResNo2=ANY_RES means 'any
+ // residue number' (in chain)
+ cpstr Ins2, // ending residue insertion code
+ // "*" means 'any code'
+ cpstr RNames, // may be several residue names
+ // "ALA,GLU,CIS"; "*" means 'any
+ // residue name'
+ cpstr ANames, // may be several names "CA,CB"; "*"
+ // means 'any atom' (in residue)
+ cpstr Elements, // may be several element types like
+ // "H,C,O,CU"; "*" means 'any
+ // element'
+ cpstr altLocs, // may be several alternative
+ // locations 'A,B'; "*" means 'any
+ // alternative location'
+ SELECTION_KEY sKey // selection key
+ ) {
+ Select ( selHnd,STYPE_ATOM,iModel,Chains,ResNo1,Ins1,ResNo2,Ins2,
+ RNames,ANames,Elements,altLocs,sKey );
+ }
+
+
+ int SelManager::Select (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ cpstr CID, // coordinate ID
+ SELECTION_KEY sKey // selection key
+ ) {
+ InsCode insCode1,insCode2;
+ pstr RNames;
+ pstr ANames;
+ pstr Elements;
+ pstr altLocs;
+ pstr Chains;
+ int seqNum1 ,seqNum2;
+ int iModel,l,RC;
+
+ l = IMax(10,strlen(CID))+1;
+ Chains = new char[l];
+ RNames = new char[l];
+ ANames = new char[l];
+ Elements = new char[l];
+ altLocs = new char[l];
+
+ if (strcmp(CID,"-all")) {
+ RC = ParseSelectionPath ( CID,iModel,Chains,seqNum1,insCode1,
+ seqNum2,insCode2,RNames,ANames,
+ Elements,altLocs );
+ } else {
+ iModel = 0;
+ strcpy ( Chains,"*" );
+ seqNum1 = ANY_RES;
+ seqNum2 = ANY_RES;
+ strcpy ( insCode1,"*" );
+ strcpy ( insCode2,"*" );
+ strcpy ( RNames ,"*" );
+ strcpy ( ANames ,"*" );
+ strcpy ( Elements,"*" );
+ strcpy ( altLocs ,"" ); // only main conformation by default
+ RC = 0;
+ }
+
+ if (!RC) {
+ Select ( selHnd,sType,iModel,Chains,seqNum1,insCode1,
+ seqNum2,insCode2,RNames,ANames,Elements,altLocs,sKey );
+ RC = 0;
+ }
+
+ delete[] Chains;
+ delete[] RNames;
+ delete[] ANames;
+ delete[] Elements;
+ delete[] altLocs;
+
+ return RC;
+
+ }
+
+ void SelManager::Select (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int iModel, // model number; iModel=0 means
+ // 'any model'
+ cpstr Chains, // may be several chains "A,B,W";
+ // "*" means 'any chain' (in model)
+ int ResNo1, // starting residue number
+ cpstr Ins1, // starting residue insertion code;
+ // "*" means 'any code'
+ int ResNo2, // ending residue number.
+ // ResNo1=ResNo2=ANY_RES means 'any
+ // residue number' (in chain)
+ cpstr Ins2, // ending residue insertion code
+ // "*" means 'any code'
+ cpstr RNames, // may be several residue names
+ // "ALA,GLU,CIS"; "*" means 'any
+ // residue name'
+ cpstr ANames, // may be several names "CA,CB"; "*"
+ // means 'any atom' (in residue)
+ cpstr Elements, // may be several element types like
+ // "H,C,O,CU"; "*" means 'any element'
+ cpstr altLocs, // may be several alternative
+ // locations 'A,B'; "*" means 'any
+ // alternative location'
+ SELECTION_KEY sKey // selection key
+ ) {
+ PModel mdl;
+ PChain chain;
+ PResidue res;
+ PAtom atom;
+ pstr chain_l;
+ pstr res_l;
+ pstr atom_l;
+ pstr elem_l;
+ pstr altLocs1;
+ pstr aloc_l;
+ int i,j,k,n,m1,m2,c, nsel;
+ bool noRes,modelSel,chainSel,resSel,selAND;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0)) return;
+
+ modelSel = false;
+
+ k = selHnd-1;
+ sk = sKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ // if something goes wrong, sk should be assigned SKEY_OR if
+ // selKey is set to SKEY_NEW or SKEY_OR below
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : nsel = 0; break;
+ case SKEY_XOR : nsel = nSelItems[k]; break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ default : return;
+ }
+
+ selAND = (sKey==SKEY_AND);
+
+ altLocs1 = NULL;
+ if (altLocs) {
+ if (strchr(altLocs,hetIndicator)) {
+ CreateCopy ( altLocs1,altLocs );
+ DelSpaces ( altLocs1 );
+ aloc_l = strchr ( altLocs1,hetIndicator );
+ aloc_l[0] = ' ';
+ if (aloc_l[1]) aloc_l[1] = ' '; // instead of comma
+ else if (aloc_l!=altLocs1) {
+ aloc_l--;
+ aloc_l[0] = ' ';
+ }
+ DelSpaces ( altLocs1 );
+ aloc_l = MakeList ( altLocs1 );
+ } else
+ aloc_l = MakeList ( altLocs );
+ } else
+ aloc_l = MakeList ( altLocs );
+
+ chain_l = MakeList ( Chains );
+ res_l = MakeList ( RNames );
+ atom_l = MakeList ( ANames );
+ elem_l = MakeList ( Elements );
+
+ // noRes==true means no residue restrictions
+ noRes = (ResNo1==ResNo2) && (ResNo1==ANY_RES) &&
+ (Ins1[0]=='*') && (Ins2[0]=='*');
+
+ m1 = iModel-1;
+ if (m1>=0)
+ m2 = m1+1; // will take only this model
+ else {
+ m1 = 0; // will take
+ m2 = nModels; // all models
+ }
+
+ if (m1>=nModels) return;
+
+ for (n=0;n<nModels;n++) {
+ mdl = model[n];
+ if (mdl) { // check for safety
+ if ((m1<=n) && (n<m2)) {
+ modelSel = false; // will be true on any selection in the model
+ for (c=0;c<mdl->nChains;c++) {
+ chain = mdl->chain[c];
+ if (chain) { // again check for safety
+ chainSel = false; // will be true on 1st sel-n in the chain
+ if (MatchName(chain_l,chain->chainID)) {
+ // the chain is to be taken
+ i = 0;
+ if (!noRes) // skip "leading" residues
+ while (i<chain->nResidues) {
+ res = chain->residue[i];
+ if (res) {
+ if ((res->seqNum==ResNo1) &&
+ MatchName(res_l,res->name) &&
+ ((Ins1[0]=='*') ||
+ (!strcmp(res->insCode,Ins1))))
+ break;
+ else if (selAND) {
+ if (sType==STYPE_ATOM)
+ res->UnmaskAtoms ( mask[k] );
+ else if (sType==STYPE_RESIDUE)
+ res->RemoveMask ( mask[k] );
+ }
+ }
+ i++;
+ }
+ while (i<chain->nResidues) {
+ res = chain->residue[i];
+ i++;
+ if (res) {
+ resSel = false; // will be true on 1st selection
+ // in the residue
+ if (MatchName(res_l,res->name)) {
+ for (j=0;j<res->nAtoms;j++) {
+ atom = res->atom[j];
+ if (atom) {
+ if ((!atom->Ter) &&
+ MatchName(atom_l,atom->name ) &&
+ MatchName(elem_l,atom->element) &&
+ MatchName(aloc_l,atom->altLoc ) &&
+ ((!altLocs1) || atom->Het)) {
+ SelectObject ( sType,atom,k,sk,nsel );
+ resSel = true;
+ chainSel = true;
+ modelSel = true;
+ } else if (selAND && (sType==STYPE_ATOM))
+ atom->RemoveMask ( mask[k] );
+ }
+ if (resSel && (sType!=STYPE_ATOM)) break;
+ }
+ } else if (selAND && (sType==STYPE_ATOM))
+ res->UnmaskAtoms ( mask[k] );
+ if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+ res->RemoveMask ( mask[k] );
+ if (chainSel && (sType>STYPE_RESIDUE)) break;
+ if (!noRes) {
+ if ((res->seqNum==ResNo2) &&
+ ((Ins2[0]=='*') || (!strcmp(res->insCode,Ins2)))
+ ) break;
+ }
+ }
+ }
+ if (selAND) {
+ if (sType==STYPE_ATOM)
+ while (i<chain->nResidues) {
+ res = chain->residue[i];
+ if (res) res->UnmaskAtoms ( mask[k] );
+ i++;
+ }
+ if (sType==STYPE_RESIDUE)
+ while (i<chain->nResidues) {
+ res = chain->residue[i];
+ if (res) res->RemoveMask ( mask[k] );
+ i++;
+ }
+ }
+ } else if (selAND)
+ switch (sType) {
+ case STYPE_ATOM : chain->UnmaskAtoms ( mask[k] ); break;
+ case STYPE_RESIDUE : chain->UnmaskResidues ( mask[k] ); break;
+ default : ;
+ }
+ if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+ chain->RemoveMask ( mask[k] );
+ if (modelSel && (sType>STYPE_CHAIN)) break;
+ }
+ }
+ } else if (selAND)
+ switch (sType) {
+ case STYPE_ATOM : mdl->UnmaskAtoms ( mask[k] ); break;
+ case STYPE_RESIDUE : mdl->UnmaskResidues ( mask[k] ); break;
+ case STYPE_CHAIN : mdl->UnmaskChains ( mask[k] ); break;
+ default : ;
+ }
+ if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+ mdl->RemoveMask ( mask[k] );
+ }
+ }
+
+ // release dynamic memory
+ if (chain_l) delete[] chain_l;
+ if (res_l) delete[] res_l;
+ if (atom_l) delete[] atom_l;
+ if (elem_l) delete[] elem_l;
+ if (altLocs1) delete[] altLocs1;
+ if (aloc_l) delete[] aloc_l;
+
+ MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ void SelManager::Select (
+ int selHnd1, // destination, must be obtained
+ // from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int selHnd2, // source, must be obtained from
+ // NewSelection() and have been
+ // used for selection
+ SELECTION_KEY sKey // selection key
+ ) {
+ // SKEY_XOR works only downward the hierarchy!
+ PAtom atom;
+ PResidue res;
+ PChain chain;
+ PModel model;
+ int k1,k2,i,j,l,n,nsel;
+ SELECTION_KEY sk;
+
+ if ((selHnd1<=0) || (selHnd1>nSelections) ||
+ (selHnd2<=0) || (selHnd2>nSelections) || (nAtoms<=0)) return;
+
+ k1 = selHnd1-1;
+ k2 = selHnd2-1;
+ sk = sKey;
+
+ if ((selType[k1]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k1] = sType;
+ else if (selType[k1]!=sType) return;
+
+ if (selType[k2]==STYPE_UNDEFINED) return;
+
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k1];i++)
+ if (selection[k1][i])
+ selection[k1][i]->RemoveMask ( mask[k1] );
+ nSelItems[k1] = 0;
+ sk = SKEY_OR;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k1]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k1];
+ break;
+ case SKEY_AND : if (nSelItems[k1]==0) return;
+ sk = SKEY_XAND;
+ nsel = 0;
+ break;
+ case SKEY_XOR : nsel = nSelItems[k1]; break;
+ case SKEY_CLR : nsel = nSelItems[k1];
+ if (nsel<=0) return;
+ break;
+ default : return;
+ }
+
+
+ switch (selType[k2]) {
+
+ case STYPE_ATOM :
+ for (i=0;i<nSelItems[k2];i++) {
+ atom = (PAtom)selection[k2][i];
+ if (atom) {
+ if (!atom->Ter)
+ SelectObject ( sType,atom,k1,sk,nsel );
+ }
+ }
+ break;
+
+ case STYPE_RESIDUE :
+ for (i=0;i<nSelItems[k2];i++) {
+ res = (PResidue)selection[k2][i];
+ if (res)
+ switch (sType) {
+ case STYPE_ATOM : for (j=0;j<res->nAtoms;j++) {
+ atom = res->atom[j];
+ if (atom) {
+ if (!atom->Ter)
+ SelectObject (atom,k1,sk,nsel);
+ }
+ }
+ break;
+ case STYPE_RESIDUE : //if (res->chain)
+ SelectObject ( res,k1,sk,nsel );
+ break;
+ case STYPE_CHAIN : if (res->chain)
+ SelectObject ( res->chain,k1,
+ sk,nsel );
+ break;
+ case STYPE_MODEL : if (res->chain) {
+ if (res->chain->model)
+ SelectObject ( res->chain->model,
+ k1,sk,nsel );
+ }
+ default : ;
+ }
+ }
+ break;
+
+ case STYPE_CHAIN :
+ for (i=0;i<nSelItems[k2];i++) {
+ chain = (PChain)selection[k2][i];
+ if (chain)
+ switch (sType) {
+ case STYPE_ATOM : for (j=0;j<chain->nResidues;j++) {
+ res = chain->residue[j];
+ if (res)
+ for (l=0;l<res->nAtoms;l++) {
+ atom = res->atom[l];
+ if (atom) {
+ if (!atom->Ter)
+ SelectObject ( atom,k1,
+ sk,nsel );
+ }
+ }
+ }
+ break;
+ case STYPE_RESIDUE : for (j=0;j<chain->nResidues;j++) {
+ res = chain->residue[j];
+ if (res)
+ SelectObject ( res,k1,sk,nsel );
+ }
+ break;
+ case STYPE_CHAIN : //if (chain->model)
+ SelectObject ( chain,k1,sk,nsel );
+ break;
+ case STYPE_MODEL : if (chain->model)
+ SelectObject ( chain->model,k1,
+ sk,nsel );
+ default : ;
+ }
+ }
+ break;
+
+ case STYPE_MODEL :
+ for (i=0;i<nSelItems[k2];i++) {
+ model = (PModel)selection[k2][i];
+ if (model)
+ switch (sType) {
+ case STYPE_ATOM :
+ for (j=0;j<model->nChains;j++) {
+ chain = model->chain[j];
+ if (chain)
+ for (l=0;l<chain->nResidues;l++) {
+ res = chain->residue[l];
+ if (res)
+ for (n=0;n<res->nAtoms;n++) {
+ atom = res->atom[n];
+ if (atom) {
+ if (!atom->Ter)
+ SelectObject ( atom,k1,sk,nsel );
+ }
+ }
+ }
+ }
+ break;
+ case STYPE_RESIDUE :
+ for (j=0;j<model->nChains;j++) {
+ chain = model->chain[j];
+ if (chain)
+ for (l=0;l<chain->nResidues;l++) {
+ res = chain->residue[j];
+ if (res)
+ SelectObject ( res,k1,sk,nsel );
+ }
+ }
+ break;
+ case STYPE_CHAIN : for (j=0;j<model->nChains;j++) {
+ chain = model->chain[j];
+ if (chain)
+ SelectObject (chain,k1,sk,nsel);
+ }
+ break;
+ case STYPE_MODEL : SelectObject ( model,k1,sk,nsel );
+ default : ;
+ }
+ }
+ break;
+
+ default : ;
+
+ }
+
+ if (sKey==SKEY_AND)
+ for (i=0;i<nSelItems[k1];i++)
+ if (selection[k1][i])
+ selection[k1][i]->XadMask ( mask[k1] );
+
+ MakeSelIndex ( selHnd1,sType,nsel );
+
+ }
+
+ void SelManager::SelectProperty (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_PROPERTY propKey, // property key
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ SELECTION_KEY sKey // selection key
+ ) {
+ PModel mdl;
+ PChain chain;
+ PResidue res;
+ int i,k,selHnd1,nsel, m,c,r;
+ bool doSelect;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0)) return;
+
+ k = selHnd-1;
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ if (sType!=STYPE_RESIDUE) {
+ selHnd1 = NewSelection();
+ if ((sKey==SKEY_AND) || (sKey==SKEY_CLR))
+ Select ( selHnd1,STYPE_RESIDUE,selHnd,SKEY_NEW );
+ } else
+ selHnd1 = selHnd;
+
+ k = selHnd1-1;
+ selType[k] = STYPE_RESIDUE;
+ sk = sKey;
+
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ sk = SKEY_OR;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : if (nSelItems[k]==0) return;
+ sk = SKEY_XAND;
+ nsel = 0;
+ break;
+ case SKEY_XOR : nsel = nSelItems[k]; break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ default : return;
+ }
+
+ if ((sKey==SKEY_AND) || (sKey==SKEY_CLR)) {
+
+ for (i=0;i<nSelItems[k];i++) {
+ res = (PResidue)selection[k][i];
+ if (res) {
+ switch (propKey) {
+ case SELPROP_Solvent : doSelect = res->isSolvent();
+ break;
+ case SELPROP_Aminoacid : doSelect = res->isAminoacid();
+ break;
+ case SELPROP_Nucleotide : doSelect = res->isNucleotide();
+ break;
+ case SELPROP_Sugar : doSelect = res->isSugar();
+ break;
+ case SELPROP_ModRes : doSelect = res->isModRes();
+ break;
+ default : doSelect = false;
+ }
+ if (doSelect) SelectObject ( res,k,sk,nsel );
+ }
+ }
+
+ if (sKey==SKEY_AND)
+ for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->XadMask ( mask[k] );
+
+ } else {
+
+ for (m=0;m<nModels;m++) {
+ mdl = model[m];
+ if (mdl) {
+ for (c=0;c<mdl->nChains;c++) {
+ chain = mdl->chain[c];
+ if (chain) {
+ for (r=0;r<chain->nResidues;r++) {
+ res = chain->residue[r];
+ if (res) {
+ switch (propKey) {
+ case SELPROP_Solvent : doSelect = res->isSolvent();
+ break;
+ case SELPROP_Aminoacid : doSelect = res->isAminoacid();
+ break;
+ case SELPROP_Nucleotide : doSelect = res->isNucleotide();
+ break;
+ case SELPROP_Sugar : doSelect = res->isSugar();
+ break;
+ case SELPROP_ModRes : doSelect = res->isModRes();
+ break;
+ default : doSelect = false;
+ }
+ if (doSelect) SelectObject ( res,k,sk,nsel );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+
+ MakeSelIndex ( selHnd1,STYPE_RESIDUE,nsel );
+
+ if (sType!=STYPE_RESIDUE) {
+ Select ( selHnd,sType,selHnd1,SKEY_NEW );
+ DeleteSelection ( selHnd1 );
+ }
+
+ }
+
+
+ void SelManager::SelectUDD (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int UDDhandle, // UDD handle
+ int selMin, // lower selection boundary
+ int selMax, // upper selection boundary
+ SELECTION_KEY sKey // selection key
+ ) {
+ PModel mdl;
+ PChain chain;
+ PResidue res;
+ PAtom atom;
+ int i,k,nsel,iudd, n,c,r,a;
+ bool selAND;
+ SELECTION_KEY sk;
+
+ k = selHnd-1;
+ sk = sKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+
+ if ((selHnd<=0) || (selHnd>nSelections)) return;
+
+ switch (sType) {
+ case STYPE_ATOM : if ((UDDhandle & UDRF_ATOM)==0) return;
+ break;
+ case STYPE_RESIDUE : if ((UDDhandle & UDRF_RESIDUE)==0) return;
+ break;
+ case STYPE_CHAIN : if ((UDDhandle & UDRF_CHAIN)==0) return;
+ break;
+ case STYPE_MODEL : if ((UDDhandle & UDRF_MODEL)==0) return;
+ break;
+ default : return;
+ }
+
+
+ // if something goes wrong, sk should be assigned SKEY_OR if
+ // selKey is set to SKEY_NEW or SKEY_OR below
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : if (nSelItems[k]==0) return;
+ nsel = 0;
+ break;
+ case SKEY_XOR : nsel = nSelItems[k]; break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ default : return;
+ }
+
+ selAND = (sKey==SKEY_AND);
+
+
+ for (n=0;n<nModels;n++) {
+
+ mdl = model[n];
+ if (mdl) { // check for safety
+
+ if (sType==STYPE_MODEL) {
+
+ mdl->getUDData ( UDDhandle,iudd );
+ if ((selMin<=iudd) && (iudd<=selMax))
+ SelectObject ( mdl,k,sk,nsel );
+ else if (selAND)
+ mdl->RemoveMask ( mask[k] );
+
+ } else {
+
+ for (c=0;c<mdl->nChains;c++) {
+
+ chain = mdl->chain[c];
+ if (chain) { // again check for safety
+
+ if (sType==STYPE_CHAIN) {
+ chain->getUDData ( UDDhandle,iudd );
+ if ((selMin<=iudd) && (iudd<=selMax))
+ SelectObject ( chain,k,sk,nsel );
+ else if (selAND)
+ chain->RemoveMask ( mask[k] );
+
+ } else {
+
+ for (r=0;r<chain->nResidues;r++) {
+
+ res = chain->residue[r];
+ if (res) {
+
+ if (sType==STYPE_RESIDUE) {
+ res->getUDData ( UDDhandle,iudd );
+ if ((selMin<=iudd) && (iudd<=selMax))
+ SelectObject ( res,k,sk,nsel );
+ else if (selAND)
+ res->RemoveMask ( mask[k] );
+
+ } else {
+
+ for (a=0;a<res->nAtoms;a++) {
+ atom = res->atom[a];
+ if (atom) {
+ if (!atom->Ter) {
+ atom->getUDData ( UDDhandle,iudd );
+ if ((selMin<=iudd) && (iudd<=selMax))
+ SelectObject ( atom,k,sk,nsel );
+ else if (selAND)
+ atom->RemoveMask ( mask[k] );
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ void SelManager::SelectUDD (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int UDDhandle, // UDD handle
+ realtype selMin, // lower selection boundary
+ realtype selMax, // upper selection boundary
+ SELECTION_KEY sKey // selection key
+ ) {
+ PModel mdl;
+ PChain chain;
+ PResidue res;
+ PAtom atom;
+ realtype rudd;
+ int i,k,nsel, n,c,r,a;
+ bool selAND;
+ SELECTION_KEY sk;
+
+ k = selHnd-1;
+ sk = sKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+
+ if ((selHnd<=0) || (selHnd>nSelections)) return;
+
+ switch (sType) {
+ case STYPE_ATOM : if ((UDDhandle & UDRF_ATOM)==0) return;
+ break;
+ case STYPE_RESIDUE : if ((UDDhandle & UDRF_RESIDUE)==0) return;
+ break;
+ case STYPE_CHAIN : if ((UDDhandle & UDRF_CHAIN)==0) return;
+ break;
+ case STYPE_MODEL : if ((UDDhandle & UDRF_MODEL)==0) return;
+ break;
+ default : return;
+ }
+
+
+ // if something goes wrong, sk should be assigned SKEY_OR if
+ // selKey is set to SKEY_NEW or SKEY_OR below
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : if (nSelItems[k]==0) return;
+ nsel = 0;
+ break;
+ case SKEY_XOR : nsel = nSelItems[k]; break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ default : return;
+ }
+
+ selAND = (sKey==SKEY_AND);
+
+
+ for (n=0;n<nModels;n++) {
+
+ mdl = model[n];
+ if (mdl) { // check for safety
+
+ if (sType==STYPE_MODEL) {
+
+ mdl->getUDData ( UDDhandle,rudd );
+ if ((selMin<=rudd) && (rudd<=selMax))
+ SelectObject ( mdl,k,sk,nsel );
+ else if (selAND)
+ mdl->RemoveMask ( mask[k] );
+
+ } else {
+
+ for (c=0;c<mdl->nChains;c++) {
+
+ chain = mdl->chain[c];
+ if (chain) { // again check for safety
+
+ if (sType==STYPE_CHAIN) {
+ chain->getUDData ( UDDhandle,rudd );
+ if ((selMin<=rudd) && (rudd<=selMax))
+ SelectObject ( chain,k,sk,nsel );
+ else if (selAND)
+ chain->RemoveMask ( mask[k] );
+
+ } else {
+
+ for (r=0;r<chain->nResidues;r++) {
+
+ res = chain->residue[r];
+ if (res) {
+
+ if (sType==STYPE_RESIDUE) {
+ res->getUDData ( UDDhandle,rudd );
+ if ((selMin<=rudd) && (rudd<=selMax))
+ SelectObject ( res,k,sk,nsel );
+ else if (selAND)
+ res->RemoveMask ( mask[k] );
+
+ } else {
+
+ for (a=0;a<res->nAtoms;a++) {
+ atom = res->atom[a];
+ if (atom) {
+ if (!atom->Ter) {
+ atom->getUDData ( UDDhandle,rudd );
+ if ((selMin<=rudd) && (rudd<=selMax))
+ SelectObject ( atom,k,sk,nsel );
+ else if (selAND)
+ atom->RemoveMask ( mask[k] );
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ bool selSUDD ( cpstr sudd, cpstr selStr, int cmpRule, int ssLen ) {
+ if (!sudd) return false;
+ switch (cmpRule) {
+ case UDSCR_LT : return (strcmp(sudd,selStr)<0);
+ case UDSCR_LE : return (strcmp(sudd,selStr)<=0);
+ case UDSCR_EQ : return (strcmp(sudd,selStr)==0);
+ case UDSCR_NE : return (strcmp(sudd,selStr)!=0);
+ case UDSCR_GE : return (strcmp(sudd,selStr)>=0);
+ case UDSCR_GT : return (strcmp(sudd,selStr)>=0);
+ case UDSCR_LTcase : return (strcasecmp(sudd,selStr)<0);
+ case UDSCR_LEcase : return (strcasecmp(sudd,selStr)<=0);
+ case UDSCR_EQcase : return (strcasecmp(sudd,selStr)==0);
+ case UDSCR_NEcase : return (strcasecmp(sudd,selStr)!=0);
+ case UDSCR_GEcase : return (strcasecmp(sudd,selStr)>=0);
+ case UDSCR_GTcase : return (strcasecmp(sudd,selStr)>=0);
+ case UDSCR_LTn : return (strncmp(sudd,selStr,ssLen)<0);
+ case UDSCR_LEn : return (strncmp(sudd,selStr,ssLen)<=0);
+ case UDSCR_EQn : return (strncmp(sudd,selStr,ssLen)==0);
+ case UDSCR_NEn : return (strncmp(sudd,selStr,ssLen)!=0);
+ case UDSCR_GEn : return (strncmp(sudd,selStr,ssLen)>=0);
+ case UDSCR_GTn : return (strncmp(sudd,selStr,ssLen)>=0);
+ case UDSCR_LTncase : return (strncasecmp(sudd,selStr,ssLen)<0);
+ case UDSCR_LEncase : return (strncasecmp(sudd,selStr,ssLen)<=0);
+ case UDSCR_EQncase : return (strncasecmp(sudd,selStr,ssLen)==0);
+ case UDSCR_NEncase : return (strncasecmp(sudd,selStr,ssLen)!=0);
+ case UDSCR_GEncase : return (strncasecmp(sudd,selStr,ssLen)>=0);
+ case UDSCR_GTncase : return (strncasecmp(sudd,selStr,ssLen)>=0);
+ case UDSCR_Substr : return (strstr(sudd,selStr)!=NULL);
+ case UDSCR_NoSubstr : return (strstr(sudd,selStr)==NULL);
+ case UDSCR_Substr1 : return (strstr(selStr,sudd)!=NULL);
+ case UDSCR_NoSubstr1 : return (strstr(selStr,sudd)==NULL);
+ default : return false;
+ }
+ }
+
+
+ void SelManager::SelectUDD (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int UDDhandle, // UDD handle
+ cpstr selStr, // selection string
+ int cmpRule, // comparison rule
+ SELECTION_KEY sKey // selection key
+ ) {
+ PModel mdl;
+ PChain chain;
+ PResidue res;
+ PAtom atom;
+ int i,k,nsel,ssLen, n,c,r,a;
+ bool selAND;
+ SELECTION_KEY sk;
+
+ k = selHnd-1;
+ sk = sKey;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+
+ if ((selHnd<=0) || (selHnd>nSelections)) return;
+
+ switch (sType) {
+ case STYPE_ATOM : if ((UDDhandle & UDRF_ATOM)==0) return;
+ break;
+ case STYPE_RESIDUE : if ((UDDhandle & UDRF_RESIDUE)==0) return;
+ break;
+ case STYPE_CHAIN : if ((UDDhandle & UDRF_CHAIN)==0) return;
+ break;
+ case STYPE_MODEL : if ((UDDhandle & UDRF_MODEL)==0) return;
+ break;
+ default : return;
+ }
+
+
+ // if something goes wrong, sk should be assigned SKEY_OR if
+ // selKey is set to SKEY_NEW or SKEY_OR below
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : if (nSelItems[k]==0) return;
+ nsel = 0;
+ break;
+ case SKEY_XOR : nsel = nSelItems[k]; break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ if (nsel<=0) return;
+ break;
+ default : return;
+ }
+
+ selAND = (sKey==SKEY_AND);
+ ssLen = strlen ( selStr );
+
+ for (n=0;n<nModels;n++) {
+
+ mdl = model[n];
+ if (mdl) { // check for safety
+
+ if (sType==STYPE_MODEL) {
+
+ if (selSUDD(mdl->getUDData(UDDhandle),selStr,
+ cmpRule,ssLen))
+ SelectObject ( mdl,k,sk,nsel );
+ else if (selAND)
+ mdl->RemoveMask ( mask[k] );
+
+ } else {
+
+ for (c=0;c<mdl->nChains;c++) {
+
+ chain = mdl->chain[c];
+ if (chain) { // again check for safety
+
+ if (sType==STYPE_CHAIN) {
+ if (selSUDD(chain->getUDData(UDDhandle),selStr,
+ cmpRule,ssLen))
+ SelectObject ( chain,k,sk,nsel );
+ else if (selAND)
+ chain->RemoveMask ( mask[k] );
+
+ } else {
+
+ for (r=0;r<chain->nResidues;r++) {
+
+ res = chain->residue[r];
+ if (res) {
+
+ if (sType==STYPE_RESIDUE) {
+ if (selSUDD(res->getUDData(UDDhandle),selStr,
+ cmpRule,ssLen))
+ SelectObject ( res,k,sk,nsel );
+ else if (selAND)
+ res->RemoveMask ( mask[k] );
+
+ } else {
+
+ for (a=0;a<res->nAtoms;a++) {
+ atom = res->atom[a];
+ if (atom) {
+ if (!atom->Ter) {
+ if (selSUDD(atom->getUDData(UDDhandle),selStr,
+ cmpRule,ssLen))
+ SelectObject ( atom,k,sk,nsel );
+ else if (selAND)
+ atom->RemoveMask ( mask[k] );
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ void SelManager::SelectSphere (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ realtype x, // x-coordinate of the sphere's center
+ realtype y, // y-coordinate of the sphere's center
+ realtype z, // z-coordinate of the sphere's center
+ realtype r, // radius of the sphere
+ SELECTION_KEY sKey // selection key
+ ) {
+ // Selecting a sphere
+ PPAtom A;
+ PAtom atm;
+ PResidue res;
+ PChain chain;
+ PModel mdl;
+ realtype dx,dy,dz, r2;
+ int i,k, nat,nsel, im,ic,ir;
+ bool ASel, resSel,chainSel,modelSel,selAND;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections) || (r<=0.0)) return;
+
+ k = selHnd-1;
+ sk = sKey;
+ A = atom;
+ nat = nAtoms;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ // if something goes wrong, sk should be assigned SKEY_OR if
+ // selKey is set to SKEY_NEW or SKEY_OR below
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : nsel = 0;
+ nat = nSelItems[k];
+ A = (PPAtom)selection[k];
+ break;
+ case SKEY_XOR : nsel = nSelItems[k];
+ break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ nat = nSelItems[k];
+ A = (PPAtom)selection[k];
+ break;
+ default : return;
+ }
+
+ selAND = (sKey==SKEY_AND);
+
+ if ((nat<=0) || (!A)) return;
+
+ r2 = r*r;
+
+ if (sType==STYPE_ATOM) {
+
+ for (i=0;i<nat;i++)
+ if (A[i]) {
+ ASel = (sk!=SKEY_AND);
+ if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates)) {
+ dx = fabs(A[i]->x-x);
+ if (dx<=r) {
+ dy = fabs(A[i]->y-y);
+ if (dy<=r) {
+ dz = fabs(A[i]->z-z);
+ if (dz<=r) {
+ if (dx*dx+dy*dy+dz*dz<=r2) {
+ ASel = true;
+ SelectAtom ( A[i],k,sk,nsel );
+ }
+ }
+ }
+ }
+ }
+ if (!ASel) A[i]->RemoveMask ( mask[k] );
+ }
+
+ } else {
+
+ for (im=0;im<nModels;im++) {
+ mdl = model[im];
+ if (mdl) {
+ modelSel = false;
+ for (ic=0;ic<mdl->nChains;ic++) {
+ chain = mdl->chain[ic];
+ if (chain) {
+ chainSel = false;
+ for (ir=0;ir<chain->nResidues;ir++) {
+ res = chain->residue[ir];
+ if (res) {
+ resSel = false;
+ for (i=0;i<res->nAtoms;i++) {
+ atm = res->atom[i];
+ if (atm) {
+ ASel = false;
+ if ((!atm->Ter) &&
+ (atm->WhatIsSet & ASET_Coordinates)) {
+ dx = fabs(atm->x-x);
+ if (dx<=r) {
+ dy = fabs(atm->y-y);
+ if (dy<=r) {
+ dz = fabs(atm->z-z);
+ if (dz<=r) {
+ if (dx*dx+dy*dy+dz*dz<=r2) {
+ SelectObject ( sType,atm,k,sk,nsel );
+ ASel = true;
+ resSel = true;
+ chainSel = true;
+ modelSel = true;
+ }
+ }
+ }
+ }
+ }
+ if (ASel) break; // selType>=STYPE_RESIDUE
+ }
+ }
+ if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+ res->RemoveMask ( mask[k] );
+ if (chainSel && (sType>STYPE_RESIDUE)) break;
+ }
+ }
+ if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+ chain->RemoveMask ( mask[k] );
+ if (modelSel && (sType>STYPE_CHAIN)) break;
+ }
+ }
+ if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+ mdl->RemoveMask ( mask[k] );
+ }
+ }
+
+ }
+
+ MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ void SelManager::SelectCylinder (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ realtype x1, // x-coordinate of the cylinder axis' 1st end
+ realtype y1, // y-coordinate of the cylinder axis' 1st end
+ realtype z1, // z-coordinate of the cylinder axis' 1st end
+ realtype x2, // x-coordinate of the cylinder axis' 2nd end
+ realtype y2, // y-coordinate of the cylinder axis' 2nd end
+ realtype z2, // z-coordinate of the cylinder axis' 2nd end
+ realtype r, // radius of the cylinder
+ SELECTION_KEY sKey // selection key
+ ) {
+ //
+ // Selecting a cylinder
+ //
+ // Method : given a line running through (x1,y1,z1) to (x2,y2,z2) on,
+ // a point (x,y,z) is then projected on it at distance
+ //
+ // c1 = (c^2-a^2+b^2)/(2c),
+ //
+ // from (x1,y1,z1), where
+ // 'a' is the distance between (x,y,z) and (x2,y2,z2)
+ // 'b' is the distance between (x,y,z) and (x1,y1,z1)
+ // 'c' is the distance between (x1,y1,z1) and (x2,y2,z2).
+ // The distance between point (x,y,z) and line is determined as
+ //
+ // h^2 = b^2 - c1^2
+ //
+ // If c1>=0 and c1<=c and h^2<=r^2 then point (x,y,z) is inside
+ // a cylinder of radius 'r' with axis running from point
+ // (x1,y1,z1) to (x2,y2,z2).
+ //
+ PPAtom A;
+ PAtom atm;
+ PResidue res;
+ PChain chain;
+ PModel mdl;
+ realtype dx,dy,dz, c,dc,c1,c2, a2,b2, r2;
+ int i,k, nat,nsel, im,ic,ir;
+ bool resSel,chainSel,modelSel,selAND;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections) || (r<=0.0)) return;
+
+ dx = x1-x2;
+ dy = y1-y2;
+ dz = z1-z2;
+ c2 = dx*dx + dy*dy + dz*dz;
+ if (c2<=0.0) return;
+ c = sqrt(c2);
+ dc = 2.0*c;
+ r2 = r*r;
+
+ k = selHnd-1;
+ sk = sKey;
+ A = atom;
+ nat = nAtoms;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ // if something goes wrong, sk should be assigned SKEY_OR if
+ // selKey is set to SKEY_NEW or SKEY_OR below
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : nsel = 0;
+ nat = nSelItems[k];
+ A = (PPAtom)selection[k];
+ break;
+ case SKEY_XOR : nsel = nSelItems[k];
+ break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ nat = nSelItems[k];
+ A = (PPAtom)selection[k];
+ break;
+ default : return;
+ }
+
+ selAND = (sKey==SKEY_AND);
+
+ if ((nat<=0) || (!A)) return;
+
+ if (sType==STYPE_ATOM) {
+
+ for (i=0;i<nat;i++)
+ if (A[i]) {
+ if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates)) {
+ dx = fabs(A[i]->x-x1);
+ dy = fabs(A[i]->y-y1);
+ dz = fabs(A[i]->z-z1);
+ a2 = dx*dx + dy*dy + dz*dz;
+ dx = fabs(A[i]->x-x2);
+ dy = fabs(A[i]->y-y2);
+ dz = fabs(A[i]->z-z2);
+ b2 = dx*dx + dy*dy + dz*dz;
+ c1 = (c2-a2+b2)/dc;
+ if ((0.0<=c1) && (c1<=c) && (b2-c1*c1<=r2))
+ SelectAtom ( A[i],k,sk,nsel );
+ else if (sk==SKEY_AND)
+ A[i]->RemoveMask ( mask[k] );
+ }
+ }
+
+ } else {
+
+ for (im=0;im<nModels;im++) {
+ mdl = model[im];
+ if (mdl) {
+ modelSel = false;
+ for (ic=0;ic<mdl->nChains;ic++) {
+ chain = mdl->chain[ic];
+ if (chain) {
+ chainSel = false;
+ for (ir=0;ir<chain->nResidues;ir++) {
+ res = chain->residue[ir];
+ if (res) {
+ resSel = false;
+ for (i=0;i<res->nAtoms;i++) {
+ atm = res->atom[i];
+ if (atm) {
+ if ((!atm->Ter) &&
+ (atm->WhatIsSet & ASET_Coordinates)) {
+ dx = fabs(atm->x-x1);
+ dy = fabs(atm->y-y1);
+ dz = fabs(atm->z-z1);
+ a2 = dx*dx + dy*dy + dz*dz;
+ dx = fabs(atm->x-x2);
+ dy = fabs(atm->y-y2);
+ dz = fabs(atm->z-z2);
+ b2 = dx*dx + dy*dy + dz*dz;
+ c1 = (c2-a2+b2)/dc;
+ if ((0.0<=c1) && (c1<=c) && (b2-c1*c1<=r2)) {
+ SelectObject ( sType,atm,k,sk,nsel );
+ resSel = true;
+ chainSel = true;
+ modelSel = true;
+ break; // selType>=STYPE_RESIDUE
+ }
+ }
+ }
+ }
+ if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+ res->RemoveMask ( mask[k] );
+ if (chainSel && (sType>STYPE_RESIDUE)) break;
+ }
+ }
+ if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+ chain->RemoveMask ( mask[k] );
+ if (modelSel && (sType>STYPE_CHAIN)) break;
+ }
+ }
+ if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+ mdl->RemoveMask ( mask[k] );
+ }
+ }
+
+ }
+
+ MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ void SelManager::SelectSlab (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ realtype a, // a-parameter of the plane ax+by+cz=d
+ realtype b, // b-parameter of the plane ax+by+cz=d
+ realtype c, // c-parameter of the plane ax+by+cz=d
+ realtype d, // d-parameter of the plane ax+by+cz=d
+ realtype r, // distance to the plane
+ SELECTION_KEY sKey // selection key
+ ) {
+ //
+ // Selecting all atoms on a given distance from a plane
+ //
+ // Method : the distance between a point (x0,y0,z0) and a plane
+ // defined by equation
+ //
+ // a*x + b*y + c*z = d
+ //
+ // is found as
+ //
+ // h = (d-a*x0-b*y0-c*z0)/sqrt(a^2+b^2+c^2)
+ //
+ // If |h|<d then point (x0,y0,z0) belongs to the slab.
+ //
+ PPAtom A;
+ PAtom atm;
+ PResidue res;
+ PChain chain;
+ PModel mdl;
+ realtype v,h;
+ int i,k, nat,nsel, im,ic,ir;
+ bool resSel,chainSel,modelSel,selAND;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections) || (r<=0.0)) return;
+
+ v = sqrt(a*a + b*b + c*c);
+ if (v<=0.0) return;
+
+ k = selHnd-1;
+ sk = sKey;
+ A = atom;
+ nat = nAtoms;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ // if something goes wrong, sk should be assigned SKEY_OR if
+ // selKey is set to SKEY_NEW or SKEY_OR below
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : nsel = 0;
+ nat = nSelItems[k];
+ A = (PPAtom)selection[k];
+ break;
+ case SKEY_XOR : nsel = nSelItems[k];
+ break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ nat = nSelItems[k];
+ A = (PPAtom)selection[k];
+ break;
+ default : return;
+ }
+
+ selAND = (sKey==SKEY_AND);
+
+ if ((nat<=0) || (!A)) return;
+
+ if (sType==STYPE_ATOM) {
+
+ for (i=0;i<nat;i++)
+ if (A[i]) {
+ if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates)) {
+ h = fabs(d-a*A[i]->x-b*A[i]->y-c*A[i]->z)/v;
+ if (h<=r)
+ SelectAtom ( A[i],k,sk,nsel );
+ else if (sk==SKEY_AND)
+ A[i]->RemoveMask ( mask[k] );
+ }
+ }
+
+ } else {
+
+ for (im=0;im<nModels;im++) {
+ mdl = model[im];
+ if (mdl) {
+ modelSel = false;
+ for (ic=0;ic<mdl->nChains;ic++) {
+ chain = mdl->chain[ic];
+ if (chain) {
+ chainSel = false;
+ for (ir=0;ir<chain->nResidues;ir++) {
+ res = chain->residue[ir];
+ if (res) {
+ resSel = false;
+ for (i=0;i<res->nAtoms;i++) {
+ atm = res->atom[i];
+ if (atm) {
+ if ((!atm->Ter) &&
+ (atm->WhatIsSet & ASET_Coordinates)) {
+ h = fabs(d-a*A[i]->x-b*A[i]->y-c*A[i]->z)/v;
+ if (h<=r) {
+ SelectObject ( sType,atm,k,sk,nsel );
+ resSel = true;
+ chainSel = true;
+ modelSel = true;
+ break; // selType>=STYPE_RESIDUE
+ }
+ }
+ }
+ }
+ if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+ res->RemoveMask ( mask[k] );
+ if (chainSel && (sType>STYPE_RESIDUE)) break;
+ }
+ }
+ if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+ chain->RemoveMask ( mask[k] );
+ if (modelSel && (sType>STYPE_CHAIN)) break;
+ }
+ }
+ if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+ mdl->RemoveMask ( mask[k] );
+ }
+ }
+
+ }
+
+ MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+ void SelManager::SelectNeighbours (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ PPAtom sA, // array of already selected atoms
+ int alen, // length of A
+ realtype d1, // minimal distance to already selected atoms
+ realtype d2, // maximal distance to already selected atoms
+ SELECTION_KEY sKey // selection key
+ ) {
+ // Selecting all atoms on a given distance from already selected
+ PPAtom A;
+ PBrick B;
+ PAtom atm;
+ PResidue res;
+ PChain chain;
+ PModel mdl;
+ realtype x,y,z, dx,dy,dz, dst, d12,d22;
+ int i,j,k, dn, nx,ny,nz, nat,nsel, im,ic,ir;
+ int ix1,ix2,ix, iy1,iy2,iy, iz1,iz2,iz;
+ bool ASel,resSel,chainSel,modelSel,selAND;
+ SELECTION_KEY sk;
+
+ if ((selHnd<=0) || (selHnd>nSelections) ||
+ (d2<=0.0) || (d2<d1)) return;
+
+ k = selHnd-1;
+ sk = sKey;
+ A = atom;
+ nat = nAtoms;
+ d12 = d1*d1;
+ d22 = d2*d2;
+
+ if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+ selType[k] = sType;
+ else if (selType[k]!=sType) return;
+
+ if ((alen<1) || (!sA)) {
+ if ((sKey==SKEY_NEW) || (sKey==SKEY_AND)) {
+ for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ }
+ return;
+ }
+
+ // if something goes wrong, sk should be assigned SKEY_OR if
+ // selKey is set to SKEY_NEW or SKEY_OR below
+ switch (sKey) {
+ case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+ if (selection[k][i])
+ selection[k][i]->RemoveMask ( mask[k] );
+ nSelItems[k] = 0;
+ nsel = 0;
+ break;
+ case SKEY_OR : if (nSelItems[k]==0) sk = SKEY_NEW;
+ nsel = nSelItems[k];
+ break;
+ case SKEY_AND : nsel = 0;
+ nat = nSelItems[k];
+ A = (PPAtom)selection[k];
+ break;
+ case SKEY_XOR : nsel = nSelItems[k];
+ break;
+ case SKEY_CLR : nsel = nSelItems[k];
+ nat = nSelItems[k];
+ A = (PPAtom)selection[k];
+ break;
+ default : return;
+ }
+
+ selAND = (sk==SKEY_AND);
+
+ if ((nat<=0) || (!A)) return;
+
+ MakeBricks ( sA,alen,d2*1.5 );
+ dn = mround(d2/brick_size)+1;
+
+ if (brick && (sType==STYPE_ATOM)) {
+
+ for (i=0;i<nat;i++)
+ if (A[i]) {
+ if (!A[i]->Ter) {
+ ASel = false;
+ GetBrickCoor ( A[i],nx,ny,nz );
+ if (nx<0) nx++;
+ ix1 = IMax ( 0,nx-dn );
+ iy1 = IMax ( 0,ny-dn );
+ iz1 = IMax ( 0,nz-dn );
+ ix2 = IMin ( nbrick_x,nx+dn+1 );
+ iy2 = IMin ( nbrick_y,ny+dn+1 );
+ iz2 = IMin ( nbrick_z,nz+dn+1 );
+ x = A[i]->x;
+ y = A[i]->y;
+ z = A[i]->z;
+ for (ix=ix1;(ix<ix2) && (!ASel);ix++)
+ if (brick[ix])
+ for (iy=iy1;(iy<iy2) && (!ASel);iy++)
+ if (brick[ix][iy])
+ for (iz=iz1;(iz<iz2) && (!ASel);iz++) {
+ B = brick[ix][iy][iz];
+ if (B)
+ for (j=0;(j<B->nAtoms) && (!ASel);j++)
+ if (B->atom[j]!=A[i]) {
+ dx = fabs(x-B->atom[j]->x);
+ if (dx<=d2) {
+ dy = fabs(y-B->atom[j]->y);
+ if (dy<=d2) {
+ dz = fabs(z-B->atom[j]->z);
+ if (dz<=d2) {
+ dst = dx*dx+dy*dy+dz*dz;
+ if ((dst>=d12) && (dst<=d22)) {
+ ASel = true;
+ SelectAtom ( A[i],k,sk,nsel );
+ }
+ }
+ }
+ }
+ }
+ }
+ if ((!ASel) && selAND) A[i]->RemoveMask ( mask[k] );
+ }
+ }
+
+ } else if (brick) {
+
+ for (im=0;im<nModels;im++) {
+ mdl = model[im];
+ if (mdl) {
+ modelSel = false;
+ for (ic=0;ic<mdl->nChains;ic++) {
+ chain = mdl->chain[ic];
+ if (chain) {
+ chainSel = false;
+ for (ir=0;ir<chain->nResidues;ir++) {
+ res = chain->residue[ir];
+ if (res) {
+ resSel = false;
+ for (i=0;(i<res->nAtoms) && (!resSel);i++) {
+ atm = res->atom[i];
+ if (atm) {
+ if ((!atm->Ter) &&
+ (atm->WhatIsSet & ASET_Coordinates)) {
+ GetBrickCoor ( atm,nx,ny,nz );
+ if (nx<0) nx++;
+ ix1 = IMax ( 0,nx-dn );
+ iy1 = IMax ( 0,ny-dn );
+ iz1 = IMax ( 0,nz-dn );
+ ix2 = IMin ( nbrick_x,nx+dn+1 );
+ iy2 = IMin ( nbrick_y,ny+dn+1 );
+ iz2 = IMin ( nbrick_z,nz+dn+1 );
+ x = atm->x;
+ y = atm->y;
+ z = atm->z;
+ for (ix=ix1;(ix<ix2) && (!resSel);ix++)
+ if (brick[ix])
+ for (iy=iy1;(iy<iy2) && (!resSel);iy++)
+ if (brick[ix][iy])
+ for (iz=iz1;(iz<iz2) && (!resSel);iz++) {
+ B = brick[ix][iy][iz];
+ if (B)
+ for (j=0;(j<B->nAtoms) &&
+ (!resSel);j++)
+ if (B->atom[j]!=atm) {
+ dx = fabs(x-B->atom[j]->x);
+ if (dx<=d2) {
+ dy = fabs(y-B->atom[j]->y);
+ if (dy<=d2) {
+ dz = fabs(z-B->atom[j]->z);
+ if (dz<=d2) {
+ dst = dx*dx+dy*dy+dz*dz;
+ if ((dst>=d12) &&
+ (dst<=d22)) {
+ SelectObject ( sType,
+ atm,k,sk,nsel );
+ resSel = true;
+ chainSel = true;
+ modelSel = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+ if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+ res->RemoveMask ( mask[k] );
+ if (chainSel && (sType>STYPE_RESIDUE)) break;
+ }
+ }
+ if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+ chain->RemoveMask ( mask[k] );
+ if (modelSel && (sType>STYPE_CHAIN)) break;
+ }
+ }
+ if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+ mdl->RemoveMask ( mask[k] );
+ }
+ }
+
+ }
+
+ MakeSelIndex ( selHnd,sType,nsel );
+
+ }
+
+
+
+ int TakeChainID ( pstr & p, pstr chainID ) {
+ int RC,k;
+ chainID[0] = char(0);
+ if (*p) {
+ RC = 0;
+ if (*p==':') {
+ // starts with colon <=> empty chain ID
+ chainID[0] = char(0);
+ p++; // advance to residue number
+ } else if (p[1]==':') {
+ // second symbol is colon <=> regular chain ID
+ chainID[0] = *p;
+ chainID[1] = char(0);
+ p++;
+ p++; // advance to residue number
+ } else if (*p=='\'') {
+ // starts with a strip <=> assume empty chain ID
+ chainID[0] = char(0);
+ p++;
+ if (*p=='\'') {
+ // closing strip must be followed by colon
+ p++;
+ if (*p!=':') RC = -1;
+ } else {
+ // no concluding strip <=> could be a strip chain ID,
+ // although this must be captured by 2nd "if"
+ chainID[0] = '\'';
+ chainID[1] = char(0);
+ // assume that residue number is following the strip
+ }
+ } else if ((int(*p)>=int('0')) && (int(*p)<=int('9'))) {
+ // a digit without following semicolon looks very much
+ // like residue number with unspecified empty chain ID
+ chainID[0] = char(0);
+ // assume that p already points on residue number
+ } else {
+ // assume a long chain ID
+ k = 0;
+ while (*p && (*p!=':') && (k<(int)sizeof(ChainID)-1)) {
+ chainID[k++] = *p;
+ p++;
+ }
+ if (*p==':') {
+ chainID[k] = char(0);
+ } else {
+ // a mistake
+ chainID[0] = char(0);
+ RC = -1;
+ }
+ }
+ while (*p==' ') p++;
+ } else
+ RC = 1;
+ return RC;
+ }
+
+ int TakeResID( pstr & p, int & seqNum, pstr inscode ) {
+ char N[100];
+ int i,RC;
+ pstr endptr;
+ RC = 1;
+ inscode[0] = '*';
+ inscode[1] = char(0);
+ seqNum = ANY_RES;
+ if (((*p) &&
+ (int(*p)>=int('0')) && (int(*p)<=int('9'))) || (*p=='-')) {
+ N[0] = *p;
+ p++;
+ i = 1;
+ while ((*p) && (int(*p)>=int('0')) && (int(*p)<=int('9'))) {
+ N[i++] = *p;
+ p++;
+ }
+ N[i] = char(0);
+ seqNum = mround(strtod(N,&endptr));
+ if ((seqNum==0) && (endptr==N))
+ RC = -1;
+ else {
+ RC = 0;
+ if ((*p) && (*p!='-') && (*p!=',') && (*p!=' ')) {
+ inscode[0] = *p;
+ inscode[1] = char(0);
+ p++;
+ } else
+ inscode[0] = char(0);
+ if ((*p=='-') || (*p==',')) p++;
+ }
+ while (*p==' ') p++;
+ }
+ return RC;
+ }
+
+
+ int SelManager::SelectDomain ( int selHnd , cpstr domainRange,
+ SELECTION_TYPE sType,
+ SELECTION_KEY sKey,
+ int modelNo ) {
+ // domainRange is of the following format:
+ // "*", "(all)" - take all file
+ // "-" - take chain without chain ID
+ // "a:Ni-Mj,b:Kp-Lq,..." - take chain a residue number N
+ // insertion code i to residue number M
+ // insertion code j plus chain b
+ // residue number K insertion code p to
+ // residue number L insertion code q and
+ // so on.
+ // "a:,b:..." - take whole chains a and b and so on
+ // "a:,b:Kp-Lq,..." - any combination of the above.
+ ChainID chainID;
+ InsCode insCode1,insCode2;
+ pstr S,p;
+ int seqNum1,seqNum2,rc;
+ SELECTION_KEY selKey1;
+
+ if ((selHnd<=0) || (selHnd>nSelections)) return 1;
+
+ // leave only required residues
+
+ rc = 1;
+ if (!domainRange) rc = 0;
+ else if ((!domainRange[0]) || (domainRange[0]=='*')) rc = 0;
+ else if (!strcasecmp(domainRange,"(all)")) rc = 0;
+ if (!rc) {
+ // select all
+ Select ( selHnd,sType,modelNo,"*",ANY_RES,"*",ANY_RES,"*",
+ "*","*","*","*",sKey );
+ return 0;
+ }
+ if (!strcasecmp(domainRange,"-")) {
+ // select chain without chain ID
+ Select ( selHnd,sType,modelNo,"",ANY_RES,"*",ANY_RES,"*",
+ "*","*","*","*",sKey );
+ return 0;
+ }
+
+ S = new char[strlen(domainRange)+10];
+ strcpy ( S,domainRange );
+ DelSpaces ( S );
+ // UpperCase ( S );
+
+ p = S;
+ rc = 0;
+
+ selKey1 = sKey;
+
+ while ((*p) && (!rc)) {
+
+ if (TakeChainID(p,chainID)<0) rc = -1;
+ else if (TakeResID(p,seqNum1,insCode1)<0) rc = -2;
+ else if (TakeResID(p,seqNum2,insCode2)<0) rc = -3;
+ else {
+ Select ( selHnd,sType,modelNo,chainID,
+ seqNum1,insCode1,seqNum2,insCode2,
+ "*","*","*","*",selKey1 );
+ if (*p==',') p++;
+ if (selKey1==SKEY_NEW) selKey1 = SKEY_OR;
+ }
+
+ }
+
+ delete[] S;
+
+ return rc;
+
+ }
+
+
+ int SelManager::GetSelLength ( int selHnd ) {
+ if ((selHnd>0) && (selHnd<=nSelections))
+ return nSelItems[selHnd-1];
+ else return 0;
+ }
+
+
+ void SelManager::GetSelIndex ( int selHnd,
+ PPAtom & SelAtom,
+ int & nSelAtoms ) {
+ if ((selHnd>0) && (selHnd<=nSelections)) {
+ if (selType[selHnd-1]!=STYPE_ATOM) {
+ SelAtom = NULL;
+ nSelAtoms = 0;
+ } else {
+ SelAtom = (PPAtom)selection[selHnd-1];
+ nSelAtoms = nSelItems[selHnd-1];
+ }
+ } else {
+ SelAtom = NULL;
+ nSelAtoms = 0;
+ }
+ }
+
+ void SelManager::GetSelIndex ( int selHnd,
+ PPResidue & SelResidue,
+ int & nSelResidues ) {
+ if ((selHnd>0) && (selHnd<=nSelections)) {
+ if (selType[selHnd-1]!=STYPE_RESIDUE) {
+ SelResidue = NULL;
+ nSelResidues = 0;
+ } else {
+ SelResidue = (PPResidue)selection[selHnd-1];
+ nSelResidues = nSelItems[selHnd-1];
+ }
+ } else {
+ SelResidue = NULL;
+ nSelResidues = 0;
+ }
+ }
+
+ void SelManager::GetSelIndex ( int selHnd,
+ PPChain & SelChain,
+ int & nSelChains ) {
+ if ((selHnd>0) && (selHnd<=nSelections)) {
+ if (selType[selHnd-1]!=STYPE_CHAIN) {
+ SelChain = NULL;
+ nSelChains = 0;
+ } else {
+ SelChain = (PPChain)selection[selHnd-1];
+ nSelChains = nSelItems[selHnd-1];
+ }
+ } else {
+ SelChain = NULL;
+ nSelChains = 0;
+ }
+ }
+
+ void SelManager::GetSelIndex ( int selHnd,
+ PPModel & SelModel,
+ int & nSelModels ) {
+ if ((selHnd>0) && (selHnd<=nSelections)) {
+ if (selType[selHnd-1]!=STYPE_MODEL) {
+ SelModel = NULL;
+ nSelModels = 0;
+ } else {
+ SelModel = (PPModel)selection[selHnd-1];
+ nSelModels = nSelItems[selHnd-1];
+ }
+ } else {
+ SelModel = NULL;
+ nSelModels = 0;
+ }
+ }
+
+
+ void SelManager::GetAtomStatistics ( int selHnd, RAtomStat AS ) {
+ int i,k;
+ AS.Init();
+ if ((selHnd>0) && (selHnd<=nSelections)) {
+ k = selHnd-1;
+ switch (selType[k]) {
+ case STYPE_MODEL : if (selection[k])
+ for (i=0;i<nSelItems[k];i++)
+ ((PModel)selection[k][i])->
+ CalAtomStatistics ( AS );
+ break;
+ case STYPE_CHAIN : if (selection[k])
+ for (i=0;i<nSelItems[k];i++)
+ ((PChain)selection[k][i])->
+ CalAtomStatistics ( AS );
+ break;
+ case STYPE_RESIDUE : if (selection[k])
+ for (i=0;i<nSelItems[k];i++)
+ ((PResidue)selection[k][i])->
+ CalAtomStatistics ( AS );
+ break;
+ case STYPE_ATOM : if (selection[k])
+ for (i=0;i<nSelItems[k];i++)
+ ((PAtom)selection[k][i])->
+ CalAtomStatistics ( AS );
+ break;
+ default : break;
+ }
+ }
+ AS.Finish();
+ }
+
+
+ void SelManager::SelectAtom ( PAtom atom, int maskNo,
+ SELECTION_KEY sKey, int & nsel ) {
+ bool ASel;
+ ASel = atom->CheckMask ( mask[maskNo] );
+ switch (sKey) {
+ default :
+ case SKEY_NEW :
+ case SKEY_OR : if (!ASel) {
+ atom->SetMask ( mask[maskNo] );
+ nsel++;
+ }
+ break;
+ case SKEY_AND : if (ASel) nsel++;
+ break;
+ case SKEY_XOR : if (ASel) {
+ atom->RemoveMask ( mask[maskNo] );
+ nsel--;
+ } else {
+ atom->SetMask ( mask[maskNo] );
+ nsel++;
+ }
+ break;
+ case SKEY_CLR : if (ASel) {
+ atom->RemoveMask ( mask[maskNo] );
+ nsel--;
+ }
+ }
+ }
+
+
+ void SelManager::SelectObject ( SELECTION_TYPE sType,
+ PAtom atm,
+ int maskNo,
+ SELECTION_KEY sKey,
+ int & nsel ) {
+ PMask object;
+ switch (sType) {
+ default :
+ case STYPE_UNDEFINED : return;
+ case STYPE_ATOM : object = atm; break;
+ case STYPE_RESIDUE : object = atm->GetResidue(); break;
+ case STYPE_CHAIN : object = atm->GetChain (); break;
+ case STYPE_MODEL : object = atm->GetModel (); break;
+ }
+ if (!object) return;
+ SelectObject ( object,maskNo,sKey,nsel );
+ }
+
+
+ void SelManager::SelectObject ( PMask object, int maskNo,
+ SELECTION_KEY sKey, int & nsel ) {
+ bool ASel;
+ ASel = object->CheckMask ( mask[maskNo] );
+ switch (sKey) {
+ default :
+ case SKEY_NEW :
+ case SKEY_OR : if (!ASel) {
+ object->SetMask ( mask[maskNo] );
+ nsel++;
+ }
+ break;
+ case SKEY_AND : if (ASel) nsel++;
+ break;
+ case SKEY_XOR : if (ASel) {
+ object->RemoveMask ( mask[maskNo] );
+ nsel--;
+ } else {
+ object->SetMask ( mask[maskNo] );
+ nsel++;
+ }
+ break;
+ case SKEY_CLR : if (ASel) {
+ object->RemoveMask ( mask[maskNo] );
+ nsel--;
+ }
+ break;
+ case SKEY_XAND : if (ASel) {
+ object->RemoveMask ( mask[maskNo] );
+ nsel++;
+ }
+ }
+ }
+
+
+ void SelManager::DeleteSelObjects ( int selHnd ) {
+ PPModel model;
+ PPChain chain;
+ PPResidue res;
+ PPAtom atom;
+ int i,k,nSel;
+
+ if ((selHnd>0) && (selHnd<=nSelections)) {
+
+ k = selHnd-1;
+ nSel = nSelItems[k];
+ switch (selType[k]) {
+
+ case STYPE_MODEL : model = (PPModel)selection[k];
+ for (i=0;i<nSel;i++)
+ delete model[i];
+ break;
+
+ case STYPE_CHAIN : chain = (PPChain)selection[k];
+ for (i=0;i<nSel;i++)
+ delete chain[i];
+ break;
+
+ case STYPE_RESIDUE : res = (PPResidue)selection[k];
+ for (i=0;i<nSel;i++)
+ delete res[i];
+ break;
+
+ case STYPE_ATOM : atom = (PPAtom)selection[k];
+ for (i=0;i<nSel;i++)
+ delete atom[i];
+ break;
+
+ default : ;
+
+ }
+
+ if (selection[k]) delete[] selection[k];
+ selection[k] = NULL;
+ nSelItems[k] = 0;
+
+ }
+
+ }
+
+ // ------------------------------------------------------------------------
+
+ void SelManager::MakeSelIndex ( int selHnd,
+ SELECTION_TYPE sType, int nsel ) {
+ // if nsel is less than 0, the number of selected atoms will
+ // be calculated.
+ PModel mdl;
+ PChain chain;
+ PResidue res;
+ int k,i,j,n,ns,k1,k2, nns;
+
+ if ((selHnd>0) && (selHnd<=nSelections)) {
+ k1 = selHnd-1;
+ k2 = k1+1;
+ } else {
+ k1 = 0;
+ k2 = nSelections;
+ }
+
+ for (k=k1;k<k2;k++) {
+ if (nsel<0) {
+ ns = 0;
+ switch (sType) {
+ case STYPE_ATOM : for (i=0;i<nAtoms;i++)
+ if (atom[i])
+ if (atom[i]->CheckMask(mask[k])) ns++;
+ break;
+ case STYPE_RESIDUE : for (n=0;n<nModels;n++) {
+ mdl = model[n];
+ if (mdl)
+ for (i=0;i<mdl->nChains;i++) {
+ chain = mdl->chain[i];
+ if (chain)
+ for (j=0;j<chain->nResidues;j++) {
+ res = chain->residue[j];
+ if (res)
+ if (res->CheckMask(mask[k])) ns++;
+ }
+ }
+ }
+ break;
+ case STYPE_CHAIN : for (i=0;i<nModels;i++) {
+ mdl = model[i];
+ if (mdl)
+ for (j=0;j<mdl->nChains;j++) {
+ chain = mdl->chain[j];
+ if (chain)
+ if (chain->CheckMask(mask[k])) ns++;
+ }
+ }
+ break;
+ case STYPE_MODEL : for (i=0;i<nModels;i++)
+ if (model[i])
+ if (model[i]->CheckMask(mask[k])) ns++;
+ break;
+ default : ;
+ }
+ } else
+ ns = nsel;
+ if (selection[k]) delete[] selection[k];
+ if (ns>0) {
+ selection[k] = new PMask[ns];
+ nns = 0;
+ switch (sType) {
+ case STYPE_ATOM : for (i=0;i<nAtoms;i++)
+ if (atom[i]) {
+ if (atom[i]->CheckMask(mask[k])) {
+ selection[k][nns++] = atom[i];
+ if (nns>=ns) nns = ns-1;
+ }
+ }
+ break;
+ case STYPE_RESIDUE : for (n=0;n<nModels;n++) {
+ mdl = model[n];
+ if (mdl)
+ for (i=0;i<mdl->nChains;i++) {
+ chain = mdl->chain[i];
+ if (chain)
+ for (j=0;j<chain->nResidues;j++) {
+ res = chain->residue[j];
+ if (res)
+ if (res->CheckMask(mask[k])) {
+ selection[k][nns++] = res;
+ if (nns>=ns) nns = ns-1;
+ }
+ }
+ }
+ }
+ break;
+ case STYPE_CHAIN : for (i=0;i<nModels;i++) {
+ mdl = model[i];
+ if (mdl)
+ for (j=0;j<mdl->nChains;j++) {
+ chain = mdl->chain[j];
+ if (chain)
+ if (chain->CheckMask(mask[k])) {
+ selection[k][nns++] = chain;
+ if (nns>=ns) nns = ns-1;
+ }
+ }
+ }
+ break;
+ case STYPE_MODEL : for (i=0;i<nModels;i++)
+ if (model[i])
+ if (model[i]->CheckMask(mask[k])) {
+ selection[k][nns++] = model[i];
+ if (nns>=ns) nns = ns-1;
+ }
+ break;
+ default : ;
+ }
+
+ } else
+ selection[k] = NULL;
+
+ nSelItems[k] = ns;
+ }
+
+ }
+
+
+ // ------------------- Stream functions ----------------------
+
+
+ void SelManager::write ( io::RFile f ) {
+ int i,sType;
+ byte Version=1;
+
+ f.WriteByte ( &Version );
+
+ CoorManager::write ( f );
+
+ f.WriteInt ( &nSelections );
+ for (i=0;i<nSelections;i++) {
+ StreamWrite ( f,mask[i] );
+ f.WriteInt ( &(nSelItems[i]) );
+ sType = selType[i];
+ f.WriteInt ( &(sType) );
+ }
+
+ }
+
+ void SelManager::read ( io::RFile f ) {
+ int i,sType;
+ byte Version;
+
+ f.ReadByte ( &Version );
+
+ DeleteAllSelections();
+
+ CoorManager::read ( f );
+
+ f.ReadInt ( &nSelections );
+ if (nSelections>0) {
+ mask = new PMask [nSelections];
+ selection = new PPMask[nSelections];
+ nSelItems = new int [nSelections];
+ selType = new SELECTION_TYPE[nSelections];
+ for (i=0;i<nSelections;i++) {
+ mask[i] = NULL;
+ StreamRead ( f,mask[i] );
+ f.ReadInt ( &(nSelItems[i]) );
+ f.ReadInt ( &(sType) );
+ selType [i] = (SELECTION_TYPE)sType;
+ selection[i] = NULL;
+ if (mask[i])
+ MakeSelIndex ( i+1,selType[i],-1 );
+ else nSelItems[i] = 0;
+ }
+ }
+
+ }
+
+
+ MakeStreamFunctions(SelManager)
+
+} // namespace mmdb
+
diff --git a/mmdb2/mmdb_selmngr.h b/mmdb2/mmdb_selmngr.h
new file mode 100644
index 0000000..fab8499
--- /dev/null
+++ b/mmdb2/mmdb_selmngr.h
@@ -0,0 +1,634 @@
+// $Id: mmdb_selmngr.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 15.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : mmdb_selmngr <interface>
+// ~~~~~~~~~
+// Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::Manager ( MMDB atom selection manager )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_SelMngr__
+#define __MMDB_SelMngr__
+
+#include "mmdb_coormngr.h"
+#include "mmdb_mask.h"
+
+namespace mmdb {
+
+ // ======================= SelManager ==========================
+
+ // Selection keys. These specify how the requested selection
+ // operation applies to the existing selection for the given mask:
+ // SKEY_NEW previous selection is wiped out
+ // SKEY_OR new selection is added to the already selected set;
+ // if no selection preexists, SKEY_NEW and SKEY_OR
+ // are equivalent. This key is the default one in
+ // all selection functions.
+ // SKEY_AND new selection is made on the already selected set;
+ // this corresponds to logical 'and' of former and
+ // current selections. If no selection preexists,
+ // no selection will be made.
+ // SKEY_XOR only those atoms will be left which are found
+ // in either former or newly selected sets, but not
+ // in both of them; this corresponds to logical
+ // 'exclusive or' of previous and current selections.
+ // If no selection preexists, it is equivalent to
+ // SKEY_OR.
+ enum SELECTION_KEY {
+ SKEY_NEW = 0,
+ SKEY_OR = 1,
+ SKEY_AND = 2,
+ SKEY_XOR = 3,
+ SKEY_CLR = 4,
+ SKEY_XAND = 100 // used internally
+ };
+
+ // Selection types
+ enum SELECTION_TYPE {
+ STYPE_INVALID = -1,
+ STYPE_UNDEFINED = 0,
+ STYPE_ATOM = 1,
+ STYPE_RESIDUE = 2,
+ STYPE_CHAIN = 3,
+ STYPE_MODEL = 4
+ };
+
+ // Residue properties for SelectProperties()
+ enum SELECTION_PROPERTY {
+ SELPROP_Solvent = 0,
+ SELPROP_Aminoacid = 1,
+ SELPROP_Nucleotide = 2,
+ SELPROP_Sugar = 3,
+ SELPROP_ModRes = 4
+ };
+
+ // comparison rules for SelectUDD function
+ enum UDD_CMP_RULE {
+ UDSCR_LT = 1,
+ UDSCR_LE = 2,
+ UDSCR_EQ = 3,
+ UDSCR_NE = 4,
+ UDSCR_GE = 5,
+ UDSCR_GT = 6,
+ UDSCR_LTcase = 7,
+ UDSCR_LEcase = 8,
+ UDSCR_EQcase = 9,
+ UDSCR_NEcase = 10,
+ UDSCR_GEcase = 11,
+ UDSCR_GTcase = 12,
+ UDSCR_LTn = 13,
+ UDSCR_LEn = 14,
+ UDSCR_EQn = 15,
+ UDSCR_NEn = 16,
+ UDSCR_GEn = 17,
+ UDSCR_GTn = 18,
+ UDSCR_LTncase = 19,
+ UDSCR_LEncase = 20,
+ UDSCR_EQncase = 21,
+ UDSCR_NEncase = 22,
+ UDSCR_GEncase = 23,
+ UDSCR_GTncase = 24,
+ UDSCR_Substr = 25,
+ UDSCR_NoSubstr = 26,
+ UDSCR_Substr1 = 27,
+ UDSCR_NoSubstr1 = 28
+ };
+
+ DefineClass(SelManager);
+ DefineStreamFunctions(SelManager);
+
+ class SelManager : public CoorManager {
+
+ public :
+
+ SelManager ();
+ SelManager ( io::RPStream Object );
+ ~ SelManager();
+
+
+ // ==================== Selecting atoms =======================
+
+ // NewSelection() creates a new selection mask and returns its
+ // handle. A handle is always a positive (non-zero) integer.
+ // Calling NewSelection() is the only way to create a new
+ // selection mask. Notice however that masks will be automatically
+ // copied from another MMDB (see Copy(..) in CMMDBManager) if
+ // coordinates are copied; if this is the case, the mask handles
+ // will be inherited from the source MMDB as well. The masks will
+ // also be automatically deleted (see Delete(..) in CMMDBManager())
+ // if coordinates are deleted.
+ int NewSelection ();
+
+ int GetSelType ( int selHnd ); // returns STYPE_XXXX
+
+ // DeleteSelection(..) deletes the specified selection mask
+ // and removes the corresponding selection attributes from
+ // all atoms, which were selected with this mask. If an atom
+ // was selected also with other mask(s), the other selection(s)
+ // will remain, provided that the corresponding masks are valid.
+ // After DeleteSelection() returns, the corresponding mask
+ // becomes invalid.
+ void DeleteSelection ( int selHnd );
+
+ // DeleteAllSelections() deletes all selection masks and
+ // unselects all atoms in the file. All mask handles become
+ // invalid.
+ void DeleteAllSelections();
+
+ // SelectAtoms(..) selects atoms in the serial number range
+ // of iSer1 to iSer2 by adding them to the set of atoms
+ // marked by the given mask. If iSer1=iSer2=0 then all atoms
+ // are selected. Each atom may be selected by a number of masks
+ // simultaneously.
+ void SelectAtoms ( int selHnd, int iSer1, int iSer2,
+ SELECTION_KEY selKey=SKEY_OR // selection key
+ );
+
+ // SelectAtoms(..) selects atoms with serial numbers given in
+ // vector asn[0..nsn-1].
+ void SelectAtoms ( int selHnd, ivector asn, int nsn,
+ SELECTION_KEY selKey=SKEY_OR // selection key
+ );
+
+ // UnselectAtoms(..) clears the specified mask for atoms in
+ // the serial number range of iSer1 to iSer2. If iSer1=iSer2=0
+ // then all atoms are cleared of the specified mask. If selHnd
+ // is set to 0, then the atoms are cleared of any mask.
+ void UnselectAtoms ( int selHnd, int iSer1, int iSer2 );
+
+ // SelectAtom(..) selects a single atom according to the value
+ // of selection key. If makeIndex is false, then the routine
+ // does not update the selection index. This saves time, but
+ // prevents GetSelIndex(..) from accessing all selected atoms.
+ // In order to update the index after all single-atom selections
+ // are done, use MakeSelIndex(selHnd) found next.
+ void SelectAtom ( int selHnd, PAtom A,
+ SELECTION_KEY selKey=SKEY_OR,
+ bool makeIndex=true );
+
+ // SelectResidue(..), SelectChain(..) and SelectModel(..)
+ // select a single residue, chain or model, or all their
+ // hierarchical descendants depending on the value of sType
+ // (i.e. atoms, residues (in chain and model) and chains
+ // (in model only). Ascending hierarchical objects should be
+ // selected explicitely, e.g. atom->GetResidue()->SelectResidue(..)
+ void SelectResidue ( int selHnd, PResidue Res,
+ SELECTION_TYPE sType,
+ SELECTION_KEY sKey,
+ bool makeIndex );
+ void SelectChain ( int selHnd, PChain chain,
+ SELECTION_TYPE sType,
+ SELECTION_KEY sKey,
+ bool makeIndex );
+ void SelectModel ( int selHnd, PModel mdl,
+ SELECTION_TYPE sType,
+ SELECTION_KEY sKey,
+ bool makeIndex );
+
+
+ // MakeSelIndex(.) calculates selection index for selection
+ // adressed by selHnd. All selection functions except the
+ // SelectAtom(..) above, update selection index automatically.
+ // This function is for use after a series of calls to
+ // SelectAtom(..) with makeIndex parameter set false. This
+ // combination of SelectAtom - MakeSelIndex considerably saves CPU
+ // at extensive selections.
+ // MakeSelIndex(.) returns the number of selected objects.
+ int MakeSelIndex ( int selHnd );
+ void MakeAllSelIndexes();
+
+ // Selecting by atom ID, space condition (a sphere) and some
+ // other bits.
+ void SelectAtoms (
+ int selHnd, // must be obtained from NewSelection()
+ int iModel, // model number; iModel=0 means
+ // 'any model'
+ cpstr Chains, // may be several chains "A,B,W"; "*"
+ // means 'any chain' (in selected
+ // model(s))
+ int ResNo1, // starting residue sequence number
+ cpstr Ins1, // starting residue insertion code; "*"
+ // means 'any code'
+ int ResNo2, // ending residue sequence number.
+ cpstr Ins2, // ending residue insertion code; "*"
+ // means 'any code'. Combination of
+ // ResNo1=ResNo2=ANY_RES and
+ // Ins1=Ins2="*" means 'any residue'
+ // (in selected chain(s))
+ cpstr RNames, // may be several residue names
+ // "ALA,GLU,CIS"; "*" means 'any
+ // residue name'
+ cpstr ANames, // may be several names "CA,CB"; "*"
+ // means 'any atom' (in selected
+ // residue(s))
+ cpstr Elements, // may be several element types
+ // 'H,C,O,CU'; "*" means 'any element'
+ cpstr altLocs, // may be several alternative
+ // locations 'A,B'; "*" means
+ // 'any alternative location'
+ cpstr Segments, // may be several segment IDs
+ // like "S1,S2,A234"; "*" means
+ // 'any segment'
+ cpstr Charges, // may be several charges like
+ // "+1,-2, "; "*" means 'any charge'
+ realtype occ1, // lowest occupancy
+ realtype occ2, // highest occupancy; occ1=occ2<0.0
+ // means "any occupancy"
+ realtype x0, // reference x-point
+ realtype y0, // reference y-point
+ realtype z0, // reference z-point
+ realtype d0, // selection distance from the
+ // reference point; d0<=0.0
+ // means "any distance" and values
+ // of x0, y0 and z0 are ignored
+ SELECTION_KEY selKey=SKEY_OR // selection key
+ );
+
+ // Selecting by just atom ID, no other conditions
+ void SelectAtoms (
+ int selHnd, // must be obtained from NewSelection()
+ int iModel, // model number; iModel=0 means
+ // 'any model'
+ cpstr Chains, // may be several chains "A,B,W"; "*"
+ // means 'any chain' (in selected
+ // model(s))
+ int ResNo1, // starting residue sequence number
+ cpstr Ins1, // starting residue insertion code; "*"
+ // means 'any code'
+ int ResNo2, // ending residue sequence number.
+ cpstr Ins2, // ending residue insertion code; "*"
+ // means 'any code'. Combination of
+ // ResNo1=ResNo2=ANY_RES and
+ // Ins1=Ins2="*" means 'any residue
+ // number' (in selected chain(s))
+ cpstr RNames, // may be several residue names
+ // "ALA,GLU,CIS"; "*" means 'any
+ // residue name'
+ cpstr ANames, // may be several names "CA,CB"; "*"
+ // means 'any atom' (in selected
+ // residue(s))
+ cpstr Elements, // may be several element types
+ // "H,C,O,CU"; "*" means 'any element'
+ cpstr altLocs, // may be several alternative
+ // locations 'A,B'; "*" means
+ // 'any alternative location'
+ SELECTION_KEY selKey=SKEY_OR // selection key
+ );
+
+
+ // Selecting by integer User-Defined Data
+ void SelectUDD (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int UDDhandle, // UDD handle
+ int selMin, // lower selection boundary
+ int selMax, // upper selection boundary
+ SELECTION_KEY sKey // selection key
+ );
+ void SelectUDD (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int UDDhandle, // UDD handle
+ realtype selMin, // lower selection boundary
+ realtype selMax, // upper selection boundary
+ SELECTION_KEY sKey // selection key
+ );
+ void SelectUDD (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int UDDhandle, // UDD handle
+ cpstr selStr, // selection string
+ int cmpRule, // comparison rule
+ SELECTION_KEY sKey // selection key
+ );
+
+
+ // Selecting a sphere
+ void SelectSphere (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ realtype x, // x-coordinate of the sphere's center
+ realtype y, // y-coordinate of the sphere's center
+ realtype z, // z-coordinate of the sphere's center
+ realtype r, // radius of the sphere
+ SELECTION_KEY sKey=SKEY_OR // selection key
+ );
+
+ // Selecting a cylinder
+ void SelectCylinder (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ realtype x1, // x-coordinate of the cylinder axis' 1st end
+ realtype y1, // y-coordinate of the cylinder axis' 1st end
+ realtype z1, // z-coordinate of the cylinder axis' 1st end
+ realtype x2, // x-coordinate of the cylinder axis' 2nd end
+ realtype y2, // y-coordinate of the cylinder axis' 2nd end
+ realtype z2, // z-coordinate of the cylinder axis' 2nd end
+ realtype r, // radius of the cylinder
+ SELECTION_KEY sKey=SKEY_OR // selection key
+ );
+
+ // Selecting all atoms on a given distance from a plane
+ void SelectSlab (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ realtype a, // a-parameter of the plane ax+by+cz=d
+ realtype b, // b-parameter of the plane ax+by+cz=d
+ realtype c, // c-parameter of the plane ax+by+cz=d
+ realtype d, // d-parameter of the plane ax+by+cz=d
+ realtype r, // distance to the plane
+ SELECTION_KEY sKey=SKEY_OR // selection key
+ );
+
+ // Selecting all atoms on a given distance from already selected
+ void SelectNeighbours (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ PPAtom sA, // array of already selected atoms
+ int alen, // length of A
+ realtype d1, // minimal distance to already selected atoms
+ realtype d2, // maximal distance to already selected atoms
+ SELECTION_KEY sKey=SKEY_OR // selection key
+ );
+
+
+ int GetSelLength ( int selHnd );
+
+ // Getting an array of atoms selected for a certain mask
+ void GetSelIndex (
+ int selHnd, // selection mask
+ PPAtom & SelAtom, // continuous index of selected
+ // atoms; application must not
+ // dispose either index or atoms
+ int & nSelAtoms // length of index
+ // [0..nSelectedAtoms-1]
+ );
+
+ // Getting an array of residues selected for a certain mask
+ void GetSelIndex (
+ int selHnd, // selection mask
+ PPResidue & SelResidues, // continuous index of selected
+ // residues; application must
+ // not dispose either index or
+ // residues
+ int & nSelResidues // length of index
+ // [0..nSelResidues-1]
+ );
+
+ // Getting an array of chains selected for a certain mask
+ void GetSelIndex (
+ int selHnd, // selection mask
+ PPChain & SelChains, // continuous index of selected
+ // chains; application must not
+ // dispose either index or chains
+ int & nSelChains // length of index
+ // [0..nSelChains-1]
+ );
+
+ // Getting an array of models selected for a certain mask
+ void GetSelIndex (
+ int selHnd, // selection mask
+ PPModel & SelModels, // continuous index of selected
+ // models; application must not
+ // dispose either index or models
+ int & nSelModels // length of index
+ // [0..nSelModels-1]
+ );
+
+ void GetAtomStatistics ( int selHnd, RAtomStat AS );
+
+
+ // =============== General selection functions ================
+
+ // Selecting by atom ID, space condition (a sphere) and some
+ // other bits.
+ void Select (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int iModel, // model number; iModel=0 means
+ // 'any model'
+ cpstr Chains, // may be several chains "A,B,W"; "*"
+ // means 'any chain' (in selected
+ // model(s))
+ int ResNo1, // starting residue sequence number
+ cpstr Ins1, // starting residue insertion code; "*"
+ // means 'any code'
+ int ResNo2, // ending residue sequence number.
+ cpstr Ins2, // ending residue insertion code; "*"
+ // means 'any code'. Combination of
+ // ResNo1=ResNo2=ANY_RES and
+ // Ins1=Ins2="*" means 'any residue'
+ // (in selected chain(s))
+ cpstr RNames, // may be several residue names
+ // "ALA,GLU,CIS"; "*" means
+ // 'any residue name'
+ cpstr ANames, // may be several names "CA,CB"; "*"
+ // means 'any atom' (in selected
+ // residue(s))
+ cpstr Elements, // may be several element types
+ // 'H,C,O,CU'; "*" means 'any element'
+ cpstr altLocs, // may be several alternative
+ // locations 'A,B'; "*" means
+ // 'any alternative location'
+ cpstr Segments, // may be several segment IDs like
+ // "S1,S2,A234"; "*" means
+ // 'any segment'
+ cpstr Charges, // may be several charges like
+ // "+1,-2, "; "*" means 'any charge'
+ realtype occ1, // lowest occupancy
+ realtype occ2, // highest occupancy; occ1=occ2<0.0
+ // means "any occupancy"
+ realtype x0, // reference x-point
+ realtype y0, // reference y-point
+ realtype z0, // reference z-point
+ realtype d0, // selection distance from the
+ // reference point; d0<=0.0
+ // means "any distance" and values
+ // of x0, y0 and z0 are ignored
+ SELECTION_KEY sKey=SKEY_OR // selection key
+ );
+
+
+ // Selecting by just atom ID, no other conditions
+ void Select (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int iModel, // model number; iModel=0 means
+ // 'any model'
+ cpstr Chains, // may be several chains "A,B,W"; "*"
+ // means 'any chain' (in selected
+ // model(s))
+ int ResNo1, // starting residue sequence number
+ cpstr Ins1, // starting residue insertion code; "*"
+ // means 'any code'
+ int ResNo2, // ending residue sequence number.
+ cpstr Ins2, // ending residue insertion code; "*"
+ // means 'any code'. Combination of
+ // ResNo1=ResNo2=ANY_RES and
+ // Ins1=Ins2="*" means 'any residue
+ // number' (in selected chain(s))
+ cpstr RNames, // may be several residue names
+ // "ALA,GLU,CIS"; "*" means
+ // 'any residue name'
+ cpstr ANames, // may be several names "CA,CB"; "*"
+ // means 'any atom' (in selected
+ // residue(s))
+ cpstr Elements, // may be several element types
+ // "H,C,O,CU"; "*" means 'any element'
+ cpstr altLocs, // may be several alternative
+ // locations 'A,B'; "*" means
+ // 'any alternative location'
+ SELECTION_KEY sKey=SKEY_OR // selection key
+ );
+
+
+ // Selecting by coordinate ID.
+ // Examples:
+ //
+ // 1. /mdl/chn/s1.i1-s2.i2/at[el]:aloc
+ // 2. /mdl/chn/*(res).ic /at[el]:aloc
+ // 3. chn/*(res).ic /at[el]:aloc
+ // 4. s1.i1-s2.i2/at[el]:aloc
+ // 5. s1.i1 /at[el]:aloc
+ // 6. /mdl
+ // 7. chn
+ // 8. s1.i1-s2.i2
+ // 9. (res)
+ // 10. at[el]:aloc
+ // 11. chn//[el]
+ //
+ // mdl - the model's serial number or 0 or '*' for any model
+ // (default).
+ // chn - the chain ID or list of chains 'A,B,C' or '*' for
+ // any chain (default).
+ // s1,s2 - the starting and ending residue sequence numbers
+ // or '*' for any sequence number (default).
+ // i1,i2 - the residues insertion codes or '*' for any
+ // insertion code. If the sequence number other than
+ // '*' is specified, then insertion code defaults to ""
+ // (no insertion code), otherwise the default is '*'.
+ // at - atom name or list of atom names 'CA,N1,O' or '*'
+ // for any atom name (default)
+ // el - chemical element name or list of chemical element
+ // names 'C,N,O' or '*' for any chemical element name
+ // (default)
+ // aloc - the alternative location indicator or '*' for any
+ // alternate location. If the atom name and chemical
+ // element name is specified (both may be '*'), then
+ // the alternative location indicator defaults to ""
+ // (no alternate location), otherwise the default is
+ // '*'.
+ //
+ // All spaces are ignored.
+ //
+ // Returns -1 if numerical format of model is wrong, -2 if
+ // numerical format for sequence number is wrong, and 0
+ // otherwise.
+
+ int Select (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ cpstr CID, // coordinate ID
+ SELECTION_KEY sKey // selection key
+ );
+
+ // Propagating the selection up and down coordinate hierarchy
+ void Select (
+ int selHnd1, // must be obtained from NewSelection()
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ int selHnd2, // must be obtained from NewSelection()
+ // and have been used for selection
+ SELECTION_KEY sKey=SKEY_OR // selection key
+ );
+
+ void SelectProperty (
+ int selHnd, // must be obtained from NewSelection()
+ SELECTION_PROPERTY propKey, // property key SELPROP_XXXXXXX
+ SELECTION_TYPE sType, // selection type STYPE_XXXXX
+ SELECTION_KEY sKey // selection key
+ );
+
+ // In SelectDomain, domainRange is of the following format:
+ // "*", "(all)" - take all file
+ // "-" - take chain without chain ID
+ // "a:Ni-Mj,b:Kp-Lq,..." - take chain a residue number N
+ // insertion code i to residue numberM
+ // insertion code j plus chain b
+ // residue number K insertion code p to
+ // residue number L insertion code q
+ // and so on.
+ // "a:,b:..." - take whole chains a and b and so on
+ // "a:,b:Kp-Lq,..." - any combination of the above.
+ int SelectDomain ( int selHnd , cpstr domainRange,
+ SELECTION_TYPE sType,
+ SELECTION_KEY sKey,
+ int modelNo=1 );
+
+ void DeleteSelObjects ( int selHnd );
+
+
+ protected :
+
+ // --- SELECTION DATA NOT FOR PUBLIC ACCESS
+ int nSelections; // number of selections
+ PPMask mask; // vector of selections
+ SELECTION_TYPE *selType; // vector of selection types
+ ivector nSelItems; // numbers of selected items
+ PPMask * selection; // vector of selected items
+
+ // --------------- Stream I/O -----------------------------
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ void InitSelManager();
+ void SelectAtom ( PAtom atm, int maskNo,
+ SELECTION_KEY sKey, int & nsel );
+ void SelectObject ( SELECTION_TYPE sType, PAtom atm,
+ int maskNo, SELECTION_KEY sKey,
+ int & nsel );
+ void SelectObject ( PMask object, int maskNo,
+ SELECTION_KEY sKey, int & nsel );
+ void MakeSelIndex ( int selHnd, SELECTION_TYPE sType,
+ int nsel );
+
+ void ResetManager();
+
+ PMask GetSelMask ( int selHnd );
+
+ };
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_seqsuperpose.cpp b/mmdb2/mmdb_seqsuperpose.cpp
new file mode 100755
index 0000000..7489850
--- /dev/null
+++ b/mmdb2/mmdb_seqsuperpose.cpp
@@ -0,0 +1,366 @@
+// $Id: mmdb_seqsuperpose.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 19.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : SeqSuperpose <implementation>
+// ~~~~~~~~~
+// **** Classes : mmdb::SeqSuperpose
+// ~~~~~~~~~
+//
+// (C) E.Krissinel 2005-2013
+//
+// =================================================================
+//
+
+#include <math.h>
+#include <string.h>
+
+#include "mmdb_tables.h"
+#include "mmdb_seqsuperpose.h"
+
+namespace mmdb {
+
+ // =================================================================
+
+ SeqSuperpose::SeqSuperpose() {
+ SeqSuperposeInit();
+ }
+
+ SeqSuperpose::~SeqSuperpose() {
+ FreeMemory();
+ }
+
+ void SeqSuperpose::SeqSuperposeInit() {
+ Align = NULL;
+ Mat4Init ( TMatrix ); // superposes Ca1 over Ca2: |T*Ca1 - Ca2|->min
+ Q = -0.5; // Q-score
+ rmsd = MaxReal; // rmsd
+ seqId = MaxReal; // sequence identity
+ _seqId = 0.0; // sequence identity in sequence alignment
+ Nalign = 0; // alignment length
+ c1 = NULL; // sup-n vector: Ca1[i]->Ca2[c1[i]] if c1[i]>=0
+ c2 = NULL; // sup-n vector: Ca2[i]->Ca1[c2[i]] if c2[i]>=0
+ cn1 = NULL; // temporary contact array #1
+ cn2 = NULL; // temporary contact array #2
+ Rmsd0 = 3.0; // quality optimization parameter
+ maxContact = 15.0; // maximal Calpha-pair contact parameter
+ contact = NULL;
+ ncontacts = 0;
+ }
+
+ void SeqSuperpose::FreeMemory() {
+ if (Align) {
+ delete Align;
+ Align = NULL;
+ }
+ FreeVectorMemory ( c1 ,0 );
+ FreeVectorMemory ( c2 ,0 );
+ FreeVectorMemory ( cn1,0 );
+ FreeVectorMemory ( cn2,0 );
+ if (contact) {
+ delete[] contact;
+ contact = NULL;
+ }
+ ncontacts = 0;
+ }
+
+ void makeAAString ( pstr & S, PPAtom C, int nat ) {
+ pstr rname;
+ ResName r1;
+ int i,j;
+ S = new char[nat+1];
+ j = 0;
+ for (i=0;i<nat;i++)
+ if (C[i]) {
+ rname = C[i]->GetResName();
+ if (rname) {
+ Get1LetterCode ( rname,r1 );
+ S[j++] = r1[0];
+ }
+ }
+ S[j] = char(0);
+ }
+
+
+ realtype SeqSuperpose::MatchQuality ( int Nalign, realtype Rmsd,
+ int nres1, int nres2 ) {
+ if (Nalign==0) return 0.0;
+ return MatchQuality2 ( Nalign,Rmsd*Rmsd*Nalign,nres1,nres2 );
+ }
+
+ realtype SeqSuperpose::MatchQuality2 ( int Nalign, realtype dist2,
+ int nres1, int nres2 ) {
+ realtype NormN,Na2,NormR;
+ NormN = nres1*nres2;
+ if (NormN<=0.0) return 0.0;
+ Na2 = Nalign*Nalign;
+ NormR = dist2/(Nalign*Rmsd0*Rmsd0);
+ return Na2/((1.0+NormR)*NormN);
+ }
+
+
+ void SeqSuperpose::MakeContacts ( mat44 & TM, realtype cont_est ) {
+ // Find the closest contacts atoms and makes the correspondence
+ // vectors cn1 and cn2
+ int i,j,i1,i2;
+
+ // 1. Find all contacts in the range of 0.0 - cont_est
+ if (contact) {
+ delete[] contact;
+ contact = NULL;
+ }
+ ncontacts = 0;
+ M->SeekContacts ( Ca2,nCa2,Ca1,nCa1,0.0,cont_est,0,
+ contact,ncontacts,0,&TM,0,
+ BRICK_ON_1 | BRICK_READY );
+
+ // 2. Leave only unique shortest contacts, that is, if Ca1[i]-Ca2[j]
+ // is the shortest contact for atom Ca1[i], it has also to be
+ // the shortest contact for atom Ca2[j].
+
+ if (ncontacts>0) {
+
+ SortContacts ( contact,ncontacts,CNSORT_DINC );
+
+ for (i=0;i<nCa1;i++)
+ cn1[i] = -1;
+ for (i=0;i<nCa2;i++)
+ cn2[i] = -1;
+
+ j = 0;
+ for (i=0;i<ncontacts;i++) {
+ i1 = contact[i].id2;
+ i2 = contact[i].id1;
+ if ((cn1[i1]<0) && (cn2[i2]<0)) {
+ // We only check for unmapped atoms in this version, so that
+ // chain misdirection and wide-angle contacts are accepted.
+ // However, the method itself is meant to be used only with
+ // highly similar chains, so we do not expect difficulties
+ // here. Our purpose here is to get maximum performance at
+ // high-quality input. See SSM code for more rigorous contact
+ // building.
+ if (j<i) contact[j].Copy ( contact[i] );
+ // close contact
+ cn1[i1] = i2;
+ cn2[i2] = i1;
+ j++;
+ }
+ }
+
+ ncontacts = j;
+
+ }
+
+ }
+
+ int SeqSuperpose::makeStructAlignment ( realtype seqThreshold,
+ bool keepBricks ) {
+ pstr S,T;
+ mat44 TM;
+ realtype dist2,maxRMSD2,Q1,Q0,dist20;
+ int i,i1,i2,nal,rc,iter,iter1;
+ char Space;
+
+ S = Align->GetAlignedS();
+ T = Align->GetAlignedT();
+
+ GetVectorMemory ( cn1,nCa1,0 );
+ GetVectorMemory ( c1 ,nCa1,0 );
+ for (i=0;i<nCa1;i++) {
+ cn1[i] = -1;
+ c1 [i] = -1;
+ }
+ GetVectorMemory ( cn2,nCa2,0 );
+ GetVectorMemory ( c2 ,nCa2,0 );
+ for (i=0;i<nCa2;i++) {
+ cn2[i] = -1;
+ c2 [i] = -1;
+ }
+
+ i = 0;
+ i1 = 0;
+ i2 = 0;
+ Space = Align->GetSpace();
+ while (S[i] && (i1<nCa1) && (i2<nCa2)) {
+ if ((S[i]==Space) && (T[i]!=Space)) i2++;
+ else if ((S[i]!=Space) && (T[i]==Space)) i1++;
+ else {
+ if (S[i]==T[i]) {
+ cn1[i1] = i2;
+ cn2[i2] = i1;
+ _seqId += 1.0;
+ }
+ i1++;
+ i2++;
+ }
+ i++;
+ }
+
+ _seqId /= IMax(nCa1,nCa2);
+
+ if (_seqId<seqThreshold) {
+ FreeVectorMemory ( cn1,0 );
+ FreeVectorMemory ( cn2,0 );
+ return SEQSP_SeqThreshold;
+ }
+
+ maxRMSD2 = maxContact*maxContact;
+
+ if ((!keepBricks) || (!M->areBricks()))
+ M->MakeBricks ( Ca2,nCa2,1.25*maxContact );
+
+ Q = -1.0;
+ Q0 = -1.0;
+ iter = 0;
+ iter1 = 0;
+
+ do {
+
+ Q = RMax ( Q,Q0 );
+ iter++;
+
+ rc = SuperposeAtoms ( TM,Ca1,nCa1,Ca2,cn1 );
+
+ if (rc==SPOSEAT_Ok) {
+
+ MakeContacts ( TM,maxContact );
+
+ dist2 = 0.0;
+ for (i=0;i<ncontacts;i++) {
+ contact[i].dist *= contact[i].dist;
+ dist2 += contact[i].dist;
+ }
+
+ dist20 = dist2;
+ nal = ncontacts;
+ Q0 = RMax ( Q0,MatchQuality2(ncontacts,dist2,nCa1,nCa2) );
+ if (ncontacts>0) {
+ i = ncontacts;
+ while (i>3) {
+ i--;
+ dist2 -= contact[i].dist;
+ if (dist2<=i*maxRMSD2) { // rmsd must be within the limits
+ Q1 = MatchQuality2 ( i,dist2,nCa1,nCa2 );
+ if (Q1>Q0) {
+ Q0 = Q1;
+ nal = i;
+ dist20 = dist2;
+ }
+ }
+ }
+ for (i=nal+1;i<ncontacts;i++) {
+ cn1[contact[i].id2] = -1;
+ cn2[contact[i].id1] = -1;
+ }
+ if (Q0>Q) {
+ for (i=0;i<nCa1;i++)
+ c1[i] = cn1[i];
+ for (i=0;i<nCa2;i++)
+ c2[i] = cn2[i];
+ Mat4Copy ( TM,TMatrix );
+ Nalign = nal;
+ rmsd = dist20;
+ iter1 = 0;
+ } else
+ iter1++;
+ }
+
+ }
+
+ if ((!rc) && (iter>100)) rc = SEQSP_IterLimit;
+
+ } while ((rc==SPOSEAT_Ok) && ((Q<Q0) || (iter1>=2)));
+
+ if (Nalign>0) {
+ SuperposeAtoms ( TMatrix,Ca1,nCa1,Ca2,c1 );
+ rmsd = sqrt(rmsd/Nalign); // rmsd
+ seqId = 0.0;
+ for (i=0;i<nCa1;i++)
+ if (c1[i]>=0) {
+ if (!strcasecmp(Ca1[i]->GetResName(),Ca2[c1[i]]->GetResName()))
+ seqId += 1.0;
+ }
+ seqId = seqId/Nalign;
+ } else {
+ rmsd = MaxReal;
+ seqId = 0.0;
+ }
+
+ FreeVectorMemory ( cn1,0 );
+ FreeVectorMemory ( cn2,0 );
+
+ if (!keepBricks) M->RemoveBricks();
+
+ return rc;
+
+ }
+
+
+ int SeqSuperpose::Superpose ( PManager MMDB,
+ PPAtom Calpha1, int nCalpha1,
+ PPAtom Calpha2, int nCalpha2,
+ realtype seqThreshold,
+ bool keepBricks ) {
+ pstr S,T;
+
+ Mat4Init ( TMatrix ); // superposes Ca1 over Ca2: |T*Ca1 - Ca2|->min
+ Q = 0.0; // Q-score
+ rmsd = MaxReal; // rmsd
+ seqId = MaxReal; // sequence identity in structure alignment
+ Nalign = 0; // alignment length in structure alignment
+
+ FreeVectorMemory ( c1,0 );
+ FreeVectorMemory ( c2,0 );
+
+ _seqId = IMin(nCalpha1,nCalpha2);
+ _seqId /= IMax(nCalpha1,nCalpha2);
+
+ if (_seqId<seqThreshold)
+ return SEQSP_SeqThreshold;
+
+ M = MMDB;
+ Ca1 = Calpha1;
+ nCa1 = nCalpha1;
+ Ca2 = Calpha2;
+ nCa2 = nCalpha2;
+
+ makeAAString ( S,Ca1,nCa1 );
+ makeAAString ( T,Ca2,nCa2 );
+
+ if (!Align) Align = new math::Alignment();
+
+ Align->Align ( S,T,math::ALIGN_FREEENDS );
+
+ if (S) delete[] S;
+ if (T) delete[] T;
+
+ return makeStructAlignment ( seqThreshold,keepBricks );
+
+ }
+
+} // namespace mmdb
+
diff --git a/mmdb2/mmdb_seqsuperpose.h b/mmdb2/mmdb_seqsuperpose.h
new file mode 100755
index 0000000..f841dea
--- /dev/null
+++ b/mmdb2/mmdb_seqsuperpose.h
@@ -0,0 +1,134 @@
+// $Id: mmdb_seqsuperpose.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 19.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : SeqSuperpose <interface>
+// ~~~~~~~~~
+// **** Classes : mmdb::SeqSuperpose
+// ~~~~~~~~~
+//
+// (C) E.Krissinel 2005-2013
+//
+// =================================================================
+//
+
+#ifndef __Seq_Superpose__
+#define __Seq_Superpose__
+
+#include "mmdb_manager.h"
+#include "mmdb_math_align.h"
+
+namespace mmdb {
+
+ // =================================================================
+
+ enum SEQSP_RC {
+ SEQSP_Ok = 0,
+ SEQSP_IterLimit = 100,
+ SEQSP_SeqThreshold = 101
+ };
+
+ DefineClass(SeqSuperpose);
+
+ class SeqSuperpose {
+
+ public :
+ mat44 TMatrix; // superposes Ca1 over Ca2: |T*Ca1 - Ca2|->min
+ realtype Q; // Q-score
+ realtype rmsd; // rmsd
+ realtype seqId; // sequence identity in structure alignment
+ realtype _seqId; // sequence identity in sequence alignment
+ int Nalign; // alignment length in structure alignment
+ ivector c1; // sup-n vector: Ca1[i]->Ca2[c1[i]] if c1[i]>=0
+ ivector c2; // sup-n vector: Ca2[i]->Ca1[c2[i]] if c2[i]>=0
+
+ SeqSuperpose();
+ ~SeqSuperpose();
+
+ // Given two sets of atoms, Calpha1 and Calpha2, Superpose(...)
+ // calculates the rotational-translational matrix TMatrix such
+ // that |TMatrix*Calpha1 - Calpha2| is minimal in least-square
+ // terms.
+ // In difference of a full-scale SSM, this simplified version
+ // uses initial superposition from sequence alignment, hence
+ // it should be applied only to similar chains where calculation
+ // time is crucial. seqThreshold specifies a threshold of
+ // sequence identity (0<=seqThreshold<=1), below which
+ // structural alignment is not performed and Superpose(..)
+ // returns SEQSP_SeqThreshold.
+ //
+ // If keepBricks is set True, then space bricks are not
+ // removed in MMDB and may be used in the next call if
+ // vector Calpha2 does not change. This saves computation
+ // time.
+ //
+ // The alignment results return in public fields above:
+ // TMatrix - transformation matrix (1 if not aligned)
+ // Q - quality Q-score (-1 if not aligned)
+ // rmsd - r.m.s.d (MaxReal if not aligned)
+ // seqId - sequence identity in structure alignment
+ // (0 if not aligned)
+ // Nalign - alignment length in structure alignment
+ // (0 if not aligned)
+ // c1,c2 - atom corrspondences:
+ // Calpha1[i] <=> Calpha2[c1[i]]
+ // Calpha2[i] <=> Calpha1[c2[i]]
+ //
+ // Upon success, Superpose(...) returns SEQSP_Ok
+ //
+ int Superpose ( PManager MMDB,
+ PPAtom Calpha1, int nCalpha1,
+ PPAtom Calpha2, int nCalpha2,
+ realtype seqThreshold,
+ bool keepBricks );
+
+ protected :
+ math::PAlignment Align;
+ PManager M; // pointers to
+ PPAtom Ca1,Ca2; // the input data
+ int nCa1,nCa2; // copy chain lengths
+ ivector cn1,cn2; // temporary contact arrays
+ realtype Rmsd0; // quality optimization parameter
+ realtype maxContact; // maximal Calpha-pair contact parameter
+ PContact contact;
+ int ncontacts;
+
+ void SeqSuperposeInit();
+ void FreeMemory ();
+ realtype MatchQuality ( int Nalign, realtype Rmsd,
+ int nres1, int nres2 );
+ realtype MatchQuality2 ( int Nalign, realtype dist2,
+ int nres1, int nres2 );
+ void MakeContacts ( mat44 & TM, realtype cont_est );
+ int makeStructAlignment ( realtype seqThreshold,
+ bool keepBricks );
+
+ };
+
+} // namespace mmdb
+
+#endif
diff --git a/mmdb2/mmdb_symop.cpp b/mmdb2/mmdb_symop.cpp
new file mode 100644
index 0000000..4b8198d
--- /dev/null
+++ b/mmdb2/mmdb_symop.cpp
@@ -0,0 +1,1001 @@
+// $Id: mmdb_symop.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_SymOp <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Classes : mmdb::SymOp ( symmetry operators )
+// ~~~~~~~~~ mmdb::SymOps ( container of symmetry operators )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "mmdb_symop.h"
+
+namespace mmdb {
+
+ // ==================== SymOp ========================
+
+ SymOp::SymOp() : io::Stream() {
+ InitSymOp();
+ }
+
+ SymOp::SymOp ( io::RPStream Object ) : io::Stream(Object) {
+ InitSymOp();
+ }
+
+ SymOp::~SymOp() {
+ FreeMemory();
+ }
+
+ void SymOp::InitSymOp() {
+ int i,j;
+ XYZOp = NULL;
+ for (i=0;i<4;i++) {
+ for (j=0;j<4;j++)
+ T[i][j] = 0.0;
+ T[i][i] = 1.0;
+ }
+ }
+
+ void SymOp::FreeMemory() {
+ if (XYZOp) delete[] XYZOp;
+ XYZOp = NULL;
+ }
+
+ int SymOp::SetSymOp ( cpstr XYZOperation ) {
+ int i,j;
+
+ CreateCopy ( XYZOp,XYZOperation );
+ DelSpaces ( XYZOp );
+
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++)
+ T[i][j] = 0.0;
+
+ i = GetOperation ( 0 );
+ if (!i) i = GetOperation ( 1 );
+ if (!i) i = GetOperation ( 2 );
+ T[3][3] = 1.0;
+
+ return i;
+
+ }
+
+ pstr SymOp::GetSymOp() {
+ if (XYZOp) return XYZOp;
+ else return pstr("");
+ }
+
+
+ int SymOp::GetOperation ( int n ) {
+ char L[100];
+ pstr p1,p2;
+ int len;
+ realtype V;
+
+ p1 = XYZOp;
+ p2 = strchr ( p1,',' );
+ if (!p2) return SYMOP_WrongSyntax;
+ if (n>0) {
+ p1 = p2+1;
+ p2 = strchr ( p1,',' );
+ if (!p2) return SYMOP_WrongSyntax;
+ }
+ if (n>1) {
+ p1 = p2+1;
+ p2 = NULL;
+ }
+
+ if (p2) *p2 = char(0);
+ strcpy ( L,p1 );
+ if (p2) *p2 = ',';
+
+ DelSpaces ( L );
+ if (!L[0]) return SYMOP_WrongSyntax;
+ UpperCase ( L );
+
+ len = strlen ( L );
+ T[n][0] = 0.0;
+ if (L[0]=='X') {
+ T[n][0] += 1.0;
+ L[0] = ' ';
+ }
+ do {
+ p1 = strstr ( L,"+X" );
+ if (p1) {
+ T[n][0] += 1.0;
+ strncpy ( p1," ",2 );
+ }
+ } while (p1);
+ do {
+ p1 = strstr ( L,"-X" );
+ if (p1) {
+ T[n][0] -= 1.0;
+ strncpy ( p1," ",2 );
+ }
+ } while (p1);
+
+ T[n][1] = 0.0;
+ if (L[0]=='Y') {
+ T[n][1] += 1.0;
+ L[0] = ' ';
+ }
+ do {
+ p1 = strstr ( L,"+Y" );
+ if (p1) {
+ T[n][1] += 1.0;
+ strncpy ( p1," ",2 );
+ }
+ } while (p1);
+ do {
+ p1 = strstr ( L,"-Y" );
+ if (p1) {
+ T[n][1] -= 1.0;
+ strncpy ( p1," ",2 );
+ }
+ } while (p1);
+
+ T[n][2] = 0.0;
+ if (L[0]=='Z') {
+ T[n][2] += 1.0;
+ L[0] = ' ';
+ }
+ do {
+ p1 = strstr ( L,"+Z" );
+ if (p1) {
+ T[n][2] += 1.0;
+ strncpy ( p1," ",2 );
+ }
+ } while (p1);
+ do {
+ p1 = strstr ( L,"-Z" );
+ if (p1) {
+ T[n][2] -= 1.0;
+ strncpy ( p1," ",2 );
+ }
+ } while (p1);
+
+ DelSpaces ( L );
+ if ((int)strlen(L)>=len) return SYMOP_NotAnOperation;
+
+ // translational part
+ p1 = L;
+ T[n][3] = strtod ( p1,&p2 );
+ if (*p2=='/') {
+ p1 = p2+1;
+ V = strtod ( p1,&p2 );
+ if (V==0.0) return SYMOP_ZeroDenominator;
+ T[n][3] /= V;
+ }
+
+ return SYMOP_Ok;
+
+ }
+
+ void MakeSign ( pstr S, realtype V, realtype & AV ) {
+ int l;
+ if (V>0.0) {
+ l = strlen ( S );
+ if (l>0) {
+ if (S[l-1]!=',') {
+ strcat ( S,"+" );
+ }
+ }
+ AV = V;
+ } else if (V<0.0) {
+ strcat ( S,"-" );
+ AV = -V;
+ } else {
+ AV = V;
+ return;
+ }
+ }
+
+
+ #define __eps 1.0e-5
+
+ void GenTranslation ( pstr S, realtype V ) {
+ realtype AV,nAV;
+ char N[50];
+ int n,d;
+
+ if (fabs(V)<=__eps) return;
+ MakeSign ( S,V,AV );
+
+ d = 0;
+ n = -1;
+ while ((d<=20) && (n<0)) {
+ d++;
+ nAV = AV*d;
+ n = mround(nAV);
+ if (fabs(nAV-n)>__eps) n = -1;
+ }
+
+ if (d<=1) sprintf ( N,"%i" ,n );
+ else if (n>=0) sprintf ( N,"%i/%i" ,n,d );
+ else sprintf ( N,"%-.10g",AV );
+ strcat ( S,N );
+
+ }
+
+ void GenTransformation ( pstr S, realtype V, pstr Axis ) {
+ realtype AV,nAV;
+ char N[50];
+ int n,d;
+
+ if (fabs(V)<=__eps) return;
+ MakeSign ( S,V,AV );
+
+ if (fabs(AV-1.0)>__eps) {
+
+ d = 0;
+ n = -1;
+ while ((d<=20) && (n<0)) {
+ d++;
+ nAV = AV*d;
+ n = mround(nAV);
+ if (fabs(nAV-n)>__eps) n = -1;
+ }
+
+ if (n>=0) sprintf ( N,"%i/%i*",n,d );
+ else sprintf ( N,"%-.10g*",AV );
+ strcat ( S,N );
+
+ }
+
+ strcat ( S,Axis );
+
+ }
+
+
+ /*
+ void GenTranslation ( pstr S, realtype V ) {
+ realtype AV,fAV;
+ int n,d;
+ char N[50];
+
+ if (V==0.0) return;
+ MakeSign ( S,V,AV );
+
+ n = mround(floor(AV+0.00000001));
+ fAV = AV-n;
+
+ if (fabs(fAV-0.5)<=__eps) { n += 1; d = 2; }
+ else if (fabs(fAV-0.25)<=__eps) { n += 1; d = 4; }
+ else if (fabs(fAV-0.75)<=__eps) { n += 3; d = 4; }
+ else if (fabs(fAV-0.33333333333)<=__eps) { n += 1; d = 3; }
+ else if (fabs(fAV-0.66666666666)<=__eps) { n += 2; d = 3; }
+ else if (fabs(fAV-0.16666666666)<=__eps) { n += 1; d = 6; }
+ else if (fabs(fAV-0.83333333333)<=__eps) { n += 5; d = 6; }
+ else d = 1;
+
+ N[0] = char(0);
+ if (d>1) sprintf ( N,"%i/%i",n,d );
+ else if (n>0) sprintf ( N,"%i",n );
+ else ParamStr ( N,pstr(""),AV );
+ strcat ( S,N );
+
+ }
+
+ void GenTransformation ( pstr S, realtype V, pstr Axis ) {
+ realtype AV;
+
+ if (V==0.0) return;
+ MakeSign ( S,V,AV );
+
+ if (fabs(AV-0.5)<=__eps) strcat ( S,"1/2*" );
+ else if (fabs(AV-0.25)<=__eps) strcat ( S,"1/4*" );
+ else if (fabs(AV-0.75)<=__eps) strcat ( S,"3/4*" );
+ else if (fabs(AV-0.33333333333)<=__eps) strcat ( S,"1/3*" );
+ else if (fabs(AV-0.66666666666)<=__eps) strcat ( S,"2/3*" );
+ else if (fabs(AV-0.16666666666)<=__eps) strcat ( S,"1/6*" );
+ else if (fabs(AV-0.83333333333)<=__eps) strcat ( S,"5/6*" );
+ else if (fabs(AV-1.0)>__eps) ParamStr ( S,pstr(""),AV,
+ 10,pstr("*") );
+
+ strcat ( S,Axis );
+
+ }
+
+ */
+
+ bool SymOp::CompileOpTitle ( pstr S ) {
+ return CompileOpTitle ( S,T,true );
+ }
+
+ bool SymOp::CompileOpTitle ( pstr S, mat44 symMat,
+ bool compare ) {
+ S[0] = char(0);
+ GenTransformation ( S,symMat[0][0],pstr("X") );
+ GenTransformation ( S,symMat[0][1],pstr("Y") );
+ GenTransformation ( S,symMat[0][2],pstr("Z") );
+ GenTranslation ( S,symMat[0][3] );
+ strcat ( S,"," );
+ GenTransformation ( S,symMat[1][0],pstr("X") );
+ GenTransformation ( S,symMat[1][1],pstr("Y") );
+ GenTransformation ( S,symMat[1][2],pstr("Z") );
+ GenTranslation ( S,symMat[1][3] );
+ strcat ( S,"," );
+ GenTransformation ( S,symMat[2][0],pstr("X") );
+ GenTransformation ( S,symMat[2][1],pstr("Y") );
+ GenTransformation ( S,symMat[2][2],pstr("Z") );
+ GenTranslation ( S,symMat[2][3] );
+ DelSpaces ( S );
+ if ((!compare) || (!strcmp(S,XYZOp))) return true;
+ else {
+ S[0] = char(0);
+ GenTranslation ( S,symMat[0][3] );
+ GenTransformation ( S,symMat[0][0],pstr("X") );
+ GenTransformation ( S,symMat[0][1],pstr("Y") );
+ GenTransformation ( S,symMat[0][2],pstr("Z") );
+ strcat ( S,"," );
+ GenTranslation ( S,symMat[1][3] );
+ GenTransformation ( S,symMat[1][0],pstr("X") );
+ GenTransformation ( S,symMat[1][1],pstr("Y") );
+ GenTransformation ( S,symMat[1][2],pstr("Z") );
+ strcat ( S,"," );
+ GenTranslation ( S,symMat[2][3] );
+ GenTransformation ( S,symMat[2][0],pstr("X") );
+ GenTransformation ( S,symMat[2][1],pstr("Y") );
+ GenTransformation ( S,symMat[2][2],pstr("Z") );
+ DelSpaces ( S );
+ if (!strcmp(S,XYZOp)) return true;
+ }
+ return false;
+ }
+
+ void SymOp::Transform ( realtype & x, realtype & y, realtype & z ) {
+ realtype x1,y1,z1;
+ x1 = T[0][0]*x + T[0][1]*y + T[0][2]*z + T[0][3];
+ y1 = T[1][0]*x + T[1][1]*y + T[1][2]*z + T[1][3];
+ z1 = T[2][0]*x + T[2][1]*y + T[2][2]*z + T[2][3];
+ x = x1;
+ y = y1;
+ z = z1;
+ }
+
+ void SymOp::GetTMatrix ( mat44 & TMatrix ) {
+ // copies T to TMatrix
+ int i,j;
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++)
+ TMatrix[i][j] = T[i][j];
+ }
+
+ void SymOp::SetTMatrix ( mat44 & TMatrix ) {
+ // copies TMatrix to T
+ int i,j;
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++)
+ T[i][j] = TMatrix[i][j];
+ }
+
+
+ void SymOp::Print() {
+ int i;
+ printf ( " operation '%s'\n",XYZOp );
+ for (i=0;i<4;i++)
+ printf ( " %10.3g %10.3g %10.3g %10.3g\n",
+ T[i][0],T[i][1],T[i][2],T[i][3] );
+ }
+
+ void SymOp::Copy ( PSymOp SymOp ) {
+ int i,j;
+ CreateCopy ( XYZOp,SymOp->XYZOp );
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++)
+ T[i][j] = SymOp->T[i][j];
+ }
+
+ void SymOp::write ( io::RFile f ) {
+ int i,j;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.CreateWrite ( XYZOp );
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++)
+ f.WriteReal ( &(T[i][j]) );
+ }
+
+ void SymOp::read ( io::RFile f ) {
+ int i,j;
+ byte Version;
+ f.ReadByte ( &Version );
+ f.CreateRead ( XYZOp );
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++)
+ f.ReadReal ( &(T[i][j]) );
+ }
+
+ MakeStreamFunctions(SymOp)
+
+
+
+ // ==================== SymOps ========================
+
+ SymOps::SymOps() : io::Stream() {
+ InitSymOps();
+ }
+
+ SymOps::SymOps ( io::RPStream Object ) : io::Stream(Object) {
+ InitSymOps();
+ }
+
+ SymOps::~SymOps() {
+ FreeMemory();
+ }
+
+ void SymOps::InitSymOps() {
+ SpGroup = NULL;
+ Nops = 0;
+ symOp = NULL;
+ }
+
+ void SymOps::FreeMemory() {
+ int i;
+ if (SpGroup) delete[] SpGroup;
+ SpGroup = NULL;
+ if (symOp) {
+ for (i=0;i<Nops;i++)
+ if (symOp[i]) delete symOp[i];
+ delete[] symOp;
+ symOp = NULL;
+ }
+ Nops = 0;
+ }
+
+ #define symop_file cpstr("symop.lib")
+
+ int SymOps::SetGroupSymopLib ( cpstr SpaceGroup,
+ cpstr symop_lib ) {
+ char S[500];
+ char G[100];
+ pstr p;
+ io::File f;
+ int i,RC;
+
+ FreeMemory();
+
+ CreateCopy ( SpGroup,SpaceGroup );
+
+ if (!symop_lib) p = pstr(symop_file);
+ else if (!symop_lib[0]) p = pstr(symop_file);
+ else p = pstr(symop_lib);
+ f.assign ( p,true );
+ if (!f.reset(true)) {
+ p = getenv ( "SYMOP" );
+ if (p)
+ strcpy ( S,p );
+ else {
+ p = getenv ( "CLIBD" );
+ if (p) {
+ strcpy ( S,p );
+ if (S[strlen(S)-1]!='/') strcat ( S,"/" );
+ strcat ( S,"symop.lib" );
+ } else
+ strcpy ( S,"symop.lib" );
+ }
+ f.assign ( S,true );
+ if (!f.reset(true)) return SYMOP_NoLibFile;
+ }
+
+ strcpy ( G," '" );
+ strcat ( G,SpGroup );
+ strcat ( G,"'" );
+ S[0] = char(0);
+ while (!f.FileEnd() && (!strstr(S,G)))
+ f.ReadLine ( S,sizeof(S) );
+ if (f.FileEnd()) {
+ f.shut();
+ return SYMOP_UnknownSpaceGroup;
+ }
+
+ p = S;
+ while (*p==' ') p++;
+ p = strchr ( p,' ' );
+ if (p) Nops = mround(strtod(p,NULL));
+ if (Nops<=0) return SYMOP_NoSymOps;
+
+ symOp = new PSymOp[Nops];
+ RC = SYMOP_Ok;
+ for (i=0;(i<Nops) && (!RC);i++) {
+ f.ReadLine ( S,sizeof(S) );
+ symOp[i] = new SymOp();
+ RC = symOp[i]->SetSymOp ( S );
+ }
+
+ f.shut();
+
+ return RC;
+
+ }
+
+
+ #define syminfo_file cpstr("syminfo.lib")
+
+ int SymOps::SetGroup ( cpstr SpaceGroup,
+ cpstr syminfo_lib ) {
+ io::File f;
+ pstr p;
+ psvector lines,lines1;
+ char S[500];
+ char G[100];
+ char O[100];
+ mat44 T1,T2,T3;
+ int i,j,k,l,m,n,RC;
+ int nlines,npops,ncops;
+
+ FreeMemory();
+
+ npops = 0;
+ ncops = 0;
+
+ CreateCopy ( SpGroup,SpaceGroup );
+
+ if (!syminfo_lib) p = pstr(syminfo_file);
+ else if (!syminfo_lib[0]) p = pstr(syminfo_file);
+ else p = pstr(syminfo_lib);
+ f.assign ( p,true );
+ if (!f.reset(true)) {
+ p = getenv ( "SYMINFO" );
+ if (p)
+ strcpy ( S,p );
+ else {
+ p = getenv ( "CLIBD" );
+ if (p) {
+ strcpy ( S,p );
+ if (S[strlen(S)-1]!='/') strcat ( S,"/" );
+ strcat ( S,"syminfo.lib" );
+ } else
+ strcpy ( S,"syminfo.lib" );
+ }
+ f.assign ( S,true );
+ if (!f.reset(true)) return SYMOP_NoLibFile;
+ }
+
+
+ if (strncasecmp(SpGroup,"Hall:",5)) {
+ // normal space group symbol on input
+ strcpy ( G," '" );
+ strcat ( G,SpGroup );
+ strcat ( G,"'" );
+ S[0] = char(0);
+ while (!f.FileEnd() && !(strstr(S,G) && (strstr(S,"symbol xHM") ||
+ strstr(S,"symbol old"))))
+ f.ReadLine ( S,sizeof(S) );
+ } else {
+ // hall descriptor on input
+ strcpy ( G," ' " );
+ p = &(SpGroup[5]);
+ while (*p==' ') p++;
+ strcat ( G,p );
+ strcat ( G,"'" );
+ S[0] = char(0);
+ while (!f.FileEnd() && !(strstr(S,G) && strstr(S,"symbol Hall")))
+ f.ReadLine ( S,sizeof(S) );
+ }
+ if (f.FileEnd()) {
+ f.shut();
+ return SYMOP_UnknownSpaceGroup;
+ }
+
+ // found spacegroup, move to symop lines
+ while (!f.FileEnd() && (!strstr(S,"symop")))
+ f.ReadLine ( S,sizeof(S) );
+
+ nlines = 256;
+ GetVectorMemory ( lines,nlines,0 );
+ for (i=0;i<nlines;i++)
+ lines[i] = NULL;
+ n = 0;
+ CreateCopy ( lines[n++],S );
+
+ // count primitive operators
+ while (!f.FileEnd() && (strstr(S,"symop"))) {
+ npops++;
+ f.ReadLine ( S,sizeof(S) );
+ if (n>=nlines) {
+ nlines += + 256;
+ GetVectorMemory ( lines1,nlines,0 );
+ for (i=0;i<n;i++)
+ lines1[i] = lines[i];
+ for (i=n;i<nlines;i++)
+ lines1[i] = NULL;
+ FreeVectorMemory ( lines,0 );
+ lines = lines1;
+ }
+ CreateCopy ( lines[n++],S );
+ }
+
+ // count centering operators
+ while (!f.FileEnd() && (strstr(S,"cenop"))) {
+ ncops++;
+ f.ReadLine ( S,sizeof(S) );
+ if (n>=nlines) {
+ nlines += + 256;
+ GetVectorMemory ( lines1,nlines,0 );
+ for (i=0;i<n;i++)
+ lines1[i] = lines[i];
+ for (i=n;i<nlines;i++)
+ lines1[i] = NULL;
+ FreeVectorMemory ( lines,0 );
+ lines = lines1;
+ }
+ CreateCopy ( lines[n++],S );
+ }
+
+ Nops = npops*ncops;
+ symOp = new PSymOp[Nops];
+ RC = SYMOP_Ok;
+
+ n = 0; // start second pass here
+
+ // read primitive operators
+ for (i=0;(i<npops) && (!RC);i++) {
+ symOp[i] = new SymOp();
+ RC = symOp[i]->SetSymOp ( lines[n++]+6 );
+ }
+
+ // loop over non-trivial centering operators, and for each loop
+ // over primtive operators
+ for (i=1;(i<ncops) && (!RC);i++) {
+ n++; // this also skips the identity operator
+ for (j=0;(j<npops) && (!RC);j++) {
+ symOp[i*npops+j] = new SymOp();
+ RC = symOp[i*npops+j]->SetSymOp ( lines[n]+6 );
+ symOp[i*npops+j]->GetTMatrix(T1);
+ symOp[j]->GetTMatrix(T2);
+ for (k=0;k<4;k++)
+ for (l=0;l<4;l++) {
+ T3[k][l] = 0.0;
+ for (m=0;m<4;m++)
+ T3[k][l] += T1[k][m]*T2[m][l];
+ }
+ for (k=0;k<3;k++) // kdc fix
+ T3[k][3] -= floor ( T3[k][3] ); // kdc fix
+ symOp[i*npops+j]->CompileOpTitle ( O,T3,false );
+ symOp[i*npops+j]->SetSymOp ( O );
+ }
+ }
+
+ f.shut();
+
+ for (i=0;i<nlines;i++)
+ if (lines[i]) delete[] lines[i];
+ FreeVectorMemory ( lines,0 );
+
+ return RC;
+
+ }
+
+ /*
+ int SymOps::SetGroup ( cpstr SpaceGroup,
+ cpstr syminfo_lib ) {
+ CFile f;
+ pstr p;
+ char S[500];
+ char G[100];
+ char O[100];
+ mat44 T1,T2,T3;
+ int i,j,k,l,m,RC;
+ int npops,ncops;
+ long symop_start;
+ //fpos_t symop_start;
+
+ FreeMemory();
+
+ npops = 0;
+ ncops = 0;
+
+ CreateCopy ( SpGroup,SpaceGroup );
+
+ if (!syminfo_lib) p = pstr(syminfo_file);
+ else if (!syminfo_lib[0]) p = pstr(syminfo_file);
+ else p = pstr(syminfo_lib);
+ f.assign ( p,true );
+ if (!f.reset(true)) {
+ p = getenv ( "SYMINFO" );
+ if (p)
+ strcpy ( S,p );
+ else {
+ p = getenv ( "CLIBD" );
+ if (p) {
+ strcpy ( S,p );
+ if (S[strlen(S)-1]!='/') strcat ( S,"/" );
+ strcat ( S,"syminfo.lib" );
+ } else
+ strcpy ( S,"syminfo.lib" );
+ }
+ f.assign ( S,true );
+ if (!f.reset(true)) return SYMOP_NoLibFile;
+ }
+
+ if (strncasecmp(SpGroup,"Hall:",5)) {
+ // normal space group symbol on input
+ strcpy ( G," '" );
+ strcat ( G,SpGroup );
+ strcat ( G,"'" );
+ S[0] = char(0);
+ while (!f.FileEnd() && !(strstr(S,G) && (strstr(S,"symbol xHM") ||
+ strstr(S,"symbol old"))))
+ f.ReadLine ( S,sizeof(S) );
+ } else {
+ // hall descriptor on input
+ strcpy ( G," ' " );
+ p = &(SpGroup[5]);
+ while (*p==' ') p++;
+ strcat ( G,p );
+ strcat ( G,"'" );
+ S[0] = char(0);
+ while (!f.FileEnd() && !(strstr(S,G) && strstr(S,"symbol Hall")))
+ f.ReadLine ( S,sizeof(S) );
+ }
+ if (f.FileEnd()) {
+ f.shut();
+ return SYMOP_UnknownSpaceGroup;
+ }
+
+ // found spacegroup, move to symop lines
+ while (!f.FileEnd() && (!strstr(S,"symop"))) {
+ symop_start = f.Position();
+ //# fgetpos ( f.GetHandle(),&symop_start );
+ f.ReadLine ( S,sizeof(S) );
+ }
+ // count primitive operators
+ while (!f.FileEnd() && (strstr(S,"symop"))) {
+ npops++;
+ f.ReadLine ( S,sizeof(S) );
+ }
+ // count centering operators
+ while (!f.FileEnd() && (strstr(S,"cenop"))) {
+ ncops++;
+ f.ReadLine ( S,sizeof(S) );
+ }
+ Nops = npops*ncops;
+ f.seek(symop_start);
+ //# fsetpos ( f.GetHandle(),&symop_start );
+ SymOp = new PSymOp[Nops];
+ RC = SYMOP_Ok;
+
+ // read primitive operators
+ for (i=0;(i<npops) && (!RC);i++) {
+ f.ReadLine ( S,sizeof(S) );
+ SymOp[i] = new SymOp();
+ RC = SymOp[i]->SetSymOp ( S+6 );
+ }
+
+ // skip identity centering operator
+ f.ReadLine ( S,sizeof(S) );
+ // loop over non-trivial centering operators, and for each loop
+ // over primtive operators
+ for (i=1;(i<ncops) && (!RC);i++) {
+ f.ReadLine ( S,sizeof(S) );
+ for (j=0;(j<npops) && (!RC);j++) {
+ SymOp[i*npops+j] = new SymOp();
+ RC = SymOp[i*npops+j]->SetSymOp ( S+6 );
+
+ SymOp[i*npops+j]->GetTMatrix(T1);
+ SymOp[j]->GetTMatrix(T2);
+ for (k=0;k<4;k++)
+ for (l=0;l<4;l++) {
+ T3[k][l] = 0.0;
+ for (m=0;m<4;m++)
+ T3[k][l] += T1[k][m]*T2[m][l];
+ }
+ for (k=0;k<3;k++) // kdc fix
+ T3[k][3] -= floor ( T3[k][3] ); // kdc fix
+ SymOp[i*npops+j]->CompileOpTitle(O,T3,false);
+ SymOp[i*npops+j]->SetSymOp (O);
+ }
+ }
+
+ f.shut();
+
+ return RC;
+
+ }
+ */
+
+ void SymOps::Reset() {
+ // removes all symmetry operations
+ FreeMemory();
+ }
+
+ int SymOps::AddSymOp ( cpstr XYZOperation ) {
+ // adds a symmetry operation
+ PPSymOp symOp1;
+ int i;
+ symOp1 = new PSymOp[Nops+1];
+ for (i=0;i<Nops;i++)
+ symOp1[i] = symOp[i];
+ if (symOp) delete[] symOp;
+ symOp = symOp1;
+ i = Nops;
+ symOp[i] = new SymOp();
+ Nops++;
+ return symOp[i]->SetSymOp ( XYZOperation );
+ }
+
+ void SymOps::PutGroupName ( cpstr SpGroupName ) {
+ CreateCopy ( SpGroup,SpGroupName );
+ }
+
+
+ int SymOps::GetNofSymOps() {
+ // GetNofSymOps() returns Nops -- the number of symmetry operations
+ return Nops;
+ }
+
+ pstr SymOps::GetSymOp ( int Nop ) {
+ if ((0<=Nop) && (Nop<Nops)) return symOp[Nop]->GetSymOp();
+ else return pstr("");
+ }
+
+ int SymOps::Transform ( realtype & x, realtype & y, realtype & z,
+ int Nop ) {
+ // Transform(..) transforms the coordinates according to the
+ // symmetry operation Nop. The return code is non-zero if
+ // Nop is a wrong operation number (must range from 0 to Nops-1).
+ if ((Nop<0) || (Nop>=Nops)) return 1;
+ if (symOp[Nop]) {
+ symOp[Nop]->Transform ( x,y,z );
+ return 0;
+ } else
+ return 2;
+ }
+
+ int SymOps::GetTMatrix ( mat44 & TMatrix, int Nop ) {
+ // GetTMatrix(..) returns the coordinate transformation matrix
+ // for the symmetry operation Nop. The return code is non-zero if
+ // Nop is a wrong operation number (must range from 0 to Nops-1).
+ if ((Nop<0) || (Nop>=Nops)) return 1;
+ if (symOp[Nop]) {
+ symOp[Nop]->GetTMatrix ( TMatrix );
+ return 0;
+ } else
+ return 2;
+ }
+
+ void SymOps::Print() {
+ int i;
+ char S[200];
+ printf ( " SPACE GROUP '%s'\n",SpGroup );
+ for (i=0;i<Nops;i++) {
+ symOp[i]->Print();
+ if (symOp[i]->CompileOpTitle(S))
+ printf ( " CHECK STATUS: Ok\n" );
+ else printf ( " CHECK STATUS: Generated '%s'\n",S );
+ }
+ }
+
+
+ void SymOps::Copy ( PSymOps SymOps ) {
+ int i;
+ FreeMemory();
+ CreateCopy ( SpGroup,SymOps->SpGroup );
+ Nops = SymOps->Nops;
+ if (Nops>0) {
+ symOp = new PSymOp[Nops];
+ for (i=0;i<Nops;i++) {
+ symOp[i] = new SymOp();
+ symOp[i]->Copy ( SymOps->symOp[i] );
+ }
+ }
+ }
+
+
+ void SymOps::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.CreateWrite ( SpGroup );
+ f.WriteInt ( &Nops );
+ for (i=0;i<Nops;i++)
+ StreamWrite ( f,symOp[i] );
+ }
+
+ void SymOps::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ FreeMemory();
+ f.ReadByte ( &Version );
+ f.CreateRead ( SpGroup );
+ f.ReadInt ( &Nops );
+ if (Nops>0) {
+ symOp = new PSymOp[Nops];
+ for (i=0;i<Nops;i++) {
+ symOp[i] = NULL;
+ StreamRead ( f,symOp[i] );
+ }
+ }
+ }
+
+
+ MakeStreamFunctions(SymOps)
+
+} // namespace mmdb
+
+
+/*
+
+void TestSymOps() {
+pstr p,p1;
+int RC;
+char S[500];
+SymOps SymOps;
+CFile f;
+
+ p = getenv ( "PDB_ROOT" );
+ if (p) {
+ strcpy ( S,p );
+ strcat ( S,"/lib/" );
+ } else
+ S[0] = char(0);
+ strcat ( S,"symop.lib" );
+ f.assign ( S,true );
+ if (!f.reset()) {
+ printf ( " +++++ No symop.lib file found.\n" );
+ return;
+ }
+
+ while (!f.FileEnd()) {
+ f.ReadLine ( S,sizeof(S) );
+ if (S[0] && (S[0]!=' ')) {
+ p = strchr ( S,'\'' );
+ if (p) {
+ p++;
+ p1 = strchr ( p,'\'' );
+ if (!p1) p = NULL;
+ }
+ if (!p) {
+ printf ( " +++++ Strange line in symop.lib:\n"
+ "%s\n",S );
+ return;
+ }
+ *p1 = char(0);
+ RC = SymOps.SetGroup ( p );
+ printf ( " =========================================================\n"
+ " RC=%i\n",RC );
+ SymOps.Print();
+ }
+ }
+
+ return;
+
+}
+
+*/
diff --git a/mmdb2/mmdb_symop.h b/mmdb2/mmdb_symop.h
new file mode 100644
index 0000000..f5e7af0
--- /dev/null
+++ b/mmdb2/mmdb_symop.h
@@ -0,0 +1,168 @@
+// $Id: mmdb_symop.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_SymOp <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Classes : mmdb::SymOp ( symmetry operators )
+// ~~~~~~~~~ mmdb::SymOps ( container of symmetry operators )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_SymOp__
+#define __MMDB_SymOp__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_defs.h"
+
+namespace mmdb {
+
+ // ==================== SymOp ========================
+
+ DefineClass(SymOp);
+ DefineStreamFunctions(SymOp);
+
+ class SymOp : public io::Stream {
+
+ public :
+
+ SymOp ();
+ SymOp ( io::RPStream Object );
+ ~SymOp();
+
+ int SetSymOp ( cpstr XYZOperation );
+ pstr GetSymOp ();
+
+ void Transform ( realtype & x, realtype & y, realtype & z );
+
+ void GetTMatrix ( mat44 & TMatrix ); // copies T to TMatrix
+ void SetTMatrix ( mat44 & TMatrix ); // copies TMatrix to T
+
+ bool CompileOpTitle ( pstr S ); // makes XYZOp from matrix T
+ bool CompileOpTitle ( pstr S, mat44 symMat, bool compare );
+ void Print (); // prints operation and matrix
+
+ void Copy ( PSymOp symOp );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ pstr XYZOp;
+ mat44 T;
+
+ void InitSymOp ();
+ void FreeMemory ();
+ int GetOperation ( int n );
+
+ };
+
+
+ // ==================== SymOps ========================
+
+ enum SYMOP_RC {
+ SYMOP_Ok = 0,
+ SYMOP_NoLibFile = -1,
+ SYMOP_UnknownSpaceGroup = -2,
+ SYMOP_NoSymOps = -3,
+ SYMOP_WrongSyntax = -4,
+ SYMOP_NotAnOperation = -5,
+ SYMOP_ZeroDenominator = -6
+ };
+
+ DefineClass(SymOps);
+ DefineStreamFunctions(SymOps);
+
+ class SymOps : public io::Stream {
+
+ public :
+
+ SymOps ();
+ SymOps ( io::RPStream Object );
+ ~SymOps();
+
+ virtual void FreeMemory();
+
+ int SetGroupSymopLib ( cpstr SpaceGroup,
+ cpstr symop_lib=NULL );
+ // Space Group is taken from symop.lib. Return Code:
+ // SYMOP_Ok <=> success
+
+ int SetGroup ( cpstr SpaceGroup,
+ cpstr syminfo_lib=NULL );
+ // Space Group is taken from syminfo.lib. Return Code:
+ // SYMOP_Ok <=> success
+
+ void Reset (); // removes all symmetry operations
+ virtual int AddSymOp ( cpstr XYZOperation ); // adds symmetry
+ // operation
+ void PutGroupName ( cpstr SpGroupName );
+
+ // GetNofSymOps() returns Nops -- the number of sym. operations
+ int GetNofSymOps ();
+ pstr GetSymOp ( int Nop );
+
+ // Transform(..) transforms the coordinates according to the
+ // symmetry operation Nop. The return code is non-zero if
+ // Nop is a wrong operation number (must range from 0 to Nops-1).
+ int Transform ( realtype & x, realtype & y, realtype & z,
+ int Nop );
+
+ // GetTMatrix(..) returns the coordinate transformation matrix
+ // for the symmetry operation Nop. The return code is non-zero if
+ // Nop is a wrong operation number (must range from 0 to Nops-1).
+ int GetTMatrix ( mat44 & TMatrix, int Nop );
+
+ void Print ();
+
+ virtual void Copy ( PSymOps symOps );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ pstr SpGroup;
+ int Nops;
+ PPSymOp symOp;
+
+ void InitSymOps();
+
+ };
+
+} // namespace mmdb
+
+// extern void TestSymOps();
+
+#endif
+
diff --git a/mmdb2/mmdb_tables.cpp b/mmdb2/mmdb_tables.cpp
new file mode 100644
index 0000000..d1e7c61
--- /dev/null
+++ b/mmdb2/mmdb_tables.cpp
@@ -0,0 +1,748 @@
+// $Id: mmdb_tables.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Tables <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Namespace : mmdb::
+//
+// **** Functions :
+// ~~~~~~~~~~~
+//
+// **** Constants : AName ( array of 2-character atom names )
+// ~~~~~~~~~~~ HAName ( array of 2=character heteroatom names )
+// RName ( 3-characters amino acid names )
+// RName1 ( 1-characters amino acid names )
+//
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+
+#include "mmdb_tables.h"
+#include "mmdb_defs.h"
+
+namespace mmdb {
+
+ // ===============================================================
+
+ cpstr const ElementName[nElementNames] = {
+ " H", "HE",
+ "LI", "BE", " B", " C", " N", " O", " F", "NE",
+ "NA", "MG", "AL", "SI", " P", " S", "CL", "AR",
+ " K", "CA",
+ "SC", "TI", " V", "CR", "MN", "FE",
+ "CO", "NI", "CU", "ZN",
+ "GA", "GE", "AS", "SE", "BR", "KR",
+ "RB", "SR",
+ " Y", "ZR", "NB", "MO", "TC", "RU",
+ "RH", "PD", "AG", "CD",
+ "IN", "SN", "SB", "TE", " I", "XE",
+ "CS", "BA",
+ "LA", "CE", "PR", "ND", "PM", "SM", "EU",
+ "GD", "TB", "DY", "HO", "ER", "TM", "YB",
+ "LU", "HF", "TA", " W", "RE", "OS",
+ "IR", "PT", "AU", "HG",
+ "TL", "PB", "BI", "PO", "AT", "RN",
+ "FR", "RA",
+ "AC", "TH", "PA", " U", "NP", "PU", "AM",
+ "CM", "BK", "CF", "ES", "FM", "MD", "NO",
+ "LR", "RF", "DB", "SG", "BH", "HS",
+ "MT", "UN", "UU", "UB",
+ "UQ", "UH", "UO",
+ " D", "AN"
+ };
+
+ realtype const MolecWeight[nElementNames] = {
+ 1.0079, 4.0026,
+ 6.9410, 9.0122, 10.811, 12.011, 14.007, 15.999, 18.998, 20.180,
+ 22.990, 24.305, 26.982, 28.086, 30.974, 32.066, 35.453, 39.948,
+ 39.098, 40.078,
+ 44.956, 47.867, 50.942, 51.996, 54.938, 55.845,
+ 58.993, 58.693, 63.546, 65.390,
+ 69.723, 72.610, 74.922, 78.960, 79.904, 83.800,
+ 85.468, 87.620,
+ 88.906, 91.224, 92.906, 95.940, 97.907, 101.07,
+ 102.91, 106.42, 107.87, 112.41,
+ 114.82, 118.71, 121.76, 127.60, 126.90, 131.29,
+ 132.91, 137.33,
+ 138.91, 140.12, 140.91, 144.24, 144.91, 150.36, 151.96,
+ 157.25, 158.93, 162.50, 164.93, 167.26, 168.93, 173.04,
+ 174.97, 178.49, 180.95, 183.84, 186.21, 190.23,
+ 192.22, 195.08, 196.97, 200.59,
+ 204.38, 207.20, 208.98, 208.98, 209.99, 222.02,
+ 232.02, 226.03,
+ 227.03, 232.04, 231.04, 238.03, 237.05, 244.06, 243.06,
+ 247.07, 247.07, 251.08, 252.08, 257.10, 258.10, 259.10,
+ 262.11, 263.11, 262.11, 266.12, 264.12, 269.13,
+ 268.14, 272.15, 272.15, 277.00,
+ 289.00, 289.00, 293.00,
+ 2.0200, 3.0300
+ };
+
+
+ realtype const CovalentRadius[nElementNames] = {
+ 0.32, 0.93,
+ 1.23, 0.90, 0.82, 0.77, 0.75, 0.73, 0.72, 0.71,
+ 1.54, 1.36, 1.18, 1.11, 1.06, 1.02, 0.99, 0.98,
+ 2.03, 1.91,
+ 1.62, 1.45, 1.34, 1.18, 1.17, 1.17,
+ 1.16, 1.15, 1.17, 1.25,
+ 1.26, 1.22, 1.20, 1.16, 1.14, 1.12,
+ 2.16, 1.91,
+ 1.62, 1.45, 1.34, 1.30, 1.27, 1.25,
+ 1.25, 1.28, 1.34, 1.48,
+ 1.44, 1.41, 1.40, 1.36, 1.33, 1.31,
+ 2.35, 1.98,
+ 1.69, 1.44, 1.34, 1.30, 1.28, 1.26, 1.27,
+ 1.30, 1.34, 1.49, 1.48, 1.47, 1.46, 1.46,
+ 1.45, 1.43, 2.50, 2.40, 2.20, 1.65,
+ 1.65, 1.64, 1.63, 1.62,
+ 1.85, 1.61, 1.59, 1.59, 1.58, 1.57,
+ 1.56, 1.74,
+ 1.56, 1.65, 1.65, 1.42, 1.65, 1.65, 1.65,
+ 1.65, 1.65, 1.65, 1.65, 1.65, 1.65, 1.65,
+ 1.65, 0.32, 0.10, /**/
+ 0.20, 0.20, 0.20,
+ 0.20, 0.20, 0.20, 0.20,
+ 0.20, 0.20, 0.20,
+ 0.32, 0.32
+ };
+
+
+ realtype const VdWaalsRadius[nElementNames] = {
+ 1.20, 1.40,
+ 1.82, 1.78, 1.74, 1.70, 1.55, 1.52, 1.47, 1.54,
+ // ^^^^ ^^^^ <- only a guess
+ 2.27, 1.73, 1.80, 2.10, 1.80, 1.80, 1.75, 1.88,
+ // ^^^^
+ 2.75, 2.65,
+ // ^^^^
+ 2.55, 2.45, 2.35, 2.20, 1.73, 1.90,
+ // ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
+ 1.75, 1.63, 1.40, 1.39,
+ // ^^^^
+ 1.87, 1.86, 1.85, 1.90, 1.85, 2.02,
+ // ^^^^
+ 2.75, 2.65,
+ //^^^^ ^^^^
+ 2.55, 2.45, 2.35, 2.20, 2.05, 1.90,
+ // ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
+ 1.75, 1.63, 1.72, 1.58,
+ // ^^^^
+ 1.93, 2.17, 2.10, 2.06, 1.98, 2.16,
+ // ^^^^
+ 2.75, 2.75,
+ //^^^^ ^^^^
+ 2.75, 2.75, 2.75, 2.75, 2.75, 2.75, 2.75,
+ // ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
+ 2.75, 2.75, 2.75, 2.75, 2.75, 2.65, 2.55,
+ // ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
+ 2.45, 2.35, 2.25, 2.15, 2.05, 1.95,
+ // ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
+ 1.85, 1.75, 1.66, 1.55,
+ // ^^^^
+ 1.96, 2.02, 2.00, 2.00, 2.00, 2.00,
+ // ^^^^ ^^^^ ^^^^ ^^^^
+ 2.75, 2.75,
+ //^^^^ ^^^^
+ 2.50, 2.25, 1.95, 1.86, 1.80, 1.80, 1.80,
+ // ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
+ 1.80, 1.80, 1.80, 1.80, 1.80, 1.80, 1.80,
+ // ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
+ 1.80, 1.80, 1.80, 1.80, 1.80, 1.80,
+ // ^^^^ ^^^^ ^^^^ ^^^^ ^^^^ ^^^^
+ 1.80, 1.80, 1.80, 1.80,
+ // ^^^^ ^^^^ ^^^^ ^^^^
+ 1.80, 1.80, 1.80,
+ // ^^^^ ^^^^ ^^^^
+ 1.30, 1.50
+ //^^^^ ^^^^
+ };
+
+ realtype const IonicRadius[nElementNames] = {
+ 0.79, 0.49, 2.05, 1.40, 1.17, 0.91, 0.75, 0.65, 0.57, 0.51,
+ 2.23, 1.72, 1.82, 1.46, 1.23, 1.09, 0.97, 0.88, 2.77, 2.23,
+ 2.09, 2.00, 1.92, 1.85, 1.79, 1.72, 1.67, 1.62, 1.57, 1.53,
+ 1.81, 1.52, 1.33, 1.22, 1.12, 1.03, 2.98, 2.45, 2.27, 2.16,
+ 2.09, 2.01, 1.95, 1.89, 1.83, 1.79, 1.75, 1.71, 2.00, 1.72,
+ 1.53, 1.42, 1.32, 1.24, 3.34, 2.78, 2.74, 2.16, 2.09, 2.02,
+ 1.97, 1.92, 1.87, 1.83, 1.79, 1.76, 2.08, 1.81, 1.63, 1.53,
+ 1.43, 1.34, 3.50, 3.00, 3.20, 2.70, 2.67, 2.64, 2.62, 2.59,
+ 2.56, 2.54, 2.51, 2.49, 2.47, 2.45, 2.42, 2.40, 2.25, 3.16,
+ 3.14, 3.11, 3.08, 3.05, 3.02, 2.99, 2.97, 2.95, 2.92, 2.90,
+ 2.87, 2.85
+ };
+
+ cpstr const ElementMetal[nElementMetals] = {
+ "LI", "BE", "NA", "MG", "AL", " K", "CA", "SC", "TI", " V",
+ "MN", "FE", "CO", "NI", "CU", "ZN", "GA", "RB", "SR", " Y",
+ "ZR", "NB", "MO", "TC", "RU", "RH", "PD", "AG", "CD", "IN",
+ "SN", "SB", "CS", "BA", "LA", "CE", "PR", "ND", "PM", "SM",
+ "EU", "GD", "TB", "DY", "HO", "ER", "TM", "YB", "LU", "HF",
+ "TA", " W", "RE", "OS", "IR", "PT", "AU", "HG", "TL", "PB",
+ "BI", "PO", "FR", "RA", "AC", "TH", "PA", " U", "NP", "PU",
+ "AM", "CM", "BK", "CF", "ES", "FM", "MD", "NO", "LR", "RF",
+ "DB", "SG", "BH", "HS", "MT", "UN", "UU", "UB", "UQ", "UH",
+ "UO"
+ };
+
+
+ cpstr const HydAtomName[nHydAtomNames] = {
+ "0H", "1H", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H",
+ "HH", "*H", "'H", """H"
+ };
+
+
+
+ bool isMetal ( cpstr element ) {
+ char name[3];
+ bool isThere;
+ int i;
+ if (!element[1]) {
+ name[0] = ' ';
+ name[1] = element[0];
+ } else
+ strncpy ( name,element,2 );
+ name[2] = char(0);
+ isThere = false;
+ for (i=0;(i<nElementMetals) && (!isThere);i++)
+ isThere = (!strcmp(ElementMetal[i],name));
+ return isThere;
+ }
+
+ int getElementNo ( cpstr element ) {
+ int type=0;
+ char El[3];
+ if ((!element[1]) || (element[1]==' ')) {
+ El[0] = ' ';
+ El[1] = element[0];
+ } else {
+ El[0] = element[0];
+ El[1] = element[1];
+ }
+ El[2] = char(0);
+ UpperCase ( El );
+ while (type<nElementNames)
+ if (!strcmp(El,ElementName[type])) break;
+ else type++;
+ if (type>=nElementNames) return ELEMENT_UNKNOWN;
+ return type+1; // so that hydrogen is 1
+ }
+
+ realtype getMolecWeight ( cpstr element ) {
+ int type=0;
+ char El[3];
+ if ((!element[1]) || (element[1]==' ')) {
+ El[0] = ' ';
+ El[1] = element[0];
+ } else {
+ El[0] = element[0];
+ El[1] = element[1];
+ }
+ El[2] = char(0);
+ UpperCase ( El );
+ while (type<nElementNames)
+ if (!strcmp(El,ElementName[type])) break;
+ else type++;
+ if (type>=nElementNames) return 1.0;
+ return MolecWeight[type];
+ }
+
+ realtype getCovalentRadius ( cpstr element ) {
+ int type=0;
+ char El[3];
+ if ((!element[1]) || (element[1]==' ')) {
+ El[0] = ' ';
+ El[1] = element[0];
+ } else {
+ El[0] = element[0];
+ El[1] = element[1];
+ }
+ El[2] = char(0);
+ UpperCase ( El );
+ while (type<nElementNames)
+ if (!strcmp(El,ElementName[type])) break;
+ else type++;
+ if (type>=nElementNames) return 2.2*CovalentRadius[0];
+ return CovalentRadius[type];
+ }
+
+ realtype getVdWaalsRadius ( cpstr element ) {
+ int type=0;
+ char El[3];
+ if ((!element[1]) || (element[1]==' ')) {
+ El[0] = ' ';
+ El[1] = element[0];
+ } else {
+ El[0] = element[0];
+ El[1] = element[1];
+ }
+ El[2] = char(0);
+ UpperCase ( El );
+ while (type<nElementNames)
+ if (!strcmp(El,ElementName[type])) break;
+ else type++;
+ if (type>=nElementNames) return 1.8;
+ return VdWaalsRadius[type];
+ }
+
+ cpstr const ResidueName[nResNames] = {
+ "ALA", "ARG", "ASN", "ASP", "CYS", "CYH", "GLN",
+ "GLU", "GLY", "HIS", "ILE", "LEU", "LYS", "MET",
+ "PHE", "PRO", "SER", "THR", "TRP", "TYR", "VAL",
+ "HEM", "WAT", "SUL", "END", "DUM"
+ };
+
+ int getResidueNo ( cpstr resName ) {
+ int i,m;
+ m = -1;
+ for (i=0;(i<nResNames) && (m<0);i++)
+ if (!strcmp(resName,ResidueName[i]))
+ m = i;
+ return m;
+ }
+
+ char const ResidueName1[nResNames] = {
+ 'A', 'R', 'N', 'D', 'C', 'C', 'Q',
+ 'E', 'G', 'H', 'I', 'L', 'K', 'M',
+ 'F', 'P', 'S', 'T', 'W', 'Y', 'V',
+ 'X', 'O', 'U', 'Z', 'Z'
+ };
+
+
+ cpstr const StdSolventName[nSolventNames] = {
+ "ADE", "CYT", "GUA", "INO", "THY", "URA",
+ "WAT", "HOH", "TIP", "H2O", "DOD", "MOH"
+ };
+
+
+ AAProperty const AAProperties[nAminoacidNames] = {
+ { "ALA", 1.8, 0.0, 0.42 },
+ { "ARG", -4.5, 1.0, -1.37 },
+ { "ASN", -3.5, 0.0, -0.82 },
+ { "ASP", -3.5, -1.0, -1.05 },
+ { "ASX", -3.5, -0.5, -1.05 }, // by analogy
+ { "CYS", 2.5, 0.0, 1.34 },
+ { "CYH", 2.5, 0.0, 1.34 }, // by analogy
+ { "GLN", -3.5, 0.0, -0.30 },
+ { "GLU", -3.5, -1.0, -0.87 },
+ { "GLX", -3.5, -0.5, 0.0 }, // by analogy
+ { "GLY", -0.4, 0.0, 0.0 },
+ { "HIS", -3.2, 0.0, 0.18 },
+ { "ILE", 4.5, 0.0, 2.46 },
+ { "LEU", 3.8, 0.0, 2.32 },
+ { "LYS", -3.9, 1.0, -1.35 },
+ { "MET", 1.9, 0.0, 1.68 },
+ { "PHE", 2.8, 0.0, 2.44 },
+ { "PRO", -1.6, 0.0, 0.98 },
+ { "SER", -0.8, 0.0, -0.05 },
+ { "THR", -0.7, 0.0, 0.35 },
+ { "TRP", -0.9, 0.0, 3.07 },
+ { "TYR", -1.3, 0.0, 1.31 },
+ { "VAL", 4.2, 0.0, 1.66 }
+ };
+
+ realtype GetAAHydropathy ( cpstr resName ) {
+ int i1,j;
+ i1 = -1;
+ j = 0;
+ while (j<nAminoacidNames)
+ if (!strcasecmp(resName,AAProperties[j].name)) {
+ i1 = j;
+ break;
+ } else
+ j++;
+ if (i1<0) return -MaxReal;
+ return AAProperties[i1].hydropathy;
+ }
+
+ realtype GetAACharge ( cpstr resName ) {
+ int i1,j;
+ i1 = -1;
+ j = 0;
+ while (j<nAminoacidNames)
+ if (!strcasecmp(resName,AAProperties[j].name)) {
+ i1 = j;
+ break;
+ } else
+ j++;
+ if (i1<0) return 0.0;
+ return AAProperties[i1].charge;
+ }
+
+ realtype GetAASolvationEnergy ( cpstr resName ) {
+ int i1,j;
+ i1 = -1;
+ j = 0;
+ while (j<nAminoacidNames)
+ if (!strcasecmp(resName,AAProperties[j].name)) {
+ i1 = j;
+ break;
+ } else
+ j++;
+ if (i1<0) return 0.0;
+ return AAProperties[i1].relSolvEnergy;
+ }
+
+
+ int const AASimilarity[nAminoacidNames][nAminoacidNames] = {
+ /* A A A A A C C G G G G H I L L M P P S T T T V */
+ /* L R S S S Y Y L L L L I L E Y E H R E H R Y A */
+ /* A G N P X S H N U X Y S E U S T E O R R P R L */
+ { 5,0,0,0,0,0,0,0,0,2,2,0,2,2,0,2,2,2,1,1,2,2,2 }, /* ALA */
+ { 0,5,2,2,2,0,0,2,2,0,0,2,0,0,4,0,0,0,0,0,0,0,0 }, /* ARG */
+ { 0,2,5,3,5,0,0,3,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 }, /* ASN */
+ { 0,2,3,5,5,0,0,3,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 }, /* ASP */
+ { 0,2,5,5,5,0,0,3,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 }, /* ASX */
+ { 0,0,0,0,0,5,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* CYS */
+ { 0,0,0,0,0,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* CYH */
+ { 0,2,3,3,3,0,0,5,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 }, /* GLN */
+ { 0,2,3,3,3,0,0,3,5,0,0,0,0,0,2,0,0,0,0,0,0,0,0 }, /* GLU */
+ { 2,0,0,0,0,0,0,0,0,5,5,0,1,1,0,1,1,2,0,0,1,1,1 }, /* GLX */
+ { 2,0,0,0,0,0,0,0,0,5,5,0,1,1,0,1,1,2,0,0,1,1,1 }, /* GLY */
+ { 0,2,0,0,0,0,0,0,0,0,0,5,1,1,2,2,2,0,1,1,2,2,1 }, /* HIS */
+ { 2,0,0,0,0,0,0,0,0,1,1,1,5,4,0,4,4,0,0,0,4,4,4 }, /* ILE */
+ { 2,0,0,0,0,0,0,0,0,1,1,1,4,5,0,4,4,0,0,0,4,4,4 }, /* LEU */
+ { 0,4,2,2,2,0,0,2,2,0,0,2,0,0,5,0,0,0,0,0,0,0,0 }, /* LYS */
+ { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,5,4,0,0,0,4,4,4 }, /* MET */
+ { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,4,5,0,0,0,5,5,4 }, /* PHE */
+ { 2,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,5,0,0,0,0,0 }, /* PRO */
+ { 1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,5,3,0,0,0 }, /* SER */
+ { 1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,3,5,0,0,0 }, /* THR */
+ { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,4,5,0,0,0,5,5,4 }, /* TRP */
+ { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,4,5,0,0,0,5,5,4 }, /* TYR */
+ { 2,0,0,0,0,0,0,0,0,1,1,1,4,4,0,4,4,0,0,0,4,4,5 }, /* VAL */
+ };
+
+ int GetAAPIndex ( cpstr resName ) {
+ // 0..nAminoacidNames-1
+ int i,k;
+ k = -1;
+ for (i=0;(i<nAminoacidNames) && (k<0);i++)
+ if (!strcasecmp(resName,AAProperties[i].name))
+ k = i;
+ return k;
+ }
+
+
+ int GetAASimilarity ( cpstr resName1, cpstr resName2 ) {
+ int i1,i2,j;
+
+ i1 = -1;
+ j = 0;
+ while (j<nAminoacidNames)
+ if (!strcasecmp(resName1,AAProperties[j].name)) {
+ i1 = j;
+ break;
+ } else
+ j++;
+ if (i1<0) return -1;
+
+ i2 = -1;
+ j = 0;
+ while (j<nAminoacidNames)
+ if (!strcasecmp(resName2,AAProperties[j].name)) {
+ i2 = j;
+ break;
+ } else
+ j++;
+ if (i2<0) return -2;
+
+ return AASimilarity[i1][i2];
+
+ }
+
+
+
+
+
+ /*
+
+
+ pstr const AminoacidName[nAminoacidNames] = {
+ "ALA", "ARG", "ASN", "ASP", "ASX", "CYS", "CYH", "GLN",
+ "GLU", "GLX", "GLY", "HIS", "ILE", "LEU", "LYS", "MET",
+ "PHE", "PRO", "SER", "THR", "TRP", "TYR", "VAL"
+ };
+
+
+ // The higher is the hydropathy scale value, the more
+ // hydrophobic the residue is.
+ // Some sources suggest that sure hydrophilic residues
+ // are those with hydropathy scale value less than -1.5,
+ // while sure hydropoobic residues have hydropathy scale
+ // value greater than 0.0.
+ // The scale is after J. Kyte and R. F. Doolittle,
+ // A simple method for displaying the hydropathic character
+ // of a protein, J. Mol. Biol. (1982) 157, 105-132
+ realtype const AAHydropathyScale[nAminoacidNames] = {
+ 1.8, -4.5, -3.5, -3.5, -3.5, 2.5, 2.5, -3.5,
+ -3.5, -3.5, -0.4, -3.2, 4.5, 3.8, -3.9, 1.9,
+ 2.8, -1.6, -0.8, -0.7, -0.9, -1.3, 4.2
+ };
+
+ realtype GetAAHydropathy ( cpstr resName ) {
+ int i1,j;
+ i1 = -1;
+ j = 0;
+ while (j<nAminoacidNames)
+ if (!strcasecmp(resName,AminoacidName[j])) {
+ i1 = j;
+ break;
+ } else
+ j++;
+ if (i1<0) return -MaxReal;
+ return AAHydropathyScale[i1];
+ }
+
+ // Acid residues are those with negative charge
+ // Base residues are those with positive charge
+ realtype const AACharge[nAminoacidNames] = {
+ 0.0, 1.0, 0.0, -1.0, -0.5, 0.0, 0.0, 0.0,
+ -1.0, -0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ };
+
+ int GetAASimilarity ( cpstr resName1, cpstr resName2 ) {
+ int i1,i2,j;
+
+ i1 = -1;
+ j = 0;
+ while (j<nAminoacidNames)
+ if (!strcasecmp(resName1,AminoacidName[j])) {
+ i1 = j;
+ break;
+ } else
+ j++;
+ if (i1<0) return -1;
+
+ i2 = -1;
+ j = 0;
+ while (j<nAminoacidNames)
+ if (!strcasecmp(resName2,AminoacidName[j])) {
+ i2 = j;
+ break;
+ } else
+ j++;
+ if (i2<0) return -2;
+
+ return AASimilarity[i1][i2];
+
+ }
+
+ bool isAminoacid ( cpstr resName ) {
+ bool isThere;
+ int i;
+ isThere = false;
+ for (i=0;(i<nAminoacidNames) && (!isThere);i++)
+ isThere = (!strcmp(AminoacidName[i],resName));
+ return isThere;
+ }
+
+ */
+
+
+ cpstr const NucleotideName[nNucleotideNames] = {
+ "A", "C", "G", "I", "T", "U",
+ "+A", "+C", "+G", "+I", "+T", "+U",
+ "DA", "DC", "DG", "DI", "DT", "DU",
+ "RA", "RC", "RG", "RU", "5NC", "TYD"
+ };
+
+
+ bool isSolvent ( cpstr resName ) {
+ bool isThere;
+ int i;
+ isThere = false;
+ for (i=0;(i<nSolventNames) && (!isThere);i++)
+ isThere = (!strcmp(StdSolventName[i],resName));
+ return isThere;
+ }
+
+ bool isAminoacid ( cpstr resName ) {
+ bool isThere;
+ int i;
+ isThere = false;
+ for (i=0;(i<nAminoacidNames) && (!isThere);i++)
+ isThere = (!strcmp(AAProperties[i].name,resName));
+ return isThere;
+ }
+
+ bool isNucleotide ( cpstr resName ) {
+ bool isThere;
+ int i;
+ isThere = false;
+ for (i=0;(i<nNucleotideNames) && (!isThere);i++)
+ isThere = (!strcmp(NucleotideName[i],resName));
+ return isThere;
+ }
+
+ int isDNARNA ( cpstr resName ) {
+ bool isThere;
+ int i;
+ isThere = false;
+ for (i=0;(i<nNucleotideNames) && (!isThere);i++)
+ isThere = (!strcmp(NucleotideName[i],resName));
+ if (!isThere) return 0; // neither
+ if (resName[0]=='D') return 1; // DNA
+ return 2; // RNA
+ }
+
+ bool isSugar ( cpstr resName ) {
+ UNUSED_ARGUMENT(resName);
+ return false;
+ }
+
+
+ cpstr const Res1Code[] = {
+
+ // standard aminoacids
+
+ "ALA A", // Alanine
+ "ARG R", // Arginine
+ "ASN N", // Asparagine
+ "ASP D", // Aspartic acid (Aspartate)
+ "CYS C", // Cysteine
+ "GLN Q", // Glutamine
+ "GLU E", // Glutamic acid (Glutamate)
+ "GLY G", // Glycine
+ "HIS H", // Histidine
+ "ILE I", // Isoleucine
+ "LEU L", // Leucine
+ "LYS K", // Lysine
+ "MET M", // Methionine
+ "PHE F", // Phenylalanine
+ "PRO P", // Proline
+ "SER S", // Serine
+ "THR T", // Threonine
+ "TRP W", // Tryptophan
+ "TYR Y", // Tyrosine
+ "VAL V", // Valine
+ "ASX B", // Aspartic acid or Asparagine
+ "GLX Z", // Glutamine or Glutamic acid.
+ // ??? X Any amino acid.
+
+ // other
+
+ "1PA A", "1PI A", "2AS D", "2ML L", "2MR R", "3GA A",
+ "5HP E", "ACB D", "ACL R", "AGM R", "AHB D", "ALM A",
+ "ALN A", "ALO T", "ALT A", "ALY K", "APH A", "APM A",
+ "AR2 R", "ARM R", "ARO R", "ASA D", "ASB D", "ASI D",
+ "ASK D", "ASL D", "ASQ D", "AYA A", "B1F A", "B2A A",
+ "B2F A", "B2I I", "B2V V", "BAL A", "BCS C", "BFD D",
+ "BHD D", "BLE L", "BLY K", "BNN F", "BNO L", "BTA L",
+ "BTC C", "BTR W", "BUC C", "BUG L", "C5C C", "C6C C",
+ "CAF C", "CAS C", "CAY C", "CCS C", "CEA C", "CGU E",
+ "CHG G", "CHP G", "CLB A", "CLD A", "CLE L", "CME C",
+ "CMT C", "CSB C", "CSD A", "CSE C", "CSO C", "CSP C",
+ "CSR C", "CSS C", "CSW C", "CSX C", "CSY C", "CSZ C",
+ "CTH T", "CXM M", "CY1 C", "CYM C", "CZZ C", "DAH F",
+ "DAL A", "DAM A", "DAR R", "DAS D", "DBY Y", "DCY C",
+ "DGL E", "DGN Q", "DHI H", "DHN V", "DIL I", "DIV V",
+ "DLE L", "DLY K", "DNP A", "DOH D", "DPH F", "DPN F",
+ "DPR P", "DSE S", "DSN S", "DSP D", "DTH T", "DTR W",
+ "DTY Y", "DVA V", "EFC C", "EHP F", "EYS C", "FLA A",
+ "FLE L", "FME M", "FTY Y", "GGL E", "GHP G", "GSC G",
+ "GT9 C", "H5M P", "HAC A", "HAR R", "HIC H", "HIP H",
+ "HMR R", "HPH F", "HPQ F", "HTR W", "HV5 A", "HYP P",
+ "IAS N", "IIL I", "ILG Q", "IML I", "IN2 K", "ISO A",
+ "IVA V", "IYR Y", "KCX K", "KPH K", "LLY K", "LOL L",
+ "LPL L", "LTR W", "LYM K", "LYZ K", "M3L K", "MAA A",
+ "MAI R", "MEN N", "MGN Q", "MGY G", "MHL L", "MHO M",
+ "MHS H", "MIS S", "MLE L", "MLY K", "MLZ K", "MME M",
+ "MNL L", "MNV V", "MPQ G", "MSE M", "MSO M", "MTY Y",
+ "MVA V", "NAL A", "NAM A", "NCY C", "NEM H", "NEP H",
+ "NFA F", "NIT A", "NLE L", "NLN L", "NNH R", "NPH C",
+ "NVA V", "OAS S", "OCS C", "OCY C", "OMT M", "OPR R",
+ "PAQ F", "PBB C", "PCA E", "PEC C", "PGY G", "PHA F",
+ "PHD N", "PHI F", "PHL F", "PHM F", "PLE L", "POM P",
+ "PPH F", "PPN F", "PR3 C", "PRR A", "PRS P", "PTH Y",
+ "PTR Y", "PYA A", "RON V", "S1H S", "SAC S", "SAH C",
+ "SAM M", "SBD A", "SBL A", "SCH C", "SCS C", "SCY C",
+ "SEB S", "SEG A", "SEP S", "SET S", "SHC C", "SHP G",
+ "SLZ K", "SMC C", "SME M", "SNC C", "SOC C", "STY Y",
+ "SVA S", "TBG G", "TCR W", "THC T", "THO T", "TIH A",
+ "TNB C", "TPL W", "TPO T", "TPQ F", "TRF W", "TRG K",
+ "TRN W", "TRO W", "TYB Y", "TYI Y", "TYN Y", "TYQ Y",
+ "TYS Y", "TYY A", "VAD V", "VAF V", "YOF Y", ""
+
+ };
+
+
+ void Get1LetterCode ( cpstr res3name, pstr res1code ) {
+ char r[4];
+ int i;
+
+ strncpy ( r,res3name,3 );
+ r[3] = char(0);
+ UpperCase ( r );
+ i = 0;
+ res1code[0] = char(1);
+ while (Res1Code[i][0]) {
+ if (Res1Code[i][0]==r[0]) {
+ if (Res1Code[i][1]==r[1]) {
+ if (Res1Code[i][2]==r[2]) {
+ res1code[0] = Res1Code[i][4];
+ break;
+ }
+ }
+ }
+ i++;
+ }
+
+ if (res1code[0]!=char(1)) res1code[1] = char(0);
+ else if (isNucleotide(r)) strcpy ( res1code,r );
+ else strcpy ( res1code,"X" );
+
+ }
+
+
+ void Get3LetterCode ( cpstr res1name, pstr res3code ) {
+ int i;
+
+ strcpy ( res3code,"XXX" );
+ i = 0;
+ while (Res1Code[i][0]) {
+ if (Res1Code[i][4]==res1name[0]) {
+ res3code[0] = Res1Code[i][0];
+ res3code[1] = Res1Code[i][1];
+ res3code[2] = Res1Code[i][2];
+ break;
+ }
+ i++;
+ }
+
+ }
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_tables.h b/mmdb2/mmdb_tables.h
new file mode 100644
index 0000000..f2d4d9d
--- /dev/null
+++ b/mmdb2/mmdb_tables.h
@@ -0,0 +1,127 @@
+// $Id: mmdb_tables.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Tables <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Namespace : mmdb::
+//
+// **** Functions :
+// ~~~~~~~~~~~
+//
+// **** Constants : AName ( array of 2-character atom names )
+// ~~~~~~~~~~~ HAName ( array of 2=character heteroatom names )
+// RName ( 3-characters amino acid names )
+// RName1 ( 1-characters amino acid names )
+//
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Tables__
+#define __MMDB_Tables__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb {
+
+ // =================================================================
+
+ const int nElementNames = 117;
+ const int nElementMetals = 91;
+ const int nHydAtomNames = 14;
+
+ extern cpstr const ElementName [nElementNames];
+ extern cpstr const ElementMetal [nElementMetals];
+ extern cpstr const HydAtomName [nHydAtomNames];
+ extern realtype const MolecWeight [nElementNames];
+ extern realtype const CovalentRadius[nElementNames];
+ extern realtype const VdWaalsRadius [nElementNames];
+ extern realtype const IonicRadius [nElementNames];
+
+ extern bool isMetal ( cpstr element );
+
+ const int ELEMENT_UNKNOWN = -1;
+
+ extern int getElementNo ( cpstr element );
+ extern realtype getMolecWeight ( cpstr element );
+ extern realtype getCovalentRadius ( cpstr element );
+ extern realtype getVdWaalsRadius ( cpstr element );
+
+ const int nResNames = 26;
+
+ extern cpstr const ResidueName [nResNames];
+ extern char const ResidueName1[nResNames];
+
+ extern int getResidueNo ( cpstr resName );
+
+ const realtype NAvogadro = 6.02214129e23;
+
+ const int nSolventNames = 12;
+ const int nAminoacidNames = 23;
+ const int nNucleotideNames = 24;
+
+ DefineStructure(AAProperty);
+
+ struct AAProperty {
+ char name[4];
+ realtype hydropathy;
+ realtype charge;
+ realtype relSolvEnergy;
+ };
+
+ extern AAProperty const AAProperties[nAminoacidNames];
+ extern int const AASimilarity[nAminoacidNames][nAminoacidNames];
+
+ extern int GetAAPIndex ( cpstr resName ); // 0..nAminoacidNames-1
+ extern realtype GetAAHydropathy ( cpstr resName ); // -4.5...+4.5
+ extern realtype GetAACharge ( cpstr resName );
+ extern realtype GetAASolvationEnergy ( cpstr resName );
+ extern int GetAASimilarity ( cpstr resName1,
+ cpstr resName2 ); // 0..5
+
+ extern cpstr const StdSolventName[nSolventNames];
+ extern cpstr const NucleotideName[nNucleotideNames];
+
+ extern bool isSolvent ( cpstr resName );
+ extern bool isAminoacid ( cpstr resName );
+ extern bool isNucleotide ( cpstr resName );
+ extern int isDNARNA ( cpstr resName ); // 0,1(DNA),2(RNA)
+ extern bool isSugar ( cpstr resName );
+
+ extern void Get1LetterCode ( cpstr res3name, pstr res1code );
+ extern void Get3LetterCode ( cpstr res1name, pstr res3code );
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_title.cpp b/mmdb2/mmdb_title.cpp
new file mode 100644
index 0000000..b16f6e1
--- /dev/null
+++ b/mmdb2/mmdb_title.cpp
@@ -0,0 +1,2662 @@
+// $Id: mmdb_title.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 21.11.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Title <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::TitleContainer (container of title classes)
+// ~~~~~~~~~ mmdb::ObsLine
+// mmdb::TitleLine
+// mmdb::Caveat
+// mmdb::Compound
+// mmdb::Source
+// mmdb::KeyWords
+// mmdb::ExpData
+// mmdb::MdlType
+// mmdb::Author
+// mmdb::RevData
+// mmdb::Supersede
+// mmdb::Journal
+// mmdb::Remark
+// mmdb::Biomolecule
+// mmdb::Title ( MMDB title section )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mmdb_title.h"
+#include "mmdb_cifdefs.h"
+
+namespace mmdb {
+
+ // ============== TitleContainer ====================
+
+ PContainerClass TitleContainer::MakeContainerClass ( int ClassID ) {
+ switch (ClassID) {
+ default :
+ case ClassID_Template : return
+ ClassContainer::MakeContainerClass(ClassID);
+ case ClassID_ObsLine : return new ObsLine ();
+ case ClassID_CAVEAT : return new Caveat ();
+ case ClassID_TitleLine : return new TitleLine();
+ case ClassID_Compound : return new Compound ();
+ case ClassID_Source : return new Source ();
+ case ClassID_ExpData : return new ExpData ();
+ case ClassID_Author : return new Author ();
+ case ClassID_RevData : return new RevData ();
+ case ClassID_Supersede : return new Supersede();
+ case ClassID_Journal : return new Journal ();
+ case ClassID_Remark : return new Remark ();
+ }
+ }
+
+ MakeStreamFunctions(TitleContainer)
+
+
+ // ================ ObsLine ===================
+
+ ObsLine::ObsLine() : ContainerClass() {
+ InitObsLine();
+ }
+
+ ObsLine::ObsLine ( cpstr S ) : ContainerClass() {
+ InitObsLine();
+ ConvertPDBASCII ( S );
+ }
+
+ ObsLine::ObsLine ( io::RPStream Object ) : ContainerClass(Object) {
+ InitObsLine();
+ }
+
+ ObsLine::~ObsLine() {}
+
+ void ObsLine::InitObsLine() {
+ int i;
+ strcpy ( repDate,"DD-MMM-YYYY" );
+ strcpy ( idCode, "----" );
+ for (i=0;i<8;i++)
+ strcpy ( rIdCode[i]," " );
+ }
+
+ void ObsLine::PDBASCIIDump ( pstr S, int N ) {
+ // makes the ASCII PDB OBSLTE line number N
+ // from the class' data
+ int i;
+ if (N==0) strcpy ( S,"OBSLTE " );
+ else sprintf ( S,"OBSLTE %2i",N+1 );
+ PadSpaces ( S,80 );
+ Date11to9 ( repDate,&(S[11]) );
+ strncpy ( &(S[21]),idCode,4 );
+ for (i=0;i<8;i++)
+ strncpy ( &(S[31+5*i]),rIdCode[i],4 );
+ }
+
+ void ObsLine::MakeCIF ( mmcif::PData CIF, int ) {
+ mmcif::PLoop Loop;
+ int RC,i,j;
+ char DateCIF[20];
+ RC = CIF->AddLoop ( CIFCAT_OBSLTE,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, provide tags
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_DATE );
+ Loop->AddLoopTag ( CIFTAG_REPLACE_PDB_ID );
+ Loop->AddLoopTag ( CIFTAG_PDB_ID );
+ }
+ Date11toCIF ( repDate,DateCIF );
+ for (i=0;i<8;i++) {
+ j = 0;
+ while (rIdCode[i][j] && (rIdCode[i][j]==' ')) j++;
+ if (rIdCode[i][j]) {
+ Loop->AddString ( pstr("OBSLTE") );
+ Loop->AddString ( DateCIF );
+ Loop->AddString ( idCode );
+ Loop->AddString ( rIdCode[i] );
+ }
+ }
+ }
+
+ ERROR_CODE ObsLine::ConvertPDBASCII ( cpstr S ) {
+ int i;
+ Date9to11 ( &(S[11]),repDate );
+ strncpy ( idCode,&(S[21]),4 );
+ idCode[4] = char(0);
+ for (i=0;i<8;i++) {
+ strncpy ( rIdCode[i],&(S[31+i*5]),4 );
+ rIdCode[i][4] = char(0);
+ }
+ return Error_NoError;
+ }
+
+ ERROR_CODE ObsLine::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ int i,RC;
+ pstr F,FDate,FID;
+ char DateCIF [20];
+ char DateCIF0[20];
+ IDCode idCode1;
+
+ Loop = CIF->GetLoop ( CIFCAT_OBSLTE );
+ if (!Loop) {
+ n = -1; // signal to finish processing of this structure
+ return Error_EmptyCIF;
+ }
+ i = 0;
+ do {
+ F = Loop->GetString ( CIFTAG_ID,n,RC );
+ if (RC) {
+ if (i==0) n = -1;
+ return Error_MissingCIFField;
+ }
+ if (F) {
+ if (!strcmp(F,"OBSLTE")) {
+ FDate = Loop->GetString ( CIFTAG_DATE,n,RC );
+ if ((!RC) && FDate)
+ strncpy ( DateCIF,FDate,15 );
+ else strcpy ( DateCIF,"YYYY-MMM-DD" );
+ FID = Loop->GetString ( CIFTAG_REPLACE_PDB_ID,n,RC );
+ if ((!RC) && FID)
+ strncpy ( idCode1,FID,sizeof(IDCode)-1 );
+ else idCode1[0] = char(0);
+ if (i==0) {
+ DateCIFto11 ( DateCIF,repDate );
+ DateCIF[11] = char(0);
+ strcpy ( idCode ,idCode1 );
+ strcpy ( DateCIF0,DateCIF );
+ } else if ((strcmp(DateCIF0,DateCIF)) ||
+ (strcmp(idCode,idCode1)))
+ return Error_MissingCIFField;
+ FID = Loop->GetString ( CIFTAG_PDB_ID,n,RC );
+ if ((!RC) && FID)
+ strncpy ( rIdCode[i],FID,sizeof(IDCode)-1 );
+ else rIdCode[i][0] = char(0);
+ Loop->DeleteField ( CIFTAG_ID ,n );
+ Loop->DeleteField ( CIFTAG_DATE ,n );
+ Loop->DeleteField ( CIFTAG_REPLACE_PDB_ID,n );
+ Loop->DeleteField ( CIFTAG_PDB_ID ,n );
+ i++;
+ }
+ }
+ n++;
+ } while (i<8);
+
+ return Error_NoError;
+
+ }
+
+ void ObsLine::Copy ( PContainerClass ObsLine ) {
+ int i;
+ strcpy ( repDate,PObsLine(ObsLine)->repDate );
+ strcpy ( idCode ,PObsLine(ObsLine)->idCode );
+ for (i=0;i<8;i++)
+ strcpy ( rIdCode[i],PObsLine(ObsLine)->rIdCode[i] );
+ }
+
+ void ObsLine::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteTerLine ( repDate,false );
+ f.WriteTerLine ( idCode ,false );
+ for (i=0;i<8;i++)
+ f.WriteTerLine ( rIdCode[i],false );
+ }
+
+ void ObsLine::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadTerLine ( repDate,false );
+ f.ReadTerLine ( idCode ,false );
+ for (i=0;i<8;i++)
+ f.ReadTerLine ( rIdCode[i],false );
+ }
+
+ MakeStreamFunctions(ObsLine)
+
+
+ // =================== TitleLine ======================
+
+ TitleLine::TitleLine() : ContString() {
+ InitTitleLine();
+ }
+
+ TitleLine::TitleLine ( cpstr S ) : ContString() {
+ InitTitleLine();
+ ConvertPDBASCII ( S );
+ }
+
+ TitleLine::TitleLine ( io::RPStream Object ) : ContString(Object) {
+ InitTitleLine();
+ }
+
+ TitleLine::~TitleLine() {
+ }
+
+ void TitleLine::InitTitleLine() {
+ CreateCopy ( CIFCategory,CIFCAT_STRUCT );
+ CreateCopy ( CIFTag, CIFTAG_TITLE );
+ }
+
+ ERROR_CODE TitleLine::ConvertPDBASCII ( cpstr S ) {
+ if (strlen(S)>10)
+ CreateCopy ( Line,&(S[10]) );
+ else CreateCopy ( Line,pstr(" ") );
+ return Error_NoError;
+ }
+
+ void TitleLine::PDBASCIIDump ( pstr S, int N ) {
+ if (N==0) strcpy ( S,"TITLE " );
+ else sprintf ( S,"TITLE %2i",N+1 );
+ strcat ( S,Line );
+ }
+
+ void TitleLine::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ ContString::write ( f );
+ }
+
+ void TitleLine::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ ContString::read ( f );
+ }
+
+ MakeStreamFunctions(TitleLine)
+
+
+
+ // =================== Caveat ======================
+
+ Caveat::Caveat() : ContString() {
+ InitCaveat();
+ }
+
+ Caveat::Caveat ( cpstr S ) : ContString() {
+ InitCaveat();
+ ConvertPDBASCII ( S );
+ }
+
+ Caveat::Caveat ( io::RPStream Object ) : ContString(Object) {
+ InitCaveat();
+ }
+
+ Caveat::~Caveat() {}
+
+ void Caveat::InitCaveat() {
+ strcpy ( idCode,"----" );
+ CreateCopy ( CIFCategory,CIFCAT_DATABASE_PDB_CAVEAT );
+ CreateCopy ( CIFTag ,CIFTAG_TEXT );
+ }
+
+ ERROR_CODE Caveat::ConvertPDBASCII ( cpstr S ) {
+ if (strlen(S)>12) {
+ strncpy ( idCode,&(S[11]),4 );
+ idCode[4] = char(0);
+ if (strlen(S)>19)
+ CreateCopy ( Line,&(S[19]) );
+ else CreateCopy ( Line,pstr(" ") );
+ } else
+ CreateCopy ( Line,pstr(" ") );
+ return Error_NoError;
+ }
+
+ void Caveat::PDBASCIIDump ( pstr S, int N ) {
+ if (N==0) strcpy ( S,"CAVEAT " );
+ else sprintf ( S,"CAVEAT %2i ",N+1 );
+ strcat ( S,idCode );
+ strcat ( S," " );
+ strcat ( S,Line );
+ }
+
+ void Caveat::MakeCIF ( mmcif::PData CIF, int N ) {
+ char S[500];
+ CIF->PutString ( idCode,CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_ID,false );
+ strcpy ( S,"\n" );
+ strncat ( S,Line,sizeof(S)-2 );
+ S[sizeof(S)-1] = char(0);
+ CIF->PutString ( S,CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_TEXT,(N!=0) );
+ }
+
+/*
+ void Caveat::GetCIF1 ( mmcif::PData CIF, ERROR_CODE & Signal,
+ int & pos ) {
+ pstr F;
+ int RC;
+ F = CIF->GetString ( CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_ID,RC );
+ if ((!RC) && F) {
+ strncpy ( idCode,F,sizeof(IDCode) );
+ idCode[sizeof(IDCode)-1] = char(0);
+ }
+ ContString::GetCIF1 ( CIF,Signal,pos );
+ if (Signal<0)
+ CIF->DeleteField ( CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_ID );
+ }
+*/
+
+ void Caveat::Copy ( PContainerClass Caveat ) {
+ strcpy ( idCode,PCaveat(Caveat)->idCode );
+ ContString::Copy ( Caveat );
+ }
+
+ void Caveat::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteTerLine ( idCode,false );
+ ContString::write ( f );
+ }
+
+ void Caveat::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadTerLine ( idCode,false );
+ ContString::read ( f );
+ }
+
+ MakeStreamFunctions(Caveat)
+
+
+
+ // =================== Compound ======================
+
+ Compound::Compound() : ContString() {
+ InitCompound();
+ }
+
+ Compound::Compound ( cpstr S ) : ContString() {
+ InitCompound();
+ ConvertPDBASCII ( S );
+ }
+
+ Compound::Compound ( io::RPStream Object ) : ContString(Object) {
+ InitCompound();
+ }
+
+ Compound::~Compound() {}
+
+ void Compound::InitCompound() {
+ CreateCopy ( CIFCategory,CIFCAT_STRUCT );
+ CreateCopy ( CIFTag ,CIFTAG_NDB_DESCRIPTOR );
+ }
+
+ ERROR_CODE Compound::ConvertPDBASCII ( cpstr S ) {
+ if (strlen(S)>10)
+ CreateCopy ( Line,&(S[10]) );
+ else CreateCopy ( Line,pstr(" ") );
+ return Error_NoError;
+ }
+
+ void Compound::PDBASCIIDump ( pstr S, int N ) {
+ if (N==0) strcpy ( S,"COMPND " );
+ else sprintf ( S,"COMPND %2i",N+1 );
+ strcat ( S,Line );
+ }
+
+ void Compound::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ ContString::write ( f );
+ }
+
+ void Compound::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ ContString::read ( f );
+ }
+
+ MakeStreamFunctions(Compound)
+
+
+
+ // =================== Source ======================
+
+ Source::Source() : ContString() {
+ InitSource();
+ }
+
+ Source::Source ( cpstr S ) : ContString() {
+ InitSource();
+ ConvertPDBASCII ( S );
+ }
+
+ Source::Source ( io::RPStream Object ) : ContString(Object) {
+ InitSource();
+ }
+
+ Source::~Source() {}
+
+ void Source::InitSource() {
+ CreateCopy ( CIFCategory,CIFCAT_STRUCT );
+ CreateCopy ( CIFTag ,CIFTAG_SOURCE );
+ }
+
+ ERROR_CODE Source::ConvertPDBASCII ( cpstr S ) {
+ if (strlen(S)>10)
+ CreateCopy ( Line,&(S[10]) );
+ else CreateCopy ( Line,pstr(" ") );
+ return Error_NoError;
+ }
+
+ void Source::PDBASCIIDump ( pstr S, int N ) {
+ if (N==0) strcpy ( S,"SOURCE " );
+ else sprintf ( S,"SOURCE %2i",N+1 );
+ strcat ( S,Line );
+ }
+
+ void Source::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ ContString::write ( f );
+ }
+
+ void Source::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ ContString::read ( f );
+ }
+
+ MakeStreamFunctions(Source)
+
+
+ // =================== KeyWords ======================
+
+ KeyWords::KeyWords() : io::Stream() {
+ Init();
+ }
+
+ KeyWords::KeyWords ( cpstr S ) : io::Stream() {
+ Init();
+ ConvertPDBASCII ( S );
+ }
+
+ KeyWords::KeyWords ( io::RPStream Object ) : io::Stream(Object) {
+ Init();
+ }
+
+ KeyWords::~KeyWords() {
+ Delete();
+ }
+
+ void KeyWords::Init() {
+ nKeyWords = 0;
+ KeyWord = NULL;
+ Cont = false;
+ }
+
+ void KeyWords::Delete() {
+ int i;
+ if (KeyWord) {
+ for (i=0;i<nKeyWords;i++)
+ if (KeyWord[i])
+ delete[] KeyWord[i];
+ delete[] KeyWord;
+ }
+ nKeyWords = 0;
+ KeyWord = NULL;
+ Cont = false;
+ }
+
+ int KeyWords::ConvertPDBASCII ( cpstr S ) {
+ // we anticipate that length of S is 80 characters
+ // -- pad with spaces if necessary
+ char L[85];
+ int i,k,m;
+ pstr * KW;
+
+ i = 10; // scan PDB line from ith character
+
+ k = nKeyWords;
+ if (!Cont) k++; // 1st keyword does not continue from previous line
+ m = 0;
+ while (S[i] && (i<70)) {
+ if (S[i]==',') k++; // count keywords
+ if (S[i]!=' ') m++; // count non-spaces to see if the line is empty
+ i++;
+ }
+
+ if (m==0) return 0; // empty line
+
+ KW = new pstr[k];
+ if (KeyWord) {
+ for (i=0;i<nKeyWords;i++)
+ KW[i] = KeyWord[i];
+ delete[] KeyWord;
+ }
+ for (i=nKeyWords;i<k;i++)
+ KW[i] = NULL; // null new pointers
+ KeyWord = KW;
+
+ i = 10;
+ if (Cont) nKeyWords--;
+ while (S[i] && (i<70)) {
+ while ((S[i]==' ') && (i<70)) i++; // skip leading spaces
+ if (Cont) {
+ strcpy ( L," " );
+ m = 1;
+ } else
+ m = 0;
+ while (S[i] && (S[i]!=',') && (i<70))
+ L[m++] = S[i++];
+ m--;
+ while ((m>0) && (L[m]==' ')) m--; // remove padding spaces
+ m++;
+ L[m] = char(0);
+ if (Cont) CreateConcat ( KeyWord[nKeyWords],L );
+ else CreateCopy ( KeyWord[nKeyWords],L );
+ if (S[i]==',') {
+ i++;
+ Cont = false;
+ } else
+ Cont = true;
+ nKeyWords++;
+ }
+
+ return 0;
+
+ }
+
+ void KeyWords::PDBASCIIDump ( io::RFile f ) {
+ int N,i,k,m1,m2,ms;
+ char S[85];
+ char c;
+ if (KeyWord) {
+ N = 0;
+ i = 0;
+ while (i<nKeyWords) {
+ if (N==0) strcpy ( S,"KEYWDS " );
+ else sprintf ( S,"KEYWDS %2i ",N+1 );
+ do {
+ while ((i<nKeyWords) && (!KeyWord[i])) i++;
+ if (i<nKeyWords) {
+ m1 = 0;
+ while (KeyWord[i][m1]) {
+ while (KeyWord[i][m1]==' ') m1++;
+ m2 = m1;
+ ms = -1;
+ while ((KeyWord[i][m2]) && ((m2-m1)<58)) {
+ if (KeyWord[i][m2]==' ') ms = m2;
+ m2++;
+ }
+ if ((ms<0) || ((m2-m1)<58)) ms = m2;
+ c = KeyWord[i][ms];
+ KeyWord[i][ms] = char(0);
+ strcat ( S,&(KeyWord[i][m1]) );
+ KeyWord[i][ms] = c;
+ m1 = ms;
+ if (c) {
+ PadSpaces ( S,80 );
+ f.WriteLine ( S );
+ N++;
+ sprintf ( S,"KEYWDS %2i ",N+1 );
+ }
+ }
+ i++;
+ if (i<nKeyWords) {
+ k = strlen(S) + strlen(KeyWord[i]) + 2;
+ if (i<nKeyWords)
+ strcat ( S,", " );
+ } else
+ k = 80;
+ } else
+ k = 80;
+ } while (k<70);
+ PadSpaces ( S,80 );
+ f.WriteLine ( S );
+ N++;
+ }
+ }
+ }
+
+ void KeyWords::MakeCIF ( mmcif::PData CIF ) {
+ int i,k;
+ char S[500];
+ strcpy ( S,"\n" );
+ for (i=0;i<nKeyWords;i++)
+ if (KeyWord[i]) {
+ k = strlen(KeyWord[i]);
+ if (strlen(S)+k>70) {
+ CIF->PutString ( S,CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT,true );
+ if (k>(int)sizeof(S)) {
+ CIF->PutString ( KeyWord[i],CIFCAT_STRUCT_KEYWORDS,
+ CIFTAG_TEXT,true );
+ k = 0;
+ }
+ strcpy ( S,"\n" );
+ }
+ if (k>0) {
+ strcat ( S,KeyWord[i] );
+ if (i<nKeyWords-1) strcat ( S,", " );
+ }
+ }
+ if (strlen(S)>1)
+ CIF->PutString ( S,CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT,true );
+ }
+
+ void KeyWords::GetCIF ( mmcif::PData CIF ) {
+ pstr F;
+ int i,j,k;
+ bool NB;
+ char c;
+ Delete();
+ F = CIF->GetString ( CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT,i );
+ k = 0;
+ if ((!i) && F) {
+ i = 0;
+ NB = false;
+ while (F[i]) {
+ if (F[i]==',') {
+ nKeyWords++;
+ NB = false;
+ } else if (F[i]!=' ')
+ NB = true;
+ i++;
+ }
+ if (NB) nKeyWords++;
+ KeyWord = new pstr[nKeyWords];
+ i = 0;
+ while (F[i] && (k<nKeyWords)) {
+ while ((F[i]==' ') || (F[i]=='\n') || (F[i]=='\r')) i++;
+ j = i;
+ while (F[i] && (F[i]!=',')) i++;
+ c = F[i];
+ F[i] = char(0);
+ KeyWord[k] = NULL;
+ CreateCopy ( KeyWord[k],&(F[j]) );
+ j = 0;
+ while (KeyWord[k][j]) {
+ if ((KeyWord[k][j]=='\n') || (KeyWord[k][j]=='\r'))
+ KeyWord[k][j] = ' ';
+ j++;
+ }
+ F[i] = c;
+ k++;
+ if (F[i]) i++;
+ }
+ }
+ while (k<nKeyWords) KeyWord[k++] = NULL;
+ CIF->DeleteField ( CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT );
+ }
+
+
+ void KeyWords::Copy ( PKeyWords KeyWords ) {
+ int i;
+ Delete();
+ nKeyWords = KeyWords->nKeyWords;
+ if (nKeyWords>0) {
+ KeyWord = new pstr[nKeyWords];
+ for (i=0;i<nKeyWords;i++) {
+ KeyWord[i] = NULL;
+ CreateCopy ( KeyWord[i],KeyWords->KeyWord[i] );
+ }
+ }
+ }
+
+ void KeyWords::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &nKeyWords );
+ for (i=0;i<nKeyWords;i++)
+ f.CreateWrite ( KeyWord[i] );
+ }
+
+ void KeyWords::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ Delete();
+ f.ReadByte ( &Version );
+ f.ReadInt ( &nKeyWords );
+ if (nKeyWords>0) {
+ KeyWord = new pstr[nKeyWords];
+ for (i=0;i<nKeyWords;i++) {
+ KeyWord[i] = NULL;
+ f.CreateRead ( KeyWord[i] );
+ }
+ }
+ }
+
+ MakeStreamFunctions(KeyWords)
+
+
+ // =================== ExpData ======================
+
+ ExpData::ExpData() : ContString() {
+ InitExpData();
+ }
+
+ ExpData::ExpData ( cpstr S ) : ContString() {
+ InitExpData();
+ ConvertPDBASCII ( S );
+ }
+
+ ExpData::ExpData ( io::RPStream Object ) : ContString(Object) {
+ InitExpData();
+ }
+
+ ExpData::~ExpData() {}
+
+ void ExpData::InitExpData() {
+ CreateCopy ( CIFCategory,CIFCAT_EXPTL );
+ CreateCopy ( CIFTag ,CIFTAG_METHOD );
+ }
+
+ ERROR_CODE ExpData::ConvertPDBASCII ( cpstr S ) {
+ if (strlen(S)>10)
+ CreateCopy ( Line,&(S[10]) );
+ else CreateCopy ( Line,pstr(" ") );
+ return Error_NoError;
+ }
+
+ void ExpData::PDBASCIIDump ( pstr S, int N ) {
+ if (N==0) strcpy ( S,"EXPDTA " );
+ else sprintf ( S,"EXPDTA %2i",N+1 );
+ strcat ( S,Line );
+ }
+
+ void ExpData::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ ContString::write ( f );
+ }
+
+ void ExpData::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ ContString::read ( f );
+ }
+
+ MakeStreamFunctions(ExpData)
+
+
+
+
+ // =================== MdlType ======================
+
+ MdlType::MdlType() : ContString() {
+ InitMdlType();
+ }
+
+ MdlType::MdlType ( cpstr S ) : ContString() {
+ InitMdlType();
+ ConvertPDBASCII ( S );
+ }
+
+ MdlType::MdlType ( io::RPStream Object ) : ContString(Object) {
+ InitMdlType();
+ }
+
+ MdlType::~MdlType() {}
+
+ void MdlType::InitMdlType() {
+ CreateCopy ( CIFCategory,CIFCAT_EXPTL );
+ CreateCopy ( CIFTag ,CIFTAG_METHOD );
+ }
+
+ ERROR_CODE MdlType::ConvertPDBASCII ( cpstr S ) {
+ if (strlen(S)>10)
+ CreateCopy ( Line,&(S[10]) );
+ else CreateCopy ( Line,pstr(" ") );
+ return Error_NoError;
+ }
+
+ void MdlType::PDBASCIIDump ( pstr S, int N ) {
+ if (N==0) strcpy ( S,"MDLTYP " );
+ else sprintf ( S,"MDLTYP %2i",N+1 );
+ strcat ( S,Line );
+ }
+
+ void MdlType::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ ContString::write ( f );
+ }
+
+ void MdlType::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ ContString::read ( f );
+ }
+
+ MakeStreamFunctions(MdlType)
+
+
+ // =================== Author ======================
+
+ Author::Author() : ContString() {
+ InitAuthor();
+ }
+
+ Author::Author ( cpstr S ) : ContString() {
+ InitAuthor();
+ ConvertPDBASCII ( S );
+ }
+
+ Author::Author ( io::RPStream Object ) : ContString(Object) {
+ InitAuthor();
+ }
+
+ Author::~Author() {}
+
+ void Author::InitAuthor() {
+ CreateCopy ( CIFCategory,CIFCAT_AUDIT_AUTHOR );
+ CreateCopy ( CIFTag ,CIFTAG_NAME );
+ }
+
+ ERROR_CODE Author::ConvertPDBASCII ( cpstr S ) {
+ if (strlen(S)>10)
+ CreateCopy ( Line,&(S[10]) );
+ else CreateCopy ( Line,pstr(" ") );
+ return Error_NoError;
+ }
+
+ void Author::PDBASCIIDump ( pstr S, int N ) {
+ if (N==0) strcpy ( S,"AUTHOR " );
+ else sprintf ( S,"AUTHOR %2i",N+1 );
+ strcat ( S,Line );
+ }
+
+ void Author::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ ContString::write ( f );
+ }
+
+ void Author::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ ContString::read ( f );
+ }
+
+ MakeStreamFunctions(Author)
+
+
+
+ // ================ RevData ===================
+
+ RevData::RevData() : ContainerClass() {
+ InitRevData();
+ }
+
+ RevData::RevData ( cpstr S ) : ContainerClass() {
+ InitRevData();
+ ConvertPDBASCII ( S );
+ }
+
+ RevData::RevData ( io::RPStream Object ) : ContainerClass(Object) {
+ InitRevData();
+ }
+
+ RevData::~RevData() {}
+
+ void RevData::InitRevData() {
+ int i;
+ modNum = 0;
+ strcpy ( modDate,"DD-MMM-YYYY" );
+ strcpy ( modId , "----" );
+ modType = -1;
+ for (i=0;i<4;i++)
+ strcpy ( record[i]," " );
+ Warning = 0;
+ }
+
+ void RevData::PDBASCIIDump ( pstr S, int N ) {
+ // makes the ASCII PDB REVDATA line number N
+ // from the class' data
+ int i;
+ if (N==0) sprintf ( S,"REVDAT %3i " ,modNum );
+ else sprintf ( S,"REVDAT %3i%2i",modNum,N+1 );
+ i = strlen(S);
+ while (i<80)
+ S[i++] = ' ';
+ S[i] = char(0);
+ Date11to9 ( modDate,&(S[13]) );
+ strncpy ( &(S[23]),modId,5 );
+ S[31] = char(modType+int('0'));
+ for (i=0;i<4;i++)
+ strncpy ( &(S[39+i*7]),record[i],6 );
+ }
+
+ void RevData::MakeCIF ( mmcif::PData CIF, int N ) {
+ mmcif::PLoop Loop;
+ int RC,i,j;
+ char DateCIF[20];
+ RC = CIF->AddLoop ( CIFCAT_DATABASE_PDB_REV,Loop );
+ if ((RC!=mmcif::CIFRC_Ok) || (N==0)) {
+ // the category was (re)created, privide tags
+ Loop->AddLoopTag ( CIFTAG_NUM );
+ Loop->AddLoopTag ( CIFTAG_DATE );
+ Loop->AddLoopTag ( CIFTAG_REPLACES );
+ Loop->AddLoopTag ( CIFTAG_MOD_TYPE );
+ Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_1 );
+ Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_2 );
+ Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_3 );
+ Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_4 );
+ }
+ Date11toCIF ( modDate,DateCIF );
+ Loop->AddInteger ( modNum );
+ Loop->AddString ( DateCIF );
+ Loop->AddString ( modId );
+ Loop->AddInteger ( modType );
+ for (i=0;i<4;i++) {
+ j = 0;
+ while (record[i][j] && (record[i][j]==' ')) j++;
+ if (record[i][j]) Loop->AddString ( record[i] );
+ else Loop->AddString ( NULL );
+ }
+
+ }
+
+ ERROR_CODE RevData::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ int RC;
+ pstr F;
+
+ Loop = CIF->GetLoop ( CIFCAT_DATABASE_PDB_REV );
+ if (!Loop) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+ RC = Loop->GetInteger ( modNum,CIFTAG_NUM,n,true );
+ if (RC==mmcif::CIFRC_WrongIndex) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+ if (RC==mmcif::CIFRC_WrongFormat) {
+ sprintf ( CIFErrorLocation,"loop %s.%s row %i",
+ CIFCAT_DATABASE_PDB_REV,CIFTAG_NUM,n );
+ n = -Error_UnrecognizedInteger-1;
+ return Error_UnrecognizedInteger;
+ }
+
+ F = Loop->GetString ( CIFTAG_DATE,n,RC );
+ if ((!RC) && F) DateCIFto11 ( F,modDate );
+ F = Loop->GetString ( CIFTAG_REPLACES,n,RC );
+ if ((!RC) && F) strcpy ( modId,F );
+ RC = Loop->GetInteger ( modType,CIFTAG_MOD_TYPE,n,true );
+ if (RC==mmcif::CIFRC_WrongFormat) {
+ sprintf ( CIFErrorLocation,"loop %s.%s row %i",
+ CIFCAT_DATABASE_PDB_REV,CIFTAG_MOD_TYPE,n );
+ n = -Error_UnrecognizedInteger-1;
+ return Error_UnrecognizedInteger;
+ }
+
+ F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_1,n,RC );
+ if ((!RC) && F) strcpy ( record[0],F );
+ F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_2,n,RC );
+ if ((!RC) && F) strcpy ( record[1],F );
+ F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_3,n,RC );
+ if ((!RC) && F) strcpy ( record[2],F );
+ F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_4,n,RC );
+ if ((!RC) && F) strcpy ( record[3],F );
+
+ Loop->DeleteField ( CIFTAG_DATE ,n );
+ Loop->DeleteField ( CIFTAG_REPLACES ,n );
+ Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_1,n );
+ Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_2,n );
+ Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_3,n );
+ Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_4,n );
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+ ERROR_CODE RevData::ConvertPDBASCII ( cpstr S ) {
+ int i;
+ pstr endptr;
+ char N[20];
+ Warning = 0;
+ strncpy ( N,&(S[7]),3 );
+ N[3] = char(0);
+ modNum = mround(strtod(N,&endptr));
+ if (endptr==N) Warning |= REVDAT_WARN_MODNUM;
+ Date9to11 ( &(S[13]),modDate );
+ strncpy ( modId,&(S[23]),5 );
+ modId[5] = char(0);
+ modType = int(S[31]) - int('0');
+ if (modType>9) Warning |= REVDAT_WARN_MODTYPE;
+ for (i=0;i<4;i++) {
+ strncpy ( record[i],&(S[39+i*7]),6 );
+ record[i][6] = char(0);
+ }
+ return Error_NoError;
+ }
+
+ void RevData::Copy ( PContainerClass RevData ) {
+ int i;
+ modNum = PRevData(RevData)->modNum;
+ modType = PRevData(RevData)->modType;
+ strcpy ( modDate,PRevData(RevData)->modDate );
+ strcpy ( modId ,PRevData(RevData)->modId );
+ for (i=0;i<4;i++)
+ strcpy ( record[i],PRevData(RevData)->record[i] );
+ }
+
+ void RevData::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &modNum );
+ f.WriteInt ( &modType );
+ f.WriteWord ( &Warning );
+ f.WriteTerLine ( modDate,false );
+ f.WriteTerLine ( modId ,false );
+ for (i=0;i<4;i++)
+ f.WriteTerLine ( record[i],false );
+ }
+
+ void RevData::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &modNum );
+ f.ReadInt ( &modType );
+ f.ReadWord ( &Warning );
+ f.ReadTerLine ( modDate,false );
+ f.ReadTerLine ( modId ,false );
+ for (i=0;i<4;i++)
+ f.ReadTerLine ( record[i],false );
+ }
+
+ MakeStreamFunctions(RevData)
+
+
+
+ // ================ Supersede ===================
+
+ Supersede::Supersede() : ContainerClass() {
+ InitSupersede();
+ }
+
+ Supersede::Supersede ( cpstr S ) : ContainerClass() {
+ InitSupersede();
+ ConvertPDBASCII ( S );
+ }
+
+ Supersede::Supersede ( io::RPStream Object ) : ContainerClass(Object) {
+ InitSupersede();
+ }
+
+ Supersede::~Supersede() {}
+
+ void Supersede::InitSupersede() {
+ int i;
+ strcpy ( sprsdeDate,"DD-MMM-YYYY" );
+ strcpy ( idCode, "----" );
+ for (i=0;i<8;i++)
+ strcpy ( sIdCode[i]," " );
+ }
+
+ void Supersede::PDBASCIIDump ( pstr S, int N ) {
+ // makes the ASCII PDB OBSLTE line number N
+ // from the class' data
+ int i;
+ if (N==0) strcpy ( S,"SPRSDE " );
+ else sprintf ( S,"SPRSDE %2i",N+1 );
+ i = strlen(S);
+ while (i<80)
+ S[i++] = ' ';
+ S[i] = char(0);
+ if (N==0) {
+ Date11to9 ( sprsdeDate,&(S[11]) );
+ strncpy ( &(S[21]),idCode,4 );
+ }
+ for (i=0;i<8;i++)
+ strncpy ( &(S[31+5*i]),sIdCode[i],4 );
+ }
+
+ void Supersede::MakeCIF ( mmcif::PData CIF, int ) {
+ mmcif::PLoop Loop;
+ int RC,i,j;
+ char DateCIF[20];
+ RC = CIF->AddLoop ( CIFCAT_SPRSDE,Loop );
+ if (RC!=mmcif::CIFRC_Ok) {
+ // the category was (re)created, privide tags
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_DATE );
+ Loop->AddLoopTag ( CIFTAG_REPLACE_PDB_ID );
+ Loop->AddLoopTag ( CIFTAG_PDB_ID );
+ }
+ Date11toCIF ( sprsdeDate,DateCIF );
+ for (i=0;i<8;i++) {
+ j = 0;
+ while (sIdCode[i][j] && (sIdCode[i][j]==' ')) j++;
+ if (sIdCode[i][j]) {
+ Loop->AddString ( pstr("SPRSDE") );
+ Loop->AddString ( DateCIF );
+ Loop->AddString ( idCode );
+ Loop->AddString ( sIdCode[i] );
+ }
+ }
+ }
+
+ ERROR_CODE Supersede::ConvertPDBASCII ( cpstr S ) {
+ int i;
+ if (S[9]==' ') {
+ Date9to11 ( &(S[11]),sprsdeDate );
+ strncpy ( idCode,&(S[21]),4 );
+ idCode[4] = char(0);
+ }
+ for (i=0;i<8;i++) {
+ strncpy ( sIdCode[i],&(S[31+i*5]),4 );
+ sIdCode[i][4] = char(0);
+ }
+ return Error_NoError;
+ }
+
+ ERROR_CODE Supersede::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ int i,RC;
+ pstr F,FDate,FID;
+ char DateCIF [20];
+ char DateCIF0[20];
+ IDCode idCode1;
+
+ Loop = CIF->GetLoop ( CIFCAT_SPRSDE );
+ if (!Loop) {
+ n = -1; // signal to finish processing of this structure
+ return Error_EmptyCIF;
+ }
+ i = 0;
+ do {
+ F = Loop->GetString ( CIFTAG_ID,n,RC );
+ if (RC) {
+ if (i==0) {
+ n = -1;
+ return Error_EmptyCIF;
+ } else
+ return Error_NoError;
+ }
+ if (F) {
+ if (!strcmp(F,"SPRSDE")) {
+ FDate = Loop->GetString ( CIFTAG_DATE,n,RC );
+ if ((!RC) && FDate)
+ strncpy ( DateCIF,FDate,15 );
+ else strcpy ( DateCIF,"YYYY-MMM-DD" );
+ FID = Loop->GetString ( CIFTAG_REPLACE_PDB_ID,n,RC );
+ if ((!RC) && FID)
+ strncpy ( idCode1,FID,sizeof(IDCode)-1 );
+ else idCode1[0] = char(0);
+ if (i==0) {
+ DateCIFto11 ( DateCIF,sprsdeDate );
+ DateCIF[11] = char(0);
+ strcpy ( idCode ,idCode1 );
+ strcpy ( DateCIF0,DateCIF );
+ } else if ((strcmp(DateCIF0,DateCIF)) ||
+ (strcmp(idCode,idCode1)))
+ return Error_NoError;
+ FID = Loop->GetString ( CIFTAG_PDB_ID,n,RC );
+ if ((!RC) && FID)
+ strncpy ( sIdCode[i],FID,sizeof(IDCode)-1 );
+ else sIdCode[i][0] = char(0);
+ Loop->DeleteField ( CIFTAG_ID ,n );
+ Loop->DeleteField ( CIFTAG_DATE ,n );
+ Loop->DeleteField ( CIFTAG_REPLACE_PDB_ID,n );
+ Loop->DeleteField ( CIFTAG_PDB_ID ,n );
+ i++;
+ }
+ }
+ n++;
+ } while (i<8);
+
+ return Error_NoError;
+
+ }
+
+ void Supersede::Copy ( PContainerClass Supersede ) {
+ int i;
+ strcpy ( sprsdeDate,PSupersede(Supersede)->sprsdeDate );
+ strcpy ( idCode ,PSupersede(Supersede)->idCode );
+ for (i=0;i<8;i++)
+ strcpy ( sIdCode[i],PSupersede(Supersede)->sIdCode[i] );
+ }
+
+ void Supersede::write ( io::RFile f ) {
+ int i;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteTerLine ( sprsdeDate,false );
+ f.WriteTerLine ( idCode ,false );
+ for (i=0;i<8;i++)
+ f.WriteTerLine ( sIdCode[i],false );
+ }
+
+ void Supersede::read ( io::RFile f ) {
+ int i;
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadTerLine ( sprsdeDate,false );
+ f.ReadTerLine ( idCode ,false );
+ for (i=0;i<8;i++)
+ f.ReadTerLine ( sIdCode[i],false );
+ }
+
+ MakeStreamFunctions(Supersede)
+
+
+ // =================== Journal ======================
+
+ Journal::Journal() : ContString() {
+ InitJournal();
+ }
+
+ Journal::Journal ( cpstr S ) : ContString() {
+ InitJournal();
+ ConvertPDBASCII ( S );
+ }
+
+ Journal::Journal ( io::RPStream Object ) : ContString(Object) {
+ InitJournal();
+ }
+
+ Journal::~Journal() {}
+
+ void Journal::InitJournal() {
+ CreateCopy ( CIFCategory,CIFCAT_CITATION );
+ CreateCopy ( CIFTag ,CIFTAG_TEXT );
+ }
+
+ ERROR_CODE Journal::ConvertPDBASCII ( cpstr S ) {
+ if (strlen(S)>10)
+ CreateCopy ( Line,&(S[10]) );
+ else CreateCopy ( Line,pstr(" ") );
+ return Error_NoError;
+ }
+
+ void Journal::PDBASCIIDump ( pstr S, int ) {
+ strcpy ( S,"JRNL " );
+ strcat ( S,Line );
+ }
+
+ void Journal::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ ContString::write ( f );
+ }
+
+ void Journal::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ ContString::read ( f );
+ }
+
+ MakeStreamFunctions(Journal)
+
+
+
+ // =================== Remark ======================
+
+ Remark::Remark() : ContainerClass() {
+ InitRemark();
+ }
+
+ Remark::Remark ( cpstr S ) : ContainerClass() {
+ InitRemark();
+ ConvertPDBASCII ( S );
+ }
+
+ Remark::Remark ( io::RPStream Object ) : ContainerClass(Object) {
+ InitRemark();
+ }
+
+ Remark::~Remark() {
+ if (remark) delete[] remark;
+ }
+
+ void Remark::InitRemark() {
+ remarkNum = 0;
+ remark = NULL;
+ }
+
+ ERROR_CODE Remark::ConvertPDBASCII ( cpstr S ) {
+ int i;
+ GetInteger ( remarkNum,&(S[7]),3 );
+ if (remarkNum==MinInt4) CreateCopy ( remark,S );
+ else if (strlen(S)>11) CreateCopy ( remark,&(S[11]) );
+ else CreateCopy ( remark,pstr(" ") );
+ i = strlen(remark)-1;
+ while ((i>0) && (remark[i]==' ')) i--;
+ remark[i+1] = char(0);
+ return Error_NoError;
+ }
+
+ void Remark::PDBASCIIDump ( pstr S, int ) {
+ if (remarkNum==MinInt4)
+ strcpy ( S,remark );
+ else {
+ strcpy ( S,"REMARK" );
+ PadSpaces ( S,80 );
+ PutInteger ( &(S[7]) ,remarkNum,3 );
+ strncpy ( &(S[11]),remark,IMin(68,strlen(remark)) );
+ }
+ }
+
+ void Remark::MakeCIF ( mmcif::PData CIF, int N ) {
+ mmcif::PLoop Loop;
+ int RC;
+ RC = CIF->AddLoop ( CIFCAT_NDB_DATABASE_REMARK,Loop );
+ if ((RC!=mmcif::CIFRC_Ok) || (N==0)) {
+ // the category was (re)created, privide tags
+ Loop->AddLoopTag ( CIFTAG_ID );
+ Loop->AddLoopTag ( CIFTAG_TEXT );
+ }
+ if (remarkNum==MinInt4) Loop->AddString ( NULL );
+ else Loop->AddInteger ( remarkNum );
+ Loop->AddString ( remark );
+ }
+
+ ERROR_CODE Remark::GetCIF ( mmcif::PData CIF, int & n ) {
+ mmcif::PLoop Loop;
+ int RC;
+
+ Loop = CIF->GetLoop ( CIFCAT_NDB_DATABASE_REMARK );
+ if (!Loop) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+ if (n>=Loop->GetLoopLength() ) {
+ n = -1;
+ return Error_EmptyCIF;
+ }
+
+ RC = Loop->GetInteger ( remarkNum,CIFTAG_ID,n,true );
+ if (RC==mmcif::CIFRC_WrongFormat) {
+ sprintf ( CIFErrorLocation,"loop %s.%s row %i",
+ CIFCAT_NDB_DATABASE_REMARK,CIFTAG_ID,n );
+ n = -Error_UnrecognizedInteger-1;
+ return Error_UnrecognizedInteger;
+ } else if (RC)
+ remarkNum = MinInt4;
+ Loop->GetString ( remark,CIFTAG_TEXT,n,true );
+
+ n++;
+
+ return Error_NoError;
+
+ }
+
+ void Remark::Copy ( PContainerClass RemarkClass ) {
+ remarkNum = PRemark(RemarkClass)->remarkNum;
+ CreateCopy ( remark,PRemark(RemarkClass)->remark );
+ }
+
+ void Remark::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &remarkNum );
+ f.CreateWrite ( remark );
+ }
+
+ void Remark::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.ReadInt ( &remarkNum );
+ f.CreateRead ( remark );
+ }
+
+ MakeStreamFunctions(Remark)
+
+
+ // ================= Biomolecule =====================
+
+ #define R350_ERRBIOMT (-3)
+ #define R350_ERROR (-2)
+ #define R350_END (-1)
+ #define R350_NONE 0
+ #define R350_BIOMOLECULE 1
+ #define R350_CHAINS 2
+ #define R350_BIOMT 3
+
+ void getRemarkKey ( RPRemark rem, int & lkey ) {
+ if (rem) {
+ if (rem->remarkNum!=350) lkey = R350_END;
+ else if (rem->remark) {
+ if (strcasestr(rem->remark,"BIOMOLECULE:"))
+ lkey = R350_BIOMOLECULE;
+ else if (strcasestr(rem->remark,"CHAINS:"))
+ lkey = R350_CHAINS;
+ else if (strcasestr(rem->remark,"BIOMT1") ||
+ strcasestr(rem->remark,"BIOMT2") ||
+ strcasestr(rem->remark,"BIOMT3"))
+ lkey = R350_BIOMT;
+ else
+ lkey = R350_NONE;
+ }
+ }
+ }
+
+ int lookupRemarks ( int & i, RPRemark rem,
+ RTitleContainer Remark ) {
+ int l,lkey;
+
+ l = Remark.Length();
+ lkey = R350_NONE;
+ while ((i<l) && (lkey==R350_NONE)) {
+ getRemarkKey ( rem,lkey );
+ if (lkey==R350_NONE) {
+ i++;
+ rem = (PRemark)Remark.GetContainerClass ( i );
+ }
+ }
+
+ return lkey;
+
+ }
+
+
+
+ BMApply::BMApply() : io::Stream() {
+ InitBMApply();
+ }
+
+ BMApply::BMApply ( io::RPStream Object ) : io::Stream ( Object ) {
+ InitBMApply();
+ }
+
+ BMApply::~BMApply() {
+ FreeMemory();
+ }
+
+ void BMApply::InitBMApply() {
+ chain = NULL;
+ nChains = 0;
+ tm = NULL;
+ nMatrices = 0;
+ }
+
+ void BMApply::FreeMemory() {
+ if (chain) delete[] chain;
+ if (tm) delete[] tm;
+ chain = NULL;
+ nChains = 0;
+ tm = NULL;
+ nMatrices = 0;
+ }
+
+ int BMApply::addChains ( int & i, RPRemark rem,
+ RTitleContainer Remark ) {
+ PChainID ch1;
+ pstr p;
+ int l,lkey,nAdd,j;
+
+ l = Remark.Length();
+ lkey = R350_NONE;
+
+ while ((i<l) && (lkey==R350_NONE)) {
+
+ p = strcasestr ( rem->remark,"CHAINS:" );
+ if (p) p += 7;
+ else {
+ p = rem->remark;
+ while (*p==' ') p++;
+ if ((p[1]!=',') && (p[1]!=' ')) p = NULL;
+ }
+
+ if (p) {
+ nAdd = strlen(p)/2 + 3;
+ ch1 = chain;
+ chain = new ChainID[nChains+nAdd];
+ for (j=0;j<nChains;j++)
+ strcpy ( chain[j],ch1[j] );
+ if (ch1) delete[] ch1;
+
+ while (*p) {
+ while ((*p==' ') || (*p==',')) p++;
+ if (*p) {
+ if ((p[1]==',') || (p[1]==' ') || (p[1]==char(0))) {
+ chain[nChains][0] = *p;
+ chain[nChains][1] = char(0);
+ nChains++;
+ p++;
+ } else
+ break;
+ }
+ }
+ }
+
+ do {
+ i++;
+ if (i<l) {
+ rem = (PRemark)Remark.GetContainerClass ( i );
+ if (rem) {
+ if (rem->remarkNum!=350) lkey = R350_END;
+ else getRemarkKey ( rem,lkey );
+ }
+ } else
+ lkey = R350_END;
+ } while ((!rem) && (lkey==R350_NONE));
+
+ }
+
+ return lkey;
+
+ }
+
+ int getBIOMT ( RPRemark rem, int biomtNo, mat44 & t,
+ RTitleContainer Remark, int & i ) {
+ char PN[20];
+ pstr p1,p2;
+ int l,j,lkey;
+
+ sprintf ( PN,"BIOMT%1i",biomtNo );
+ p1 = strcasestr ( rem->remark,PN );
+ if (!p1) return R350_ERRBIOMT;
+
+ p1 += 6;
+ while (*p1==' ') p1++;
+ while (*p1 && (*p1!=' ')) p1++;
+
+ l = biomtNo - 1;
+ t[l][0] = strtod ( p1,&p2 );
+ if (p1==p2) return R350_ERRBIOMT;
+ t[l][1] = strtod ( p2,&p1 );
+ if (p1==p2) return R350_ERRBIOMT;
+ t[l][2] = strtod ( p1,&p2 );
+ if (p1==p2) return R350_ERRBIOMT;
+ t[l][3] = strtod ( p2,&p1 );
+ if (p1==p2) return R350_ERRBIOMT;
+
+ if (biomtNo==3) {
+ for (j=0;j<3;j++)
+ t[3][j] = 0.0;
+ t[3][3] = 1.0;
+ }
+
+ l = Remark.Length();
+ lkey = R350_BIOMT;
+ do {
+ i++;
+ if (i<l) {
+ rem = (PRemark)Remark.GetContainerClass ( i );
+ if (rem) {
+ if (rem->remarkNum!=350) lkey = R350_END;
+ else getRemarkKey ( rem,lkey );
+ }
+ } else
+ lkey = R350_END;
+ } while ((lkey==R350_NONE) || ((!rem) && (lkey==R350_BIOMT)));
+
+ return lkey;
+
+ }
+
+ int BMApply::addMatrices ( int & i, RPRemark rem,
+ RTitleContainer Remark ) {
+ pmat44 tm1;
+ int l,lkey,j,k1,k2,nAlloc;
+
+ l = Remark.Length();
+ lkey = R350_BIOMT;
+ nAlloc = nMatrices;
+
+ while ((i<l) && (lkey==R350_BIOMT)) {
+
+ if (nMatrices>=nAlloc) {
+ nAlloc = nMatrices + 10;
+ tm1 = tm;
+ tm = new mat44[nAlloc];
+ for (j=0;j<nMatrices;j++)
+ for (k1=0;k1<4;k1++)
+ for (k2=0;k2<4;k2++)
+ tm[j][k1][k2] = tm1[j][k1][k2];
+ if (tm1) delete[] tm1;
+ }
+
+ lkey = getBIOMT ( rem,1,tm[nMatrices],Remark,i );
+ if (lkey==R350_BIOMT)
+ lkey = getBIOMT ( rem,2,tm[nMatrices],Remark,i );
+ if (lkey==R350_BIOMT)
+ lkey = getBIOMT ( rem,3,tm[nMatrices],Remark,i );
+ nMatrices++;
+
+ }
+
+ return lkey;
+
+ }
+
+ void BMApply::Copy ( PBMApply BMA ) {
+ // if BMA is NULL, then empties the class
+ int i,j,k;
+
+ FreeMemory();
+
+ if (BMA) {
+
+ nChains = BMA->nChains;
+ if (nChains>0) {
+ chain = new ChainID[nChains];
+ for (i=0;i<nChains;i++)
+ strcpy ( chain[i],BMA->chain[i] );
+ }
+
+ nMatrices = BMA->nMatrices;
+ if (nMatrices>0) {
+ tm = new mat44[nMatrices];
+ for (i=0;i<nMatrices;i++)
+ for (j=0;j<4;j++)
+ for (k=0;k<4;k++)
+ tm[i][j][k] = BMA->tm[i][j][k];
+ }
+ }
+
+ }
+
+ void BMApply::write ( io::RFile f ) {
+ int i,j,k;
+ f.WriteInt ( &nChains );
+ for (i=0;i<nChains;i++)
+ f.WriteTerLine ( chain[i],false );
+ f.WriteInt ( &nMatrices );
+ for (i=0;i<nMatrices;i++)
+ for (j=0;j<3;j++)
+ for (k=0;k<4;k++)
+ f.WriteReal ( &(tm[i][j][k]) );
+ }
+
+ void BMApply::read ( io::RFile f ) {
+ int i,j,k;
+ FreeMemory();
+ f.ReadInt ( &nChains );
+ if (nChains>0) {
+ chain = new ChainID[nChains];
+ for (i=0;i<nChains;i++)
+ f.ReadTerLine ( chain[i],false );
+ }
+ f.ReadInt ( &nMatrices );
+ if (nMatrices>0) {
+ tm = new mat44[nMatrices];
+ for (i=0;i<nMatrices;i++) {
+ for (j=0;j<3;j++) {
+ for (k=0;k<4;k++)
+ f.ReadReal ( &(tm[i][j][k]) );
+ tm[i][3][j] = 0.0;
+ }
+ tm[i][3][3] = 1.0;
+ }
+ }
+ }
+
+ MakeStreamFunctions(BMApply)
+
+
+ Biomolecule::Biomolecule() : io::Stream() {
+ InitBiomolecule();
+ }
+
+ Biomolecule::Biomolecule ( io::RPStream Object )
+ : io::Stream ( Object ) {
+ InitBiomolecule();
+ }
+
+ Biomolecule::~Biomolecule() {
+ FreeMemory();
+ }
+
+ void Biomolecule::InitBiomolecule() {
+ bmApply = NULL;
+ nBMAs = 0;
+ }
+
+ void Biomolecule::FreeMemory() {
+ int i;
+ if (bmApply) {
+ for (i=0;i<nBMAs;i++)
+ if (bmApply[i]) delete bmApply[i];
+ delete[] bmApply;
+ bmApply = NULL;
+ }
+ nBMAs = 0;
+ }
+
+
+ PBMApply Biomolecule::addBMApply() {
+ PPBMApply bmA1;
+ int i;
+ bmA1 = bmApply;
+ bmApply = new PBMApply[nBMAs+1];
+ for (i=0;i<nBMAs;i++)
+ bmApply[i] = bmA1[i];
+ if (bmA1) delete[] bmA1;
+ bmApply[nBMAs] = new BMApply();
+ nBMAs++;
+ return bmApply[nBMAs-1];
+ }
+
+ int Biomolecule::Size() {
+ int i,k;
+ k = 0;
+ for (i=0;i<nBMAs;i++)
+ k += bmApply[i]->nChains*bmApply[i]->nMatrices;
+ return k;
+ }
+
+ bool Biomolecule::checkComposition ( PChainID chID, ivector occ,
+ ivector wocc, int n ) {
+ // chID[n] is list of chain IDs
+ // occ[n] is list of chain occurencies
+ // wocc[n] is working array
+ int i,j,k,k1;
+ bool cmp;
+
+ for (i=0;i<n;i++)
+ wocc[i] = 0;
+
+ cmp = true;
+
+ for (i=0;(i<nBMAs) && cmp;i++)
+ for (j=0;(j<bmApply[i]->nChains) && cmp;j++) {
+ k1 = -1;
+ for (k=0;(k<n) && (k1<0);k++)
+ if (!strcmp(chID[k],bmApply[i]->chain[j]))
+ k1 = k;
+ if (k1<0) cmp = false; // chain not found in the list
+ else wocc[k1] += bmApply[i]->nMatrices;
+ }
+
+ for (i=0;(i<n) && cmp;i++)
+ if (occ[i]!=wocc[i]) cmp = false;
+
+ return cmp;
+
+ }
+
+ void Biomolecule::Copy ( PBiomolecule B ) {
+ // if B is NULL, then empties the class
+ int i;
+
+ FreeMemory();
+
+ if (B) {
+
+ nBMAs = B->nBMAs;
+ if (nBMAs>0) {
+ bmApply = new PBMApply[nBMAs];
+ for (i=0;i<nBMAs;i++)
+ if (B->bmApply[i]) {
+ bmApply[i] = new BMApply();
+ bmApply[i]->Copy ( B->bmApply[i] );
+ } else
+ bmApply[i] = NULL;
+ }
+
+ }
+
+ }
+
+ void Biomolecule::write ( io::RFile f ) {
+ int i;
+ f.WriteInt ( &nBMAs );
+ for (i=0;i<nBMAs;i++)
+ StreamWrite ( f,bmApply[i] );
+ }
+
+ void Biomolecule::read ( io::RFile f ) {
+ int i;
+ FreeMemory();
+ f.ReadInt ( &nBMAs );
+ if (nBMAs>0) {
+ bmApply = new PBMApply[nBMAs];
+ for (i=0;i<nBMAs;i++) {
+ bmApply[i] = NULL;
+ StreamRead ( f,bmApply[i] );
+ }
+ }
+ }
+
+ MakeStreamFunctions(Biomolecule)
+
+
+ // ===================== Title =======================
+
+ Title::Title() : io::Stream() {
+ Init();
+ }
+
+ Title::Title ( io::RPStream Object ) : io::Stream(Object) {
+ Init();
+ }
+
+ void Title::Init() {
+
+ // Header data
+ classification = NULL;
+ depDate[0] = char(0);
+ idCode [0] = char(0);
+ resolution = -2.0;
+ col73 = false;
+
+ biomolecule = NULL;
+ nBiomolecules = 0;
+
+ }
+
+ Title::~Title() {
+ FreeMemory ( false );
+ }
+
+ void Title::FreeMemory ( bool keepBiomolecules ) {
+
+ if (classification) delete[] classification;
+ classification = NULL;
+ resolution = -2.0;
+
+ obsData .FreeContainer();
+ title .FreeContainer();
+ caveat .FreeContainer();
+ compound .FreeContainer();
+ source .FreeContainer();
+ keyWords .Delete ();
+ expData .FreeContainer();
+ mdlType .FreeContainer();
+ author .FreeContainer();
+ revData .FreeContainer();
+ supersede.FreeContainer();
+ journal .FreeContainer();
+ remark .FreeContainer();
+
+ col73 = false;
+
+ if (!keepBiomolecules)
+ FreeBiomolecules();
+
+ }
+
+ void Title::FreeBiomolecules() {
+ int i;
+ if (biomolecule) {
+ for (i=0;i<nBiomolecules;i++)
+ if (biomolecule[i]) delete biomolecule[i];
+ delete[] biomolecule;
+ biomolecule = NULL;
+ }
+ nBiomolecules = 0;
+ }
+
+
+ void Title::SetHeader ( cpstr Classification,
+ cpstr DepDate,
+ cpstr IDCode ) {
+ // fills the PDB file header
+ CreateCopy ( classification ,Classification );
+ strncpy ( depDate,DepDate,sizeof(depDate) );
+ strncpy ( idCode ,IDCode ,sizeof(idCode) );
+ depDate[sizeof(depDate)-1] = char(0);
+ idCode [sizeof(idCode) -1] = char(0);
+ }
+
+ ERROR_CODE Title::ConvertPDBString ( pstr PDBString ) {
+ // Interprets the ASCII PDB line belonging to the title section
+ // and fills the corresponding fields.
+ // Returns zero if the line was converted, otherwise returns a
+ // non-negative value of Error_XXXX.
+ // PDBString must be not shorter than 81 characters.
+ int i;
+ char c;
+ PContainerClass ContainerClass;
+
+ // pad input line with spaces, if necessary
+ PadSpaces ( PDBString,80 );
+
+ if (!strncmp(PDBString,"HEADER",6)) {
+
+ i = 49;
+ while ((i>=10) && (PDBString[i]==' ')) i--;
+ i++;
+ c = PDBString[i];
+ PDBString[i] = char(0);
+ CreateCopy ( classification,&(PDBString[10]) );
+ PDBString[i] = c;
+
+ Date9to11 ( &(PDBString[50]),depDate );
+
+ strncpy ( idCode,&(PDBString[62]),4 );
+ idCode[4] = char(0);
+
+ } else if (!strncmp(PDBString,"OBSLTE",6)) {
+
+ ContainerClass = new ObsLine(PDBString);
+ obsData.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"TITLE ",6)) {
+
+ ContainerClass = new TitleLine(PDBString);
+ title.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"CAVEAT",6)) {
+
+ ContainerClass = new Caveat(PDBString);
+ caveat.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"COMPND",6)) {
+
+ ContainerClass = new Compound(PDBString);
+ compound.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"SOURCE",6)) {
+
+ ContainerClass = new Source(PDBString);
+ source.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"KEYWDS",6)) {
+
+ keyWords.ConvertPDBASCII ( PDBString );
+
+ } else if (!strncmp(PDBString,"EXPDTA",6)) {
+
+ ContainerClass = new ExpData(PDBString);
+ expData.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"MDLTYPE",6)) {
+
+ ContainerClass = new MdlType(PDBString);
+ mdlType.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"AUTHOR",6)) {
+
+ ContainerClass = new Author(PDBString);
+ author.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"REVDAT",6)) {
+
+ ContainerClass = new RevData(PDBString);
+ revData.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"SPRSDE",6)) {
+
+ ContainerClass = new Supersede(PDBString);
+ supersede.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"JRNL ",6)) {
+
+ ContainerClass = new Journal(PDBString);
+ journal.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"REMARK",6)) {
+
+ ContainerClass = new Remark(PDBString);
+ remark.AddData ( ContainerClass );
+
+ } else if (!strncmp(PDBString,"SPLIT ",6)) {
+ // do nothing at the moment
+ } else
+ return Error_WrongSection;
+
+ // check for ID code in columns 73-80
+
+ if (!col73) {
+ if (('0'<=idCode[0]) && (idCode[0]<='9')) {
+ if (!strncasecmp(idCode,&(PDBString[72]),4))
+ col73 = true;
+ }
+ }
+
+ return Error_NoError;
+
+ }
+
+ realtype Title::GetResolution() {
+ // returns -1.0 if there is no resolution record in the file
+ PRemark rem;
+ pstr p,eptr;
+ int i,l;
+ if (resolution>-1.5) return resolution;
+ l = remark.Length();
+ for (i=0;(i<l) && (resolution<-1.5);i++) {
+ rem = (PRemark)remark.GetContainerClass ( i );
+ if (rem) {
+ if (rem->remarkNum==2) {
+ if (rem->remark) {
+ p = strcasestr ( rem->remark,"RESOLUTION" );
+ if (p) {
+ while ((*p) && (*p!=' ')) p++;
+ if (*p) {
+ resolution = strtod ( p,&eptr );
+ if ((resolution<0.0) || (eptr==p))
+ resolution = -1.0;
+ }
+ }
+ }
+ } else if (rem->remarkNum>2)
+ resolution = -1.0;
+ }
+ }
+ return resolution;
+ }
+
+ PBiomolecule Title::addBiomolecule() {
+ PPBiomolecule BM1;
+ int i;
+ BM1 = biomolecule;
+ biomolecule = new PBiomolecule[nBiomolecules+1];
+ for (i=0;i<nBiomolecules;i++)
+ biomolecule[i] = BM1[i];
+ if (BM1) delete[] BM1;
+ biomolecule[nBiomolecules] = new Biomolecule();
+ nBiomolecules++;
+ return biomolecule[nBiomolecules-1];
+ }
+
+ int Title::ParseBiomolecules() {
+ PRemark rem;
+ PBiomolecule BMol;
+ PBMApply BMA;
+ int i,l, lkey;
+
+ FreeBiomolecules();
+
+ l = remark.Length();
+ i = 0;
+ lkey = 0;
+ while ((i<l) && (!lkey)) {
+ rem = (PRemark)remark.GetContainerClass ( i );
+ if (rem) {
+ if (rem->remarkNum==350) lkey = 1;
+ else if (rem->remarkNum>350) lkey = -1;
+ }
+ if (!lkey) i++;
+ }
+
+ BMol = NULL;
+ BMA = NULL;
+
+ while (lkey>0) {
+
+ rem = (PRemark)remark.GetContainerClass ( i );
+ lkey = lookupRemarks ( i,rem,remark );
+
+ switch (lkey) {
+ case R350_BIOMOLECULE : BMol = addBiomolecule();
+ i++;
+ break;
+ case R350_CHAINS : if (BMol) {
+ BMA = BMol->addBMApply();
+ while (lkey==R350_CHAINS)
+ lkey = BMA->addChains(i,rem,remark);
+ } else
+ lkey = R350_ERROR;
+ break;
+ case R350_BIOMT : if (BMA)
+ lkey = BMA->addMatrices(i,rem,remark);
+ else
+ lkey = R350_ERROR;
+ break;
+ default : i++;
+ }
+
+ }
+
+ if (lkey<=R350_ERROR) {
+ FreeBiomolecules();
+ return lkey;
+ }
+
+ return nBiomolecules;
+
+ }
+
+ int Title::GetNofBiomolecules() {
+ return nBiomolecules;
+ }
+
+ void Title::GetBiomolecules ( PPBiomolecule & BM, int & nBMs ) {
+ BM = biomolecule;
+ nBMs = nBiomolecules;
+ }
+
+ PBiomolecule Title::GetBiomolecule ( int bmNo ) { // bmno=0,1,..
+ if ((0<=bmNo) && (bmNo<nBiomolecules))
+ return biomolecule[bmNo];
+ return NULL;
+ }
+
+
+ ERROR_CODE Title::GetCIF ( mmcif::PData CIF ) {
+ pstr S;
+ ERROR_CODE RC;
+
+ S = NULL;
+ CIF->GetDataName ( S,true );
+ if (!S) CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_ENTRY_ID,true );
+ if (!S) CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_CODE_NDB,true );
+ if (!S) CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_CODE_PDB,true );
+ if (S) {
+ strncpy ( idCode,S,sizeof(IDCode)-1 );
+ idCode[sizeof(IDCode)-1] = char(0);
+ delete[] S;
+ S = NULL;
+ CIF->DeleteField ( CIFCAT_DATABASE,CIFTAG_ENTRY_ID );
+ CIF->DeleteField ( CIFCAT_DATABASE,CIFTAG_CODE_NDB );
+ CIF->DeleteField ( CIFCAT_DATABASE,CIFTAG_CODE_PDB );
+ } else
+ idCode[0] = char(0);
+ CIF->GetString ( classification,CIFCAT_STRUCT_KEYWORDS,
+ CIFTAG_NDB_KEYWORDS,true );
+ CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_DATE_ORIGINAL,true );
+ if (S) {
+ DateCIFto11 ( S,depDate );
+ delete[] S;
+ S = NULL;
+ } else
+ depDate[0] = char(0);
+
+ if (CIF->GetReal(resolution,CIFCAT_REFINE,
+ CIFTAG_LS_D_RES_HIGH,false)!=mmcif::CIFRC_Ok)
+ resolution = -2.0;
+
+ obsData .GetCIF ( CIF,ClassID_ObsLine );
+ title .GetCIF ( CIF,ClassID_TitleLine );
+ caveat .GetCIF ( CIF,ClassID_CAVEAT );
+ compound.GetCIF ( CIF,ClassID_Compound );
+ source .GetCIF ( CIF,ClassID_Source );
+ keyWords.GetCIF ( CIF );
+ expData .GetCIF ( CIF,ClassID_ExpData );
+ mdlType .GetCIF ( CIF,ClassID_MdlType );
+ author .GetCIF ( CIF,ClassID_Author );
+ RC = revData.GetCIF ( CIF,ClassID_RevData );
+ if (RC!=Error_NoError) {
+ supersede.GetCIF ( CIF,ClassID_Supersede );
+ journal .GetCIF ( CIF,ClassID_Journal );
+ RC = remark.GetCIF ( CIF,ClassID_Remark );
+ }
+ return RC;
+
+ }
+
+ void Title::MakePDBHeaderString ( pstr PDBString ) {
+ // makes the ASCII PDB HEADER line from the class' data
+ int i;
+
+ if (classification) {
+
+ strcpy ( PDBString,"HEADER " );
+ strcat ( PDBString,classification );
+ i = strlen(PDBString);
+ while (i<80)
+ PDBString[i++] = ' ';
+ PDBString[IMin(i,80)] = char(0);
+ Date11to9 ( depDate,&(PDBString[50]) );
+ strncpy ( &(PDBString[62]),idCode,4 );
+
+ } else
+ strcpy ( PDBString,
+ "HEADER XXXXXXXXXXXXXXXXXXXXXXXXXXXX XX-XXX-XX ----" );
+
+ }
+
+ pstr Title::GetStructureTitle ( pstr & S ) {
+ // GetStructureTitle() returns the contents of TITLE record
+ // unfolded into single line. If Title is missing, returns
+ // contents of COMPND(:MOLECULE). If COMPND is missing, returns
+ // HEADER. If Header is missing, returns PDB code. If no PDB
+ // code is there, returns "Not available".
+ PTitleLine TLine;
+ PCompound CLine;
+ pstr p;
+ int i,cl,l;
+ bool B;
+
+ if (S) delete[] S;
+ S = NULL;
+
+ cl = title.Length();
+ if (cl>0) {
+ l = 0;
+ for (i=0;i<cl;i++) {
+ TLine = PTitleLine(title.GetContainerClass(i));
+ if (TLine) l += strlen_des(TLine->Line)+5;
+ }
+ S = new char[l];
+ S[0] = char(0);
+ for (i=0;i<cl;i++) {
+ TLine = PTitleLine(title.GetContainerClass(i));
+ if (TLine) {
+ if (i>0) strcat ( S," " );
+ strcat_des ( S,TLine->Line );
+ }
+ }
+ } else {
+ cl = compound.Length();
+ if (cl>0) {
+ l = 0;
+ p = NULL;
+ B = true;
+ for (i=0;(i<cl) && B;i++) {
+ CLine = PCompound(compound.GetContainerClass(i));
+ if (CLine) {
+ if (!p) {
+ p = strstr(CLine->Line,"MOLECULE:");
+ if (p) l += strlen_des(&(p[9]))+5;
+ } else {
+ p = strstr(CLine->Line,"MOLECULE:");
+ if (p)
+ l += strlen_des(&(p[9]))+5;
+ else {
+ p = strchr(CLine->Line,':');
+ if (!p) {
+ l += strlen_des(CLine->Line)+5;
+ p = CLine->Line;
+ } else
+ B = false;
+ }
+ }
+ }
+ }
+ if (l>0) {
+ S = new char[l];
+ S[0] = char(0);
+ p = NULL;
+ B = true;
+ for (i=0;(i<cl) && B;i++) {
+ CLine = PCompound(compound.GetContainerClass(i));
+ if (CLine) {
+ if (!p) {
+ p = strstr(CLine->Line,"MOLECULE:");
+ if (p) strcat_des ( S,&(p[9]) );
+ } else {
+ p = strstr(CLine->Line,"MOLECULE:");
+ if (p)
+ strcat_des ( S,&(p[9]) );
+ else {
+ p = strchr(CLine->Line,':');
+ if (!p) {
+ strcat_des ( S,CLine->Line );
+ p = CLine->Line;
+ } else
+ B = false;
+ }
+ }
+ l = strlen(S)-1;
+ if (S[l]==';') S[l] = char(0);
+ }
+ }
+ } else {
+ l = 0;
+ for (i=0;i<cl;i++) {
+ CLine = PCompound(compound.GetContainerClass(i));
+ if (CLine) l += strlen_des(CLine->Line)+5;
+ }
+ S = new char[l];
+ S[0] = char(0);
+ for (i=0;i<cl;i++) {
+ CLine = PCompound(compound.GetContainerClass(i));
+ if (CLine) {
+ if (i>0) strcat ( S," " );
+ strcat_des ( S,CLine->Line );
+ }
+ }
+ }
+ } else if (classification)
+ CreateCopy ( S,classification );
+ else if (idCode[0])
+ CreateCopy ( S,idCode );
+ else
+ CreateCopy ( S,pstr("Not available") );
+ }
+
+ if (!S[0]) CreateCopy ( S,pstr("Not available") );
+
+ return S;
+
+ }
+
+ void Title::PDBASCIIDump ( io::RFile f ) {
+ char PDBString[100];
+ if (classification) {
+ MakePDBHeaderString ( PDBString );
+ f.WriteLine ( PDBString );
+ }
+ obsData .PDBASCIIDump ( f );
+ title .PDBASCIIDump ( f );
+ caveat .PDBASCIIDump ( f );
+ compound .PDBASCIIDump ( f );
+ source .PDBASCIIDump ( f );
+ keyWords .PDBASCIIDump ( f );
+ expData .PDBASCIIDump ( f );
+ mdlType .PDBASCIIDump ( f );
+ author .PDBASCIIDump ( f );
+ revData .PDBASCIIDump ( f );
+ supersede.PDBASCIIDump ( f );
+ journal .PDBASCIIDump ( f );
+ remark .PDBASCIIDump ( f );
+ }
+
+
+ void Title::MakeCIF ( mmcif::PData CIF ) {
+ char DateCIF[20];
+
+ if (idCode[0]) {
+ CIF->PutDataName ( idCode );
+ CIF->PutString ( idCode, CIFCAT_DATABASE,CIFTAG_ENTRY_ID );
+ CIF->PutString ( idCode, CIFCAT_DATABASE,CIFTAG_CODE_NDB );
+ CIF->PutString ( idCode, CIFCAT_DATABASE,CIFTAG_CODE_PDB );
+ } else {
+ CIF->PutDataName ( pstr("") );
+ CIF->PutString ( NULL, CIFCAT_DATABASE,CIFTAG_ENTRY_ID );
+ CIF->PutString ( NULL, CIFCAT_DATABASE,CIFTAG_CODE_NDB );
+ CIF->PutString ( NULL, CIFCAT_DATABASE,CIFTAG_CODE_PDB );
+ }
+ CIF->PutString ( classification, CIFCAT_STRUCT_KEYWORDS,
+ CIFTAG_NDB_KEYWORDS );
+ if (depDate[0]) {
+ Date11toCIF ( depDate,DateCIF );
+ CIF->PutString ( DateCIF,CIFCAT_DATABASE,CIFTAG_DATE_ORIGINAL );
+ } else
+ CIF->PutString ( NULL,CIFCAT_DATABASE,CIFTAG_DATE_ORIGINAL );
+
+ CIF->PutReal ( resolution,CIFCAT_REFINE,CIFTAG_LS_D_RES_HIGH,3 );
+
+ obsData .MakeCIF ( CIF );
+ title .MakeCIF ( CIF );
+ caveat .MakeCIF ( CIF );
+ compound .MakeCIF ( CIF );
+ source .MakeCIF ( CIF );
+ keyWords .MakeCIF ( CIF );
+ expData .MakeCIF ( CIF );
+ mdlType .MakeCIF ( CIF );
+ author .MakeCIF ( CIF );
+ revData .MakeCIF ( CIF );
+ supersede.MakeCIF ( CIF );
+ journal .MakeCIF ( CIF );
+ remark .MakeCIF ( CIF );
+
+ }
+
+ void Title::Copy ( PTitle TS ) {
+ int i;
+
+ FreeBiomolecules();
+
+ if (TS) {
+
+ CreateCopy ( classification,TS->classification );
+ strcpy ( depDate ,TS->depDate );
+ strcpy ( idCode ,TS->idCode );
+ resolution = TS->resolution;
+
+ obsData .Copy ( &(TS->obsData) );
+ title .Copy ( &(TS->title) );
+ caveat .Copy ( &(TS->caveat) );
+ compound .Copy ( &(TS->compound) );
+ source .Copy ( &(TS->source) );
+ keyWords .Copy ( &(TS->keyWords) );
+ expData .Copy ( &(TS->expData) );
+ mdlType .Copy ( &(TS->mdlType) );
+ author .Copy ( &(TS->author) );
+ revData .Copy ( &(TS->revData) );
+ supersede.Copy ( &(TS->supersede) );
+ journal .Copy ( &(TS->journal) );
+ remark .Copy ( &(TS->remark) );
+
+ nBiomolecules = TS->nBiomolecules;
+ if (nBiomolecules>0) {
+ biomolecule = new PBiomolecule[nBiomolecules];
+ for (i=0;i<nBiomolecules;i++)
+ if (TS->biomolecule[i]) {
+ biomolecule[i] = new Biomolecule();
+ biomolecule[i]->Copy ( TS->biomolecule[i] );
+ } else
+ biomolecule[i] = NULL;
+ }
+
+ } else {
+
+ if (classification) delete[] classification;
+ classification = NULL;
+ resolution = -2.0;
+ obsData .FreeContainer();
+ title .FreeContainer();
+ caveat .FreeContainer();
+ compound .FreeContainer();
+ source .FreeContainer();
+ keyWords .Delete ();
+ expData .FreeContainer();
+ mdlType .FreeContainer();
+ author .FreeContainer();
+ revData .FreeContainer();
+ supersede.FreeContainer();
+ journal .FreeContainer();
+ remark .FreeContainer();
+
+ }
+
+ }
+
+ void Title::TrimInput ( pstr PDBString ) {
+ if (col73) {
+ if (!strncasecmp(idCode,&(PDBString[72]),4))
+ PDBString[72] = char(0);
+ }
+ PadSpaces ( PDBString,80 );
+ }
+
+ void Title::write ( io::RFile f ) {
+ // writes header to PDB binary file
+ int i;
+ byte Version=3;
+
+ f.WriteByte ( &Version );
+
+ // Header data
+ f.CreateWrite ( classification );
+ f.WriteTerLine ( depDate,false );
+ f.WriteTerLine ( idCode ,false );
+ f.WriteReal ( &resolution );
+
+ obsData .write ( f ); // Obsoletion data
+ title .write ( f ); // Title
+ caveat .write ( f ); // Error data
+ compound .write ( f ); // Compound
+ source .write ( f ); // Source
+ keyWords .write ( f ); // Key words
+ expData .write ( f ); // Experimental data
+ mdlType .write ( f ); // Model descriptions
+ author .write ( f ); // Author data
+ revData .write ( f ); // Revision data
+ supersede.write ( f ); // Supersede records
+ journal .write ( f ); // Journal records
+ remark .write ( f ); // Remarks
+
+ f.WriteInt ( &nBiomolecules );
+ for (i=0;i<nBiomolecules;i++)
+ StreamWrite ( f,biomolecule[i] );
+
+ }
+
+ void Title::read ( io::RFile f ) {
+ // reads header from PDB binary file
+ int i;
+ byte Version;
+
+ f.ReadByte ( &Version );
+
+ // Header data
+ f.CreateRead ( classification );
+ f.ReadTerLine ( depDate,false );
+ f.ReadTerLine ( idCode ,false );
+ if (Version>1)
+ f.ReadReal ( &resolution );
+ else
+ resolution = -2.0;
+
+ obsData .read ( f ); // Obsoletion data
+ title .read ( f ); // Title
+ caveat .read ( f ); // Error data
+ compound .read ( f ); // Compound
+ source .read ( f ); // Source
+ keyWords .read ( f ); // Key words
+ expData .read ( f ); // Experimental data
+ if (Version>2)
+ mdlType.read ( f ); // Model descriptions
+ author .read ( f ); // Author data
+ revData .read ( f ); // Revision data
+ supersede.read ( f ); // Supersede records
+ journal .read ( f ); // Journal records
+ remark .read ( f ); // Remarks
+
+ FreeBiomolecules();
+ if (Version>1) {
+ f.ReadInt ( &nBiomolecules );
+ if (nBiomolecules>0) {
+ biomolecule = new PBiomolecule[nBiomolecules];
+ for (i=0;i<nBiomolecules;i++) {
+ biomolecule[i] = NULL;
+ StreamRead ( f,biomolecule[i] );
+ }
+ }
+ }
+
+ }
+
+ MakeStreamFunctions(Title)
+
+} // namespace mmdb
+
+
+// ===================================================================
+
+/*
+void TestHeader() {
+PTitle Hdr;
+char S[81],S1[81];
+
+ Hdr = new Title();
+
+ Hdr->SetHeader ( pstr("MUSCLE PROTEIN"),pstr("02-JUN-1993"),pstr("1MYS") );
+ Hdr->MakePDBHeaderString ( S );
+ printf ( "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890\n" );
+ printf ( S );
+ printf ( "\n" );
+
+ strcpy ( S,
+// 1234567890123456789012345678901234567890123456789012345678901234567890
+ "HEADER HYDROLASE (CARBOXYLIC ESTER) 07-APR-01 2PHI" );
+
+ Hdr->ConvertPDBString ( S );
+ Hdr->MakePDBHeaderString ( S1 );
+ printf ( "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890\n" );
+ printf ( S1 );
+ printf ( "\n" );
+
+ Hdr->SetHeader (
+ pstr("MUSCLE PROTEIN;**A VERY LONG TITLE TEST;**ARBITRARY LENGTH"),
+ pstr("02-JUN-1993"),pstr("1MYS") );
+ Hdr->MakePDBHeaderString ( S );
+ printf ( "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890\n" );
+ printf ( S );
+ printf ( "\n" );
+
+ delete Hdr;
+
+ printf ( " header deleted \n" );
+
+}
+
+void TestTitle() {
+// reads PDB title from file 'in.title'
+// and rewrites it into 'out.title' and 'abin.title'
+CFile f;
+char S[81];
+PTitle Title;
+
+ Title = new Title();
+
+ f.assign ( pstr("in.title"),true );
+ if (f.reset()) {
+ while (!f.FileEnd()) {
+ f.ReadLine ( S,sizeof(S) );
+ Title->ConvertPDBString ( S );
+ }
+ f.shut();
+ } else {
+ printf ( " Can't open input file 'in.title' \n" );
+ delete Title;
+ return;
+ }
+
+ f.assign ( pstr("out.title"),true );
+ if (f.rewrite()) {
+ Title->PDBASCIIDump ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open output file 'out.title' \n" );
+ delete Title;
+ return;
+ }
+
+
+
+ f.assign ( pstr("mmdb.title.bin"),false );
+ if (f.rewrite()) {
+ Title->write ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open binary file for writing.\n" );
+ delete Title;
+ return;
+ }
+
+ delete Title;
+ printf ( " Title deleted.\n" );
+
+ Title = new Title();
+ if (f.reset()) {
+ Title->read ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open binary file for reading.\n" );
+ delete Title;
+ return;
+ }
+
+ f.assign ( pstr("abin.title"),true );
+ if (f.rewrite()) {
+ Title->PDBASCIIDump ( f );
+ f.shut();
+ } else {
+ printf ( " Can't open output file 'abin.title' \n" );
+ }
+
+ delete Title;
+
+}
+
+
+*/
diff --git a/mmdb2/mmdb_title.h b/mmdb2/mmdb_title.h
new file mode 100644
index 0000000..1e00d38
--- /dev/null
+++ b/mmdb2/mmdb_title.h
@@ -0,0 +1,696 @@
+// $Id: mmdb_title.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_Title <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::TitleContainer (container of title classes)
+// ~~~~~~~~~ mmdb::ObsLine
+// mmdb::TitleLine
+// mmdb::Caveat
+// mmdb::Compound
+// mmdb::Source
+// mmdb::KeyWords
+// mmdb::ExpData
+// mmdb::MdlType
+// mmdb::Author
+// mmdb::RevData
+// mmdb::Supersede
+// mmdb::Journal
+// mmdb::Remark
+// mmdb::Biomolecule
+// mmdb::Title ( MMDB title section )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Title__
+#define __MMDB_Title__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_defs.h"
+#include "mmdb_utils.h"
+#include "mmdb_mmcif_.h"
+
+namespace mmdb {
+
+ // ====================== TitleContainer =======================
+
+ DefineClass(TitleContainer);
+ DefineStreamFunctions(TitleContainer);
+
+ class TitleContainer : public ClassContainer {
+
+ public :
+
+ TitleContainer () : ClassContainer() {}
+ TitleContainer ( io::RPStream Object )
+ : ClassContainer ( Object ) {}
+ ~TitleContainer() {}
+
+ PContainerClass MakeContainerClass ( int ClassID );
+
+ };
+
+
+ // ================== ObsLine ========================
+
+ DefineClass(ObsLine);
+ DefineStreamFunctions(ObsLine);
+
+ class ObsLine : public ContainerClass {
+
+ public :
+
+ Date repDate; // date of replacement
+ IDCode idCode; // ID code of replaced entry
+ IDCode rIdCode[8]; // ID codes of entries that replaced this one
+
+ ObsLine ();
+ ObsLine ( cpstr S );
+ ObsLine ( io::RPStream Object );
+ ~ObsLine();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_ObsLine; }
+
+ void Copy ( PContainerClass ObsLine );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitObsLine();
+
+ };
+
+
+ // ==================== TitleLine =====================
+
+ DefineClass(TitleLine);
+ DefineStreamFunctions(TitleLine);
+
+ class TitleLine : public ContString {
+
+ public :
+
+ TitleLine ();
+ TitleLine ( cpstr S );
+ TitleLine ( io::RPStream Object );
+ ~TitleLine();
+
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ void PDBASCIIDump ( pstr S, int N );
+ bool PDBASCIIDump1 ( io::RFile ) { return false; }
+ CLASS_ID GetClassID () { return ClassID_TitleLine; }
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitTitleLine();
+
+ };
+
+
+ // ==================== Caveat =====================
+
+ DefineClass(Caveat);
+ DefineStreamFunctions(Caveat);
+
+ class Caveat : public ContString {
+
+ public :
+
+ IDCode idCode; // ID code of the entry
+
+ Caveat ();
+ Caveat ( cpstr S );
+ Caveat ( io::RPStream Object );
+ ~Caveat();
+
+ void PDBASCIIDump ( pstr S, int N );
+ bool PDBASCIIDump1 ( io::RFile ) { return false; }
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+
+// virtual void GetCIF1 ( mmcif::PData CIF, ERROR_CODE & Signal,
+// int & pos );
+
+ CLASS_ID GetClassID () { return ClassID_CAVEAT; }
+
+ void Copy ( PContainerClass Caveat );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitCaveat();
+
+ };
+
+
+ // ==================== Compound =====================
+
+ DefineClass(Compound);
+ DefineStreamFunctions(Compound);
+
+ class Compound : public ContString {
+
+ public :
+
+ Compound ();
+ Compound ( cpstr S );
+ Compound ( io::RPStream Object );
+ ~Compound();
+
+ void PDBASCIIDump ( pstr S, int N );
+ bool PDBASCIIDump1 ( io::RFile ) { return false; }
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ CLASS_ID GetClassID () { return ClassID_Compound; }
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitCompound();
+
+ };
+
+
+ // ==================== Source =====================
+
+ DefineClass(Source);
+ DefineStreamFunctions(Source);
+
+ class Source : public ContString {
+
+ public :
+
+ Source ();
+ Source ( cpstr S );
+ Source ( io::RPStream Object );
+ ~Source();
+
+ void PDBASCIIDump ( pstr S, int N );
+ bool PDBASCIIDump1 ( io::RFile ) { return false; }
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ CLASS_ID GetClassID () { return ClassID_Source; }
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitSource();
+
+ };
+
+
+ // ==================== KeyWords =====================
+
+ DefineClass(KeyWords);
+ DefineStreamFunctions(KeyWords);
+
+ class KeyWords : public io::Stream {
+
+ public :
+ int nKeyWords; // number of key words
+ psvector KeyWord; // key word array
+
+ KeyWords ();
+ KeyWords ( cpstr S );
+ KeyWords ( io::RPStream Object );
+ ~KeyWords();
+
+ void Delete ();
+
+ void PDBASCIIDump ( io::RFile f );
+ void MakeCIF ( mmcif::PData CIF );
+
+ int ConvertPDBASCII ( cpstr S );
+ void GetCIF ( mmcif::PData CIF );
+
+ void Copy ( PKeyWords KeyWords );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ bool Cont;
+
+ void Init();
+
+ };
+
+
+ // ==================== ExpData =====================
+
+ DefineClass(ExpData);
+ DefineStreamFunctions(ExpData);
+
+ class ExpData : public ContString {
+
+ public :
+
+ ExpData ();
+ ExpData ( cpstr S );
+ ExpData ( io::RPStream Object );
+ ~ExpData();
+
+ void PDBASCIIDump ( pstr S, int N );
+ bool PDBASCIIDump1 ( io::RFile ) { return false; }
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ CLASS_ID GetClassID () { return ClassID_ExpData; }
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitExpData();
+
+ };
+
+
+ // ==================== MdlType =====================
+
+ DefineClass(MdlType);
+ DefineStreamFunctions(MdlType);
+
+ class MdlType : public ContString {
+
+ public :
+
+ MdlType ();
+ MdlType ( cpstr S );
+ MdlType ( io::RPStream Object );
+ ~MdlType();
+
+ void PDBASCIIDump ( pstr S, int N );
+ bool PDBASCIIDump1 ( io::RFile ) { return false; }
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ CLASS_ID GetClassID () { return ClassID_MdlType; }
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitMdlType();
+
+ };
+
+
+ // ==================== Author =====================
+
+ DefineClass(Author);
+ DefineStreamFunctions(Author);
+
+ class Author : public ContString {
+
+ public :
+
+ Author ();
+ Author ( cpstr S );
+ Author ( io::RPStream Object );
+ ~Author();
+
+ void PDBASCIIDump ( pstr S, int N );
+ bool PDBASCIIDump1 ( io::RFile ) { return false; }
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ CLASS_ID GetClassID () { return ClassID_Author; }
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitAuthor();
+
+ };
+
+
+ // ==================== RevData =====================
+
+ DefineClass(RevData);
+ DefineStreamFunctions(RevData);
+
+ enum REVDAT_WARNING {
+ REVDAT_WARN_MODNUM = 0x00000001,
+ REVDAT_WARN_MODTYPE = 0x00000002
+ };
+
+ class RevData : public ContainerClass {
+
+ public :
+ int modNum;
+ Date modDate;
+ char modId[13];
+ int modType;
+ RecName record[4];
+ word Warning;
+
+ RevData ();
+ RevData ( cpstr S );
+ RevData ( io::RPStream Object );
+ ~RevData();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_RevData; }
+
+ void Copy ( PContainerClass RevData );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitRevData();
+
+ };
+
+
+ // ================== Supersede ========================
+
+ DefineClass(Supersede);
+ DefineStreamFunctions(Supersede);
+
+ class Supersede : public ContainerClass {
+
+ public :
+ Date sprsdeDate; // date of supersede
+ IDCode idCode; // ID code of the entry
+ IDCode sIdCode[8]; // ID codes of superseded entries
+
+ Supersede ();
+ Supersede ( cpstr S );
+ Supersede ( io::RPStream Object );
+ ~Supersede();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_Supersede; }
+
+ void Copy ( PContainerClass Supersede );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitSupersede();
+
+ };
+
+
+ // ==================== Journal =====================
+
+ DefineClass(Journal);
+ DefineStreamFunctions(Journal);
+
+ class Journal : public ContString {
+
+ public :
+
+ Journal ();
+ Journal ( cpstr S );
+ Journal ( io::RPStream Object );
+ ~Journal();
+
+ void PDBASCIIDump ( pstr S, int N );
+ bool PDBASCIIDump1 ( io::RFile ) { return false; }
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ CLASS_ID GetClassID () { return ClassID_Journal; }
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitJournal();
+
+ };
+
+
+ // ==================== Remark =====================
+
+ DefineClass(Remark);
+ DefineStreamFunctions(Remark);
+
+ class Remark : public ContainerClass {
+
+ public :
+
+ int remarkNum; // remark id
+ pstr remark; // remark line
+
+ Remark ();
+ Remark ( cpstr S );
+ Remark ( io::RPStream Object );
+ ~Remark();
+
+ void PDBASCIIDump ( pstr S, int N );
+ void MakeCIF ( mmcif::PData CIF, int N );
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ ERROR_CODE GetCIF ( mmcif::PData CIF, int & n );
+ CLASS_ID GetClassID () { return ClassID_Remark; }
+
+ void Copy ( PContainerClass RemarkClass );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+
+ void InitRemark();
+
+ };
+
+ // ================= Biomolecule =====================
+
+ DefineClass(BMApply);
+ DefineStreamFunctions(BMApply);
+
+ class BMApply : public io::Stream {
+
+ public :
+ PChainID chain;
+ int nChains;
+ pmat44 tm;
+ int nMatrices;
+
+ BMApply ();
+ BMApply ( io::RPStream Object );
+ ~BMApply();
+
+ void FreeMemory();
+
+ int addChains ( int & i, RPRemark rem, RTitleContainer Remark );
+ int addMatrices ( int & i, RPRemark rem, RTitleContainer Remark );
+
+ void Copy ( PBMApply BMA ); // if BMA is NULL, then empties
+ // the class
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ void InitBMApply();
+
+ };
+
+
+ DefineClass(Biomolecule);
+ DefineStreamFunctions(Biomolecule);
+
+ class Biomolecule : public io::Stream {
+
+ public :
+ PPBMApply bmApply;
+ int nBMAs;
+
+ Biomolecule ();
+ Biomolecule ( io::RPStream Object );
+ ~Biomolecule();
+
+ void FreeMemory();
+
+ PBMApply addBMApply();
+
+ int Size();
+ bool checkComposition ( PChainID chID, ivector occ,
+ ivector wocc, int n );
+
+ void Copy ( PBiomolecule B ); // if B is NULL, then empties
+ // the class
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ void InitBiomolecule();
+
+ };
+
+ // ================= Title =======================
+
+ DefineClass(Title);
+ DefineStreamFunctions(Title);
+
+ class Title : public io::Stream {
+
+ friend class Model;
+ friend class Chain;
+ friend class Root;
+
+ public :
+
+ Title ();
+ Title ( io::RPStream Object );
+ ~Title();
+
+ void FreeMemory ( bool keepBiomolecules );
+
+ // Fills the PDB file header
+ void SetHeader ( cpstr Classification, // any length is Ok
+ cpstr DepDate, // DD-MMM-YYYY
+ cpstr ID_Code ); // not more than 11 chars
+
+ // Interprets the ASCII PDB line belonging to the title section
+ // and fills the corresponding fields.
+ // Returns zero if the line was converted, otherwise returns a
+ // non-negative value of Error_XXXX.
+ // PDBString must be not shorter than 81 characters.
+ ERROR_CODE ConvertPDBString ( pstr PDBString );
+
+ // MakePDBString() makes the ASCII PDB HEADER line from the
+ // class data. PDBString must be not shorter than 81 characters.
+ void MakePDBHeaderString ( pstr PDBString );
+
+ // GetStructureTitle() returns the contents of TITLE record
+ // unfolded into single line. If Title is missing, returns
+ // contents of COMPND(:MOLECULE). If COMPND is missing, returns
+ // HEADER. If Header is missing, returns PDB code. If no PDB
+ // code is there, returns "Not available".
+ pstr GetStructureTitle ( pstr & S );
+
+ PTitleContainer GetObsData () { return &obsData; }
+ PTitleContainer GetCaveat () { return &caveat; }
+ PTitleContainer GetCompound() { return &compound; }
+ PTitleContainer GetSource () { return &source; }
+ PKeyWords GetKeyWords() { return &keyWords; }
+ PTitleContainer GetExpData () { return &expData; }
+ PTitleContainer GetMdlType () { return &mdlType; }
+ PTitleContainer GetRemarks () { return &remark; }
+ PTitleContainer GetJournal () { return &journal; }
+
+ realtype GetResolution(); // -1.0 mean no resolution record in file
+
+ int ParseBiomolecules(); // returns the number of biomolecules,
+ // -2 for general format error
+ // -3 for errors in BIOMT records
+
+ int GetNofBiomolecules();
+ void GetBiomolecules ( PPBiomolecule & BM, int & nBMs );
+ PBiomolecule GetBiomolecule ( int bmNo ); // bmno=0,1,..
+ // returns NULL if bmNo is incorrect
+
+ void PDBASCIIDump ( io::RFile f );
+ void MakeCIF ( mmcif::PData CIF );
+
+ // GetCIF(..) returns the same code as ConvertPDBString(..)
+ // save for Error_WrongSection
+ ERROR_CODE GetCIF ( mmcif::PData CIF );
+
+ inline pstr GetIDCode() { return idCode; }
+ inline bool GetCol73 () { return col73; }
+ void TrimInput ( pstr PDBString );
+
+ void Copy ( PTitle TS ); // if TS is NULL, then empties
+ // the class
+
+ void write ( io::RFile f ); // writes header to PDB binary file
+ void read ( io::RFile f ); // reads header from PDB binary file
+
+ protected :
+
+ // Header data
+ pstr classification; // classification of the molecule
+ Date depDate; // deposition date DD-MMM-YYYY
+ IDCode idCode; // unique PDB identifier
+ realtype resolution; // resolution
+ bool col73; // True if columns 73-80 contain PDB ID
+
+ TitleContainer obsData; // obsoletion data
+ TitleContainer title; // title data
+ TitleContainer caveat; // error data
+ TitleContainer compound; // compound data
+ TitleContainer source; // source
+ KeyWords keyWords; // key words
+ TitleContainer expData; // experimental data
+ TitleContainer mdlType; // model desctiptions
+ TitleContainer author; // author data
+ TitleContainer revData; // revision data
+ TitleContainer supersede; // supersede records
+ TitleContainer journal; // journal records
+ TitleContainer remark; // remark records
+
+ PPBiomolecule biomolecule;
+ int nBiomolecules;
+
+ void Init();
+ void FreeBiomolecules();
+
+ PBiomolecule addBiomolecule();
+
+ };
+
+ extern void TestHeader();
+ extern void TestTitle (); // reads PDB title from file 'in.title'
+ // and rewrites it into 'out.title' and
+ // 'abin.title'
+
+} // namespace mmdb
+
+
+#endif
+
diff --git a/mmdb2/mmdb_uddata.cpp b/mmdb2/mmdb_uddata.cpp
new file mode 100644
index 0000000..1bfcc09
--- /dev/null
+++ b/mmdb2/mmdb_uddata.cpp
@@ -0,0 +1,534 @@
+// $Id: mmdb_uddata.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDBF_UDData <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Classes : mmdb::UDData ( user-defined data )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+
+#include "mmdb_uddata.h"
+
+namespace mmdb {
+
+ // ======================== UDRegister ==========================
+
+ #define nUDRTypes 5
+
+ UDRegister::UDRegister() : io::Stream() {
+ InitUDRegister();
+ }
+
+ UDRegister::UDRegister ( io::RPStream Object ) : io::Stream(Object) {
+ InitUDRegister();
+ }
+
+ UDRegister::~UDRegister() {
+ FreeUDRegister();
+ }
+
+ void UDRegister::InitUDRegister() {
+ int i;
+ for (i=0;i<nUDRTypes;i++) {
+ nIUDR[i] = 0;
+ nRUDR[i] = 0;
+ nSUDR[i] = 0;
+ IUDRegister[i] = NULL;
+ RUDRegister[i] = NULL;
+ SUDRegister[i] = NULL;
+ }
+ }
+
+ void UDRegister::FreeUDRegister() {
+ int i,j;
+
+ for (j=0;j<nUDRTypes;j++) {
+
+ if (IUDRegister[j]) {
+ for (i=0;i<nIUDR[j];i++)
+ if (IUDRegister[j][i]) delete[] IUDRegister[j][i];
+ delete[] IUDRegister[j];
+ IUDRegister[j] = NULL;
+ }
+ nIUDR[j] = 0;
+
+ if (RUDRegister[j]) {
+ for (i=0;i<nRUDR[j];i++)
+ if (RUDRegister[j][i]) delete[] RUDRegister[j][i];
+ delete[] RUDRegister[j];
+ RUDRegister[j] = NULL;
+ }
+ nRUDR[j] = 0;
+ if (SUDRegister[j]) {
+ for (i=0;i<nRUDR[j];i++)
+ if (SUDRegister[j][i]) delete[] SUDRegister[j][i];
+ delete[] SUDRegister[j];
+ SUDRegister[j] = NULL;
+ }
+ nSUDR[j] = 0;
+
+ }
+
+ }
+
+ int UDRegister::RegisterUDData ( psvector & UDRegister,
+ int & nUDR,
+ cpstr UDDataID ) {
+ psvector UDReg;
+ int i,UDDhandle,n;
+
+ n = -1;
+ UDDhandle = 0;
+ for (i=0;(i<nUDR) && (!UDDhandle);i++)
+ if (UDRegister[i]) {
+ if (!strcmp(UDDataID,UDRegister[i]))
+ UDDhandle = i+1;
+ } else
+ n = i;
+
+ if (!UDDhandle) {
+ if (n<0) {
+ UDReg = new pstr[nUDR+1];
+ for (i=0;i<nUDR;i++)
+ UDReg[i] = UDRegister[i];
+ UDReg[nUDR] = NULL;
+ if (UDRegister) delete[] UDRegister;
+ UDRegister = UDReg;
+ n = nUDR;
+ nUDR++;
+ }
+ CreateCopy ( UDRegister[n],UDDataID );
+ UDDhandle = n+1;
+ }
+
+ return UDDhandle;
+
+ }
+
+ static int UDRegisterFlag[nUDRTypes] = {
+ UDRF_ATOM,
+ UDRF_RESIDUE,
+ UDRF_CHAIN,
+ UDRF_MODEL,
+ UDRF_HIERARCHY
+ };
+
+
+ int UDRegister::RegisterUDInteger ( UDR_TYPE udr_type,
+ cpstr UDDataID ) {
+ if ((udr_type>=0) && (udr_type<nUDRTypes))
+ return RegisterUDData ( IUDRegister[udr_type],
+ nIUDR[udr_type],UDDataID ) |
+ UDRegisterFlag[udr_type];
+ else
+ return UDDATA_WrongUDRType;
+ }
+
+ int UDRegister::RegisterUDReal ( UDR_TYPE udr_type,
+ cpstr UDDataID ) {
+ if ((udr_type>=0) && (udr_type<nUDRTypes))
+ return RegisterUDData ( RUDRegister[udr_type],
+ nRUDR[udr_type],UDDataID ) |
+ UDRegisterFlag[udr_type];
+ else
+ return UDDATA_WrongUDRType;
+ }
+
+ int UDRegister::RegisterUDString ( UDR_TYPE udr_type,
+ cpstr UDDataID ) {
+ if ((udr_type>=0) && (udr_type<nUDRTypes))
+ return RegisterUDData ( SUDRegister[udr_type],
+ nSUDR[udr_type],UDDataID ) |
+ UDRegisterFlag[udr_type];
+ else
+ return UDDATA_WrongUDRType;
+ }
+
+ int UDRegister::GetUDDHandle ( UDR_TYPE udr_type,
+ cpstr UDDataID ) {
+ int i,UDDhandle;
+
+ if ((udr_type>=0) && (udr_type<nUDRTypes)) {
+
+ UDDhandle = 0;
+
+ for (i=0;(i<nIUDR[udr_type]) && (!UDDhandle);i++)
+ if (IUDRegister[udr_type][i]) {
+ if (!strcmp(UDDataID,IUDRegister[udr_type][i]))
+ UDDhandle = i+1;
+ }
+ for (i=0;(i<nRUDR[udr_type]) && (!UDDhandle);i++)
+ if (RUDRegister[udr_type][i]) {
+ if (!strcmp(UDDataID,RUDRegister[udr_type][i]))
+ UDDhandle = i+1;
+ }
+ for (i=0;(i<nSUDR[udr_type]) && (!UDDhandle);i++)
+ if (SUDRegister[udr_type][i]) {
+ if (!strcmp(UDDataID,SUDRegister[udr_type][i]))
+ UDDhandle = i+1;
+ }
+
+ if (UDDhandle) return UDDhandle | UDRegisterFlag[udr_type];
+ else return UDDhandle;
+
+ } else
+ return UDDATA_WrongUDRType;
+
+ }
+
+
+ void UDRegister::write ( io::RFile f ) {
+ int i,j;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ for (j=0;j<nUDRTypes;j++) {
+ f.WriteInt ( &nIUDR[j] );
+ for (i=0;i<nIUDR[j];i++)
+ f.CreateWrite ( IUDRegister[j][i] );
+ f.WriteInt ( &nRUDR[j] );
+ for (i=0;i<nRUDR[j];i++)
+ f.CreateWrite ( RUDRegister[j][i] );
+ f.WriteInt ( &nSUDR[j] );
+ for (i=0;i<nSUDR[j];i++)
+ f.CreateWrite ( SUDRegister[j][i] );
+ }
+ }
+
+ void UDRegister::read ( io::RFile f ) {
+ int i,j;
+ byte Version;
+ f.ReadByte ( &Version );
+ FreeUDRegister();
+ for (j=0;j<nUDRTypes;j++) {
+ f.ReadInt ( &nIUDR[j] );
+ if (nIUDR[j]>0) {
+ IUDRegister[j] = new pstr[nIUDR[j]];
+ for (i=0;i<nIUDR[j];i++) {
+ IUDRegister[j][i] = NULL;
+ f.CreateRead ( IUDRegister[j][i] );
+ }
+ }
+ f.ReadInt ( &nRUDR[j] );
+ if (nRUDR[j]>0) {
+ RUDRegister[j] = new pstr[nRUDR[j]];
+ for (i=0;i<nRUDR[j];i++) {
+ RUDRegister[j][i] = NULL;
+ f.CreateRead ( RUDRegister[j][i] );
+ }
+ }
+ f.ReadInt ( &nSUDR[j] );
+ if (nSUDR[j]>0) {
+ SUDRegister[j] = new pstr[nSUDR[j]];
+ for (i=0;i<nSUDR[j];i++) {
+ SUDRegister[j][i] = NULL;
+ f.CreateRead ( SUDRegister[j][i] );
+ }
+ }
+ }
+ }
+
+
+ MakeStreamFunctions(UDRegister)
+
+
+
+ // ========================== UDData ============================
+
+ UDData::UDData() : Mask() {
+ InitUDData();
+ }
+
+ UDData::UDData ( io::RPStream Object ) : Mask(Object) {
+ InitUDData();
+ }
+
+ UDData::~UDData() {
+ FreeUDDMemory();
+ }
+
+ void UDData::InitUDData() {
+ IUData = NULL;
+ RUData = NULL;
+ SUData = NULL;
+ }
+
+ void UDData::FreeUDDMemory() {
+ int i,l;
+ FreeVectorMemory ( IUData,0 );
+ FreeVectorMemory ( RUData,0 );
+ if (SUData) {
+ l = getNofSUData();
+ for (i=0;i<=l;i++)
+ if (SUData[i]) delete[] SUData[i];
+ delete[] SUData;
+ }
+ IUData = NULL;
+ RUData = NULL;
+ SUData = NULL;
+ }
+
+ int UDData::getNofIUData() {
+ if (!IUData) return 0;
+ return IUData[0];
+ }
+
+ int UDData::getNofRUData() {
+ if (!RUData) return 0;
+ return mround(RUData[0]);
+ }
+
+ int UDData::getNofSUData() {
+ if (!SUData) return 0;
+ if (!SUData[0]) return 0;
+ return (int(SUData[0][0]) << 24) +
+ (int(SUData[0][1]) << 16) +
+ (int(SUData[0][2]) << 8) +
+ int(SUData[0][3]);
+ }
+
+ void UDData::setNofSUData ( int newN ) {
+ if (!SUData) return;
+ if (!SUData[0]) return;
+ SUData[0][3] = byte( newN & 0x000000FF);
+ SUData[0][2] = byte((newN & 0x0000FF00) >> 8);
+ SUData[0][1] = byte((newN & 0x00FF0000) >> 16);
+ SUData[0][0] = byte((newN & 0xFF000000) >> 24);
+ }
+
+
+ int UDData::putUDData ( int UDDhandle, int iudd ) {
+ ivector IUD;
+ int i,l,udh;
+ udh = UDDhandle & UDRF_MASK;
+ if (udh<1) return UDDATA_WrongHandle;
+ l = getNofIUData();
+ if (udh>l) {
+ GetVectorMemory ( IUD,udh+1,0 );
+ IUD[0] = udh;
+ for (i=1;i<=l;i++)
+ IUD[i] = IUData[i];
+ for (i=l+1;i<udh;i++)
+ IUD[i] = MinInt4;
+ FreeVectorMemory ( IUData,0 );
+ IUData = IUD;
+ }
+ IUData[udh] = iudd;
+ return UDDATA_Ok;
+ }
+
+ int UDData::putUDData ( int UDDhandle, realtype rudd ) {
+ rvector RUD;
+ int i,l,udh;
+ udh = UDDhandle & UDRF_MASK;
+ if (udh<1) return UDDATA_WrongHandle;
+ l = getNofRUData();
+ if (udh>l) {
+ GetVectorMemory ( RUD,udh+1,0 );
+ RUD[0] = udh;
+ for (i=1;i<=l;i++)
+ RUD[i] = RUData[i];
+ for (i=l+1;i<udh;i++)
+ RUD[i] = -MaxReal;
+ FreeVectorMemory ( RUData,0 );
+ RUData = RUD;
+ }
+ RUData[udh] = rudd;
+ return UDDATA_Ok;
+ }
+
+ int UDData::putUDData ( int UDDhandle, cpstr sudd ) {
+ psvector SUD;
+ int i,l,udh;
+ udh = UDDhandle & UDRF_MASK;
+ if (udh<1) return UDDATA_WrongHandle;
+ l = getNofSUData();
+ if (udh>l) {
+ if (l>0) {
+ GetVectorMemory ( SUD,udh+1,0 );
+ for (i=0;i<=l;i++)
+ SUD[i] = SUData[i];
+ for (i=l+1;i<=udh;i++)
+ SUD[i] = NULL;
+ FreeVectorMemory ( SUData,0 );
+ SUData = SUD;
+ } else {
+ GetVectorMemory ( SUData,udh+1,0 );
+ SUData[0] = new char[4];
+ for (i=1;i<=udh;i++)
+ SUData[i] = NULL;
+ }
+ setNofSUData ( udh );
+ }
+ CreateCopy ( SUData[udh],sudd );
+ return UDDATA_Ok;
+ }
+
+ int UDData::getUDData ( int UDDhandle, int & iudd ) {
+ int l,udh;
+ iudd = 0;
+ udh = UDDhandle & UDRF_MASK;
+ if (udh<1) return UDDATA_WrongHandle;
+ l = getNofIUData();
+ if (udh>l) return UDDATA_NoData;
+ iudd = IUData[udh];
+ if (iudd==MinInt4) return UDDATA_NoData;
+ return UDDATA_Ok;
+ }
+
+ int UDData::getUDData ( int UDDhandle, realtype & rudd ) {
+ int l,udh;
+ rudd = 0.0;
+ udh = UDDhandle & UDRF_MASK;
+ if (udh<1) return UDDATA_WrongHandle;
+ l = getNofRUData();
+ if (udh>l) return UDDATA_NoData;
+ rudd = RUData[udh];
+ if (rudd==-MaxReal) return UDDATA_NoData;
+ return UDDATA_Ok;
+ }
+
+ int UDData::getUDData ( int UDDhandle, pstr sudd, int maxLen ) {
+ int l,udh;
+ sudd[0] = char(0);
+ udh = UDDhandle & UDRF_MASK;
+ if (udh<1) return UDDATA_WrongHandle;
+ l = getNofSUData();
+ if (udh>l) return UDDATA_NoData;
+ if (!SUData[udh]) return UDDATA_NoData;
+ strcpy_n0 ( sudd,SUData[udh],maxLen-1 );
+ return UDDATA_Ok;
+ }
+
+ pstr UDData::getUDData ( int UDDhandle, int * retcode ) {
+ int l,udh;
+ udh = UDDhandle & UDRF_MASK;
+ if (udh<1) {
+ if (retcode) *retcode = UDDATA_WrongHandle;
+ return NULL;
+ }
+ l = getNofSUData();
+ if (udh>l) {
+ if (retcode) *retcode = UDDATA_NoData;
+ return NULL;
+ }
+ if (!SUData[udh]) {
+ if (retcode) *retcode = UDDATA_NoData;
+ return NULL;
+ }
+ if (retcode) *retcode = UDDATA_Ok;
+ return SUData[udh];
+ }
+
+ int UDData::getUDData ( int UDDhandle, pstr & sudd ) {
+ int l,udh;
+ udh = UDDhandle & UDRF_MASK;
+ if (udh<1) {
+ if (sudd) {
+ delete[] sudd;
+ sudd = NULL;
+ }
+ return UDDATA_WrongHandle;
+ }
+ l = getNofSUData();
+ if (udh>l) {
+ if (sudd) {
+ delete[] sudd;
+ sudd = NULL;
+ }
+ return UDDATA_NoData;
+ }
+ if (!SUData[udh]) {
+ if (sudd) {
+ delete[] sudd;
+ sudd = NULL;
+ }
+ return UDDATA_NoData;
+ }
+ CreateCopy ( sudd,SUData[udh] );
+ return UDDATA_Ok;
+ }
+
+
+ void UDData::write ( io::RFile f ) {
+ int i,l;
+ byte Version=1;
+
+ f.WriteByte ( &Version );
+
+ Mask::write ( f );
+
+ if (IUData) l = IUData[0];
+ else l = -1;
+ f.WriteVector ( IUData,l+1,0 );
+ if (RUData) l = mround(RUData[0]);
+ else l = -1;
+ f.WriteVector ( RUData,l+1,0 );
+ l = getNofSUData();
+ f.WriteInt ( &l );
+ for (i=1;i<=l;i++)
+ f.CreateWrite ( SUData[i] );
+ }
+
+ void UDData::read ( io::RFile f ) {
+ int i,l;
+ byte Version;
+
+ f.ReadByte ( &Version );
+
+ FreeUDDMemory();
+
+ Mask::read ( f );
+
+ f.CreateReadVector ( IUData,0 );
+ f.CreateReadVector ( RUData,0 );
+ f.ReadInt ( &l );
+ if (l>0) {
+ SUData = new pstr[l+1];
+ SUData[0] = new char[4];
+ setNofSUData ( l );
+ for (i=1;i<=l;i++) {
+ SUData[i] = NULL;
+ f.CreateRead ( SUData[i] );
+ }
+ }
+ }
+
+
+ MakeStreamFunctions(UDData)
+
+} // namespace mmdb
+
diff --git a/mmdb2/mmdb_uddata.h b/mmdb2/mmdb_uddata.h
new file mode 100644
index 0000000..c591891
--- /dev/null
+++ b/mmdb2/mmdb_uddata.h
@@ -0,0 +1,154 @@
+// $Id: mmdb_uddata.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDBF_UDData <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Classes : mmdb::UDData ( user-defined data )
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_UDData__
+#define __MMDB_UDData__
+
+#include "mmdb_mask.h"
+
+namespace mmdb {
+
+ // ======================= UDRegister =========================
+
+ enum UDR_TYPE {
+ UDR_ATOM = 0,
+ UDR_RESIDUE = 1,
+ UDR_CHAIN = 2,
+ UDR_MODEL = 3,
+ UDR_HIERARCHY = 4
+ };
+
+ enum UDD_FLAG {
+ UDRF_ATOM = 0x01000000,
+ UDRF_RESIDUE = 0x02000000,
+ UDRF_CHAIN = 0x04000000,
+ UDRF_MODEL = 0x08000000,
+ UDRF_HIERARCHY = 0x10000000,
+ UDRF_MASK = 0x00FFFFFF
+ };
+
+ DefineClass(UDRegister);
+ DefineStreamFunctions(UDRegister);
+
+ class UDRegister : public io::Stream {
+
+ public :
+
+ UDRegister ();
+ UDRegister ( io::RPStream Object );
+ ~UDRegister();
+
+ int RegisterUDInteger ( UDR_TYPE udr_type, cpstr UDDataID );
+ int RegisterUDReal ( UDR_TYPE udr_type, cpstr UDDataID );
+ int RegisterUDString ( UDR_TYPE udr_type, cpstr UDDataID );
+ int GetUDDHandle ( UDR_TYPE udr_type, cpstr UDDataID );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ int nIUDR[5],nRUDR[5],nSUDR[5];
+ psvector IUDRegister[5];
+ psvector RUDRegister[5];
+ psvector SUDRegister[5];
+
+ void InitUDRegister ();
+ void FreeUDRegister ();
+ int RegisterUDData ( psvector & UDRegister,
+ int & nUDR,
+ cpstr UDDataID );
+
+ };
+
+
+ // ========================== UDData ===========================
+
+ enum UDDATA_RC {
+ UDDATA_Ok = 0,
+ UDDATA_WrongHandle = -1,
+ UDDATA_WrongUDRType = -2,
+ UDDATA_NoData = -3
+ };
+
+ DefineClass(UDData);
+ DefineStreamFunctions(UDData);
+
+ class UDData : public Mask {
+
+ friend class SelManager;
+
+ public :
+
+ UDData ();
+ UDData ( io::RPStream Object );
+ ~UDData();
+
+ protected :
+ ivector IUData;
+ rvector RUData;
+ psvector SUData;
+
+ void InitUDData ();
+ void FreeUDDMemory();
+ int getNofIUData ();
+ int getNofRUData ();
+ int getNofSUData ();
+ void setNofSUData ( int newN );
+
+ int putUDData ( int UDDhandle, int iudd );
+ int putUDData ( int UDDhandle, realtype rudd );
+ int putUDData ( int UDDhandle, cpstr sudd );
+
+ int getUDData ( int UDDhandle, int & iudd );
+ int getUDData ( int UDDhandle, realtype & rudd );
+ int getUDData ( int UDDhandle, pstr sudd, int maxLen );
+ pstr getUDData ( int UDDhandle, int * retcode=NULL );
+ int getUDData ( int UDDhandle, pstr & sudd );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ };
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_utils.cpp b/mmdb2/mmdb_utils.cpp
new file mode 100644
index 0000000..a39f79b
--- /dev/null
+++ b/mmdb2/mmdb_utils.cpp
@@ -0,0 +1,1994 @@
+// $Id: mmdb_utils.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDBF_Utils <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Classes : mmdb::ContainerClass ( containered class template )
+// ~~~~~~~~~ mmdb::ContString ( containered string )
+// mmdb::ClassContainer ( container of classes )
+// mmdb::AtomPath ( atom path ID )
+// mmdb::QuickSort ( quick sort of integers )
+//
+// **** Functions : Date9to11 ( DD-MMM-YY -> DD-MMM-YYYY )
+// ~~~~~~~~~~~ Date11to9 ( DD-MMM-YYYY -> DD-MMM-YY )
+// Date9toCIF ( DD-MMM-YY -> YYYY-MM-DD )
+// Date11toCIF( DD-MMM-YYYY -> YYYY-MM-DD )
+// DateCIFto9 ( YYYY-MM-DD -> DD-MMM-YY )
+// DateCIFto11( YYYY-MM-DD -> DD-MMM-YYYY )
+// GetInteger ( reads integer from a string )
+// GetReal ( reads real from a string )
+// GetIntIns ( reads integer and insert code )
+// PutInteger ( writes integer into a string )
+// PutRealF ( writes real in F-form into a string )
+// PutIntIns ( writes integer and insert code )
+// CIFGetInteger ( reads and deletes int from CIF )
+// CIFGetReal ( reads and deletes real from CIF )
+// CIFGetString ( reads and deletes string from CIF)
+// CIFGetInteger1 (reads and del-s int from CIF loop)
+// CIFGetReal1 (reads and del-s int from CIF loop)
+// Mat4Inverse ( inversion of 4x4 matrices )
+// GetErrorDescription (ascii line to an Error_XXXXX)
+// ParseAtomID ( parses atom ID line )
+// ParseResID ( parses residue ID line )
+// ParseAtomPath ( parses full atom path )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "mmdb_utils.h"
+#include "hybrid_36.h"
+
+namespace mmdb {
+
+ // ====================== Date functions =======================
+
+ static cpstr Month[12] = {
+ "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
+ "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
+ };
+
+ static cpstr nMonth[12] = {
+ "01", "02", "03", "04", "05", "06",
+ "07", "08", "09", "10", "11", "12"
+ };
+
+ void Date9to11 ( cpstr Date9, pstr Date11 ) {
+ // converts DD-MMM-YY to DD-MMM-YYYY
+ int i;
+ i = 0;
+ while ((i<12) && (strncmp(Month[i],&(Date9[3]),3))) i++;
+ if (i<12) { // DD-MMM-YY -> DD-MMM-YYYY
+ strncpy ( Date11,Date9,7 );
+ if (Date9[7]!='0') strncpy ( &(Date11[7]),"19",2 );
+ else strncpy ( &(Date11[7]),"20",2 );
+ strncpy ( &(Date11[9]),&(Date9[7]),2 );
+ Date11[2] = '-';
+ Date11[6] = '-';
+ Date11[11] = char(0);
+ } else { // DD-MM-YY -> DD-MMM-YYYY
+ strncpy ( Date11,Date9,3 );
+ i = 0;
+ while ((i<12) && (strncmp(nMonth[i],&(Date9[3]),2))) i++;
+ if (i<12) {
+ strncpy ( &(Date11[3]),Month[i],3 );
+ if (Date9[6]!='0') strncpy ( &(Date11[7]),"19",2 );
+ else strncpy ( &(Date11[7]),"20",2 );
+ strncpy ( &(Date11[9]),&(Date9[6]),2 );
+ Date11[2] = '-';
+ Date11[6] = '-';
+ Date11[11] = char(0);
+ } else
+ strcpy ( Date11," " );
+ }
+ }
+
+ void Date11to9 ( cpstr Date11, pstr Date9 ) {
+ // converts DD-MMM-YYYY to DD-MMM-YY
+ int i;
+ i = 0;
+ while ((i<12) && (strncmp(Month[i],&(Date11[3]),3))) i++;
+ if (i<12) { // DD-MMM-YYYY -> DD-MMM-YY
+ strncpy ( Date9,Date11,7 );
+ strncpy ( &(Date9[7]),&(Date11[9]),2 );
+ Date9[2] = '-';
+ Date9[6] = '-';
+ } else { // DD-MM-YYYY -> DD-MMM-YY
+ strncpy ( Date9,Date11,3 );
+ i = 0;
+ while ((i<12) && (strncmp(nMonth[i],&(Date11[3]),2))) i++;
+ if (i<12) {
+ strncpy ( &(Date9[3]),Month[i],3 );
+ strncpy ( &(Date9[7]),&(Date11[8]),2 );
+ Date9[2] = '-';
+ Date9[6] = '-';
+ } else
+ strcpy ( Date9," " );
+ }
+ }
+
+ void Date9toCIF ( cpstr Date9, pstr DateCIF ) {
+ // DD-MMM-YY -> YYYY-MM-DD )
+ int i;
+ i = 0;
+ while ((i<12) && (strncmp(Month[i],&(Date9[3]),3))) i++;
+ if (i<12) { // DD-MMM-YY -> YYYY-MM-DD
+ if (Date9[7]!='0') strcpy ( DateCIF,"19" );
+ else strcpy ( DateCIF,"20" );
+ strncpy ( &(DateCIF[2]),&(Date9[7]),2 );
+ strncpy ( &(DateCIF[5]),nMonth[i],2 );
+ } else { // DD-MM-YY -> YYYY-MM-DD
+ if (Date9[6]!='0') strcpy ( DateCIF,"19" );
+ else strcpy ( DateCIF,"20" );
+ strncpy ( &(DateCIF[2]),&(Date9[6]),2 );
+ strncpy ( &(DateCIF[5]),&(Date9[3]),2 );
+ }
+ DateCIF[4] = '-';
+ DateCIF[7] = '-';
+ strncpy ( &(DateCIF[8]),Date9,2 );
+ DateCIF[10] = char(0);
+ }
+
+ void Date11toCIF ( cpstr Date11, pstr DateCIF ) {
+ // DD-MMM-YYYY -> YYYY-MM-DD
+ int i;
+ i = 0;
+ while ((i<12) && (strncmp(Month[i],&(Date11[3]),3))) i++;
+ if (i<12) {
+ strncpy ( DateCIF,&(Date11[7]),4 );
+ strncpy ( &(DateCIF[5]),nMonth[i],2 );
+ } else {
+ strncpy ( DateCIF,&(Date11[6]),4 );
+ strncpy ( &(DateCIF[5]),&(Date11[3]),2 );
+ }
+ DateCIF[4] = '-';
+ DateCIF[7] = '-';
+ strncpy ( &(DateCIF[8]),Date11,2 );
+ DateCIF[10] = char(0);
+ }
+
+ void DateCIFto9 ( cpstr DateCIF, pstr Date9 ) {
+ // YYYY-MM-DD -> DD-MMM-YY
+ int i;
+ strncpy ( Date9,&(DateCIF[8]),2 );
+ Date9[2] = '-';
+ i = 0;
+ while ((i<12) && (strncmp(nMonth[i],&(DateCIF[5]),2))) i++;
+ if (i<12) strncpy ( &(Date9[3]),Month[i],3 );
+ else {
+ strncpy ( &(Date9[3]),&(DateCIF[5]),2 );
+ Date9[5] = 'X';
+ }
+ Date9[6] = '-';
+ strncpy ( &(Date9[7]),&(DateCIF[2]),2 );
+ // DateCIF[9] = char(0);
+ }
+
+ void DateCIFto11 ( cpstr DateCIF, pstr Date11 ) {
+ // YYYY-MM-DD -> DD-MMM-YYYY
+ int i;
+ strncpy ( Date11,&(DateCIF[8]),2 );
+ Date11[2] = '-';
+ i = 0;
+ while ((i<12) && (strncmp(nMonth[i],&(DateCIF[5]),2))) i++;
+ if (i<12) strncpy ( &(Date11[3]),Month[i],3 );
+ else {
+ strncpy ( &(Date11[3]),&(DateCIF[5]),2 );
+ Date11[5] = 'X';
+ }
+ Date11[6] = '-';
+ strncpy ( &(Date11[7]),DateCIF,4 );
+ // DateCIF[11] = char(0);
+ }
+
+
+ // =============== Format functions ===================
+
+ bool GetInteger ( int & N, cpstr S, int M ) {
+ // Returns true if S contains an integer number in its
+ // first M characters. This number is returned in N.
+ // The return is false if no integer number may be
+ // recognized. In this case, N is assigned MinInt4 value.
+ pstr endptr;
+ char L[50];
+ strncpy ( L,S,M );
+ L[M] = char(0);
+ N = mround(strtod(L,&endptr));
+ if ((N==0) && (endptr==L)) {
+ N = MinInt4; // no number
+ return false;
+ } else
+ return true;
+ }
+
+ bool GetReal ( realtype & R, cpstr S, int M ) {
+ // Returns true if S contains a real number in its
+ // first M characters. This number is returned in R.
+ // The return is false if no real number may be
+ // recognized. In this case, R is assigned -MaxReal value.
+ pstr endptr;
+ char L[50];
+ strncpy ( L,S,M );
+ L[M] = char(0);
+ R = strtod(L,&endptr);
+ if ((R==0.0) && (endptr==L)) {
+ R = -MaxReal; // no number
+ return false;
+ } else
+ return true;
+ }
+
+ bool GetIntIns ( int & N, pstr ins, cpstr S, int M ) {
+ // Returns true if S contains an integer number in its
+ // first M characters. This number is returned in N. In addition
+ // to that, GetIntIns() retrieves the insertion code which may
+ // follow the integer and returns it in "ins" (1 character +
+ // terminating 0).
+ // The return is false if no integer number may be
+ // recognized. In this case, N is assigned MinInt4 value,
+ // "ins" just returns (M+1)th symbol of S (+terminating 0).
+ pstr endptr;
+ char L[50];
+
+ if (S[M]!=' ') {
+ ins[0] = S[M];
+ ins[1] = char(0);
+ } else
+ ins[0] = char(0);
+
+ strncpy ( L,S,M );
+ L[M] = char(0);
+ if ((M==4) && ((S[0]>='A') || ((S[0]=='-') && (S[1]>='A'))))
+ hy36decode ( M,L,M,&N);
+ else {
+ endptr = NULL;
+ N = mround(strtod(L,&endptr));
+ if ((N==0) && (endptr==L)) {
+ N = MinInt4; // no number
+ return false;
+ }
+ }
+
+ return true;
+
+ }
+
+ void PutInteger ( pstr S, int N, int M ) {
+ // Integer N is converted into ASCII string of length M
+ // and pasted onto first M characters of string S. No
+ // terminating zero is added.
+ // If N is set to MinInt4, then first M characters of
+ // string S are set to the space character.
+ char L[50];
+ int i;
+ if (N==MinInt4)
+ for (i=0;i<M;i++)
+ S[i] = ' ';
+ else {
+ sprintf ( L,"%*i",M,N );
+ strncpy ( S,L,M );
+ }
+ }
+
+ void PutRealF ( pstr S, realtype R, int M, int L ) {
+ // Real R is converted into ASCII string of length M
+ // and pasted onto first M characters of string S. No
+ // terminating zero is added. The conversion is done
+ // according to fixed format FM.L
+ // If R is set to -MaxReal, then first M characters of
+ // string S are set to the space character.
+ char N[50];
+ int i;
+ if (R==-MaxReal)
+ for (i=0;i<M;i++)
+ S[i] = ' ';
+ else {
+ sprintf ( N,"%*.*f",M,L,R );
+ strncpy ( S,N,M );
+ }
+ }
+
+ ERROR_CODE CIFGetIntegerD ( int & I, mmcif::PLoop Loop, cpstr Tag,
+ int defValue ) {
+ int Signal;
+ ERROR_CODE RC;
+ Signal = 0;
+ RC = CIFGetInteger ( I,Loop,Tag,Signal );
+ if (RC)
+ I = defValue;
+ return RC;
+ }
+
+ ERROR_CODE CIFGetInteger ( int & I, mmcif::PLoop Loop, cpstr Tag,
+ int & Signal ) {
+ pstr F;
+ int RC;
+ RC = Loop->GetInteger ( I,Tag,Signal,true );
+ if (RC==mmcif::CIFRC_WrongFormat) {
+ F = Loop->GetString ( Tag,Signal,RC );
+ if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+ Loop->GetCategoryName(),Tag,Signal,F );
+ else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+ Loop->GetCategoryName(),Tag,Signal );
+ Signal = -Error_UnrecognizedInteger-1;
+ return Error_UnrecognizedInteger;
+ }
+ if (RC==mmcif::CIFRC_WrongIndex) {
+ Signal = -1;
+ return Error_NoData;
+ }
+ if (RC) {
+ F = Loop->GetString ( Tag,Signal,RC );
+ if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+ Loop->GetCategoryName(),Tag,Signal,F );
+ else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+ Loop->GetCategoryName(),Tag,Signal );
+ Signal = -Error_NoData-1;
+ return Error_NoData;
+ }
+ return Error_NoError;
+ }
+
+
+ ERROR_CODE CIFGetInteger1 ( int & I, mmcif::PLoop Loop, cpstr Tag,
+ int nrow ) {
+ pstr F;
+ int RC;
+ RC = Loop->GetInteger ( I,Tag,nrow,true );
+ if (RC==mmcif::CIFRC_WrongFormat) {
+ F = Loop->GetString ( Tag,nrow,RC );
+ if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+ Loop->GetCategoryName(),Tag,nrow,F );
+ else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+ Loop->GetCategoryName(),Tag,nrow );
+ return Error_UnrecognizedInteger;
+ }
+ if (RC==mmcif::CIFRC_WrongIndex)
+ return Error_NoData;
+ if (RC) {
+ F = Loop->GetString ( Tag,nrow,RC );
+ if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+ Loop->GetCategoryName(),Tag,nrow,F );
+ else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+ Loop->GetCategoryName(),Tag,nrow );
+ return Error_NoData;
+ }
+ return Error_NoError;
+ }
+
+
+ ERROR_CODE CIFGetReal ( realtype & R, mmcif::PLoop Loop, cpstr Tag,
+ int & Signal ) {
+ pstr F;
+ int RC;
+ RC = Loop->GetReal ( R,Tag,Signal,true );
+ if (RC==mmcif::CIFRC_WrongFormat) {
+ F = Loop->GetString ( Tag,Signal,RC );
+ if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+ Loop->GetCategoryName(),Tag,Signal,F );
+ else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+ Loop->GetCategoryName(),Tag,Signal );
+ Signal = -Error_UnrecognizedReal-1;
+ return Error_UnrecognizedReal;
+ }
+ if (RC==mmcif::CIFRC_WrongIndex) {
+ Signal = -1;
+ return Error_NoData;
+ }
+ if (RC) {
+ F = Loop->GetString ( Tag,Signal,RC );
+ if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+ Loop->GetCategoryName(),Tag,Signal,F );
+ else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+ Loop->GetCategoryName(),Tag,Signal );
+ Signal = -Error_NoData-1;
+ return Error_NoData;
+ }
+ return Error_NoError;
+ }
+
+
+ ERROR_CODE CIFGetReal1 ( realtype & R, mmcif::PLoop Loop, cpstr Tag,
+ int nrow ) {
+ pstr F;
+ int RC;
+ RC = Loop->GetReal ( R,Tag,nrow,true );
+ if (RC==mmcif::CIFRC_WrongFormat) {
+ F = Loop->GetString ( Tag,nrow,RC );
+ if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+ Loop->GetCategoryName(),Tag,nrow,F );
+ else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+ Loop->GetCategoryName(),Tag,nrow );
+ return Error_UnrecognizedReal;
+ }
+ if (RC==mmcif::CIFRC_WrongIndex)
+ return Error_NoData;
+ if (RC) {
+ F = Loop->GetString ( Tag,nrow,RC );
+ if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+ Loop->GetCategoryName(),Tag,nrow,F );
+ else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+ Loop->GetCategoryName(),Tag,nrow );
+ return Error_NoData;
+ }
+ return Error_NoError;
+ }
+
+
+ ERROR_CODE CIFGetString ( pstr S, mmcif::PLoop Loop, cpstr Tag,
+ int row, int SLen, cpstr DefS ) {
+ pstr F;
+ int RC;
+ F = Loop->GetString ( Tag,row,RC );
+ if ((!RC) && F) {
+ strncpy ( S,F,SLen-1 );
+ Loop->DeleteField ( Tag,row );
+ return Error_NoError;
+ } else {
+ strcpy ( S,DefS );
+ return Error_EmptyCIFLoop;
+ }
+ }
+
+
+ ERROR_CODE CIFGetInteger ( int & I, mmcif::PStruct Struct, cpstr Tag,
+ bool Remove ) {
+ pstr F;
+ int RC;
+ RC = Struct->GetInteger ( I,Tag,Remove );
+ if (RC==mmcif::CIFRC_WrongFormat) {
+ F = Struct->GetString ( Tag,RC );
+ if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
+ Struct->GetCategoryName(),Tag,F );
+ else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
+ Struct->GetCategoryName(),Tag );
+ return Error_UnrecognizedInteger;
+ }
+ if (RC) {
+ F = Struct->GetString ( Tag,RC );
+ if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
+ Struct->GetCategoryName(),Tag,F );
+ else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
+ Struct->GetCategoryName(),Tag );
+ return Error_NoData;
+ }
+ return Error_NoError;
+ }
+
+ ERROR_CODE CIFGetReal ( realtype & R, mmcif::PStruct Struct, cpstr Tag,
+ bool Remove ) {
+ pstr F;
+ int RC;
+ RC = Struct->GetReal ( R,Tag,Remove );
+ if (RC==mmcif::CIFRC_WrongFormat) {
+ F = Struct->GetString ( Tag,RC );
+ if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
+ Struct->GetCategoryName(),Tag,F );
+ else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
+ Struct->GetCategoryName(),Tag );
+ return Error_UnrecognizedReal;
+ }
+ if (RC) {
+ F = Struct->GetString ( Tag,RC );
+ if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
+ Struct->GetCategoryName(),Tag,F );
+ else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
+ Struct->GetCategoryName(),Tag );
+ return Error_NoData;
+ }
+ return Error_NoError;
+ }
+
+ ERROR_CODE CIFGetString ( pstr S, mmcif::PStruct Struct, cpstr Tag,
+ int SLen, cpstr DefS, bool Remove ) {
+ pstr F;
+ int RC;
+ F = Struct->GetString ( Tag,RC );
+ if ((!RC) && F) {
+ strcpy_n0 ( S,F,SLen-1 );
+ if (Remove) Struct->DeleteField ( Tag );
+ return Error_NoError;
+ } else {
+ strcpy ( S,DefS );
+ return Error_EmptyCIFStruct;
+ }
+ }
+
+
+ void PutIntIns ( pstr S, int N, int M, cpstr ins ) {
+ // Integer N is converted into ASCII string of length M
+ // and pasted onto first M characters of string S. No
+ // terminating zero is added. The insert code ins is put
+ // immediately after the integer.
+ // If N is set to MinInt4, then first M+1 characters of
+ // string S are set to space, and no insert code are
+ // appended.
+ char L[50];
+ int i;
+
+ if (N==MinInt4) {
+ for (i=0;i<=M;i++)
+ S[i] = ' ';
+ } else {
+ if ((M!=4) || ((N>=-999) && (N<=9999)))
+ sprintf ( L,"%*i",M,N );
+ else hy36encode ( M,N,L );
+ strcpy_n1 ( S,L,M );
+ if (ins[0]) S[M] = ins[0];
+ }
+
+ }
+
+
+ void Mat4Inverse ( mat44 & A, mat44 & AI ) {
+ // *** FORMER RBRINV(A,AI) ***
+ // Function to invert 4*4 matrices (AI=A^{-1})
+ mat44 c;
+ mat33 x;
+ realtype s,s1;
+ int ii,jj,i,i1,j,j1;
+
+ // ---- Get cofactors of 'a' in array 'c'
+
+ s1 = 1.0;
+ for (ii=0;ii<4;ii++) {
+ s = s1;
+ for (jj=0;jj<4;jj++) {
+ i = -1;
+ for (i1=0;i1<4;i1++)
+ if (i1!=ii) {
+ i++;
+ j = -1;
+ for (j1=0;j1<4;j1++)
+ if (j1!=jj) {
+ j++;
+ x[i][j] = A[i1][j1];
+ }
+ }
+ c[ii][jj] = s*(x[0][0]*(x[1][1]*x[2][2]-x[1][2]*x[2][1]) +
+ x[0][1]*(x[1][2]*x[2][0]-x[1][0]*x[2][2]) +
+ x[0][2]*(x[1][0]*x[2][1]-x[1][1]*x[2][0]));
+ s = -s;
+ }
+ s1 = -s1;
+ }
+
+ // ---- Calculate determinant
+
+ s = 0.0;
+ for (i=0;i<4;i++)
+ s += A[i][0]*c[i][0];
+
+ // ---- Get inverse matrix
+
+ if (s!=0.0)
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++)
+ AI[i][j] = c[j][i]/s;
+
+ }
+
+ realtype Mat3Inverse ( mat33 & A, mat33 & AI ) {
+ mat33 c,x;
+ realtype s;
+ int ii,jj,i,i1,j,j1;
+
+ // Get cofactors of 'a' in array 'c'
+
+ s = 1.0;
+ for (ii=0;ii<3;ii++)
+ for (jj=0;jj<3;jj++) {
+ i = -1;
+ for (i1=0;i1<3;i1++)
+ if (i1!=ii) {
+ i++;
+ j = -1;
+ for (j1=0;j1<3;j1++)
+ if (j1!=jj) {
+ j++;
+ x[i][j] = A[i1][j1];
+ }
+ }
+ c[ii][jj] = s*(x[0][0]*x[1][1]-x[0][1]*x[1][0]);
+ s = -s;
+ }
+
+ // Calculate determinant
+
+ s = 0.0;
+ for (i=0;i<3;i++)
+ s += A[i][0]*c[i][0];
+
+ // Get inverse matrix
+
+ if (s!=0.0)
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++)
+ AI[i][j] = c[j][i]/s;
+
+ return s;
+
+ }
+
+ void Mat4Mult ( mat44 & A, mat44 & B, mat44 & C ) {
+ // Calculates A=B*C
+ int i,j,k;
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++) {
+ A[i][j] = 0.0;
+ for (k=0;k<4;k++)
+ A[i][j] += B[i][k]*C[k][j];
+ }
+ }
+
+ void Mat4Div1 ( mat44 & A, mat44 & B, mat44 & C ) {
+ // Calculates A=B^{-1}*C
+ mat44 B1;
+ int i,j,k;
+ B1[0][0] = 1.0; // in order to supress warnings from some
+ // stupid compilers
+ Mat4Inverse ( B,B1 );
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++) {
+ A[i][j] = 0.0;
+ for (k=0;k<4;k++)
+ A[i][j] += B1[i][k]*C[k][j];
+ }
+ }
+
+ void Mat4Div2 ( mat44 & A, mat44 & B, mat44 & C ) {
+ // Calculates A=B*C^{-1}
+ mat44 C1;
+ int i,j,k;
+ C1[0][0] = 1.0; // in order to supress warnings from some
+ // stupid compilers
+ Mat4Inverse ( C,C1 );
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++) {
+ A[i][j] = 0.0;
+ for (k=0;k<4;k++)
+ A[i][j] += B[i][k]*C1[k][j];
+ }
+ }
+
+ void Mat4Init ( mat44 & A ) {
+ int i,j;
+ for (i=0;i<4;i++) {
+ for (j=0;j<4;j++)
+ A[i][j] = 0.0;
+ A[i][i] = 1.0;
+ }
+ }
+
+ realtype Mat4RotDet ( mat44 & T ) {
+ // returns determinant of the rotation part
+ return T[0][0]*T[1][1]*T[2][2] +
+ T[0][1]*T[1][2]*T[2][0] +
+ T[1][0]*T[2][1]*T[0][2] -
+ T[0][2]*T[1][1]*T[2][0] -
+ T[0][0]*T[1][2]*T[2][1] -
+ T[2][2]*T[0][1]*T[1][0];
+ }
+
+ bool isMat4Unit ( mat44 & A, realtype eps, bool rotOnly ) {
+ // returns true if A is a unit 4x4 matrix
+ int i,j,k;
+ bool B;
+
+ if (rotOnly) k = 3;
+ else k = 4;
+
+ B = true;
+ for (i=0;(i<k) && B;i++)
+ for (j=0;(j<k) && B;j++)
+ if (i==j) B = (fabs(1.0-A[i][j])<eps);
+ else B = (fabs(A[i][j])<eps);
+
+ return B;
+
+ }
+
+ void Mat3Init ( mat33 & A ) {
+ int i,j;
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++)
+ A[i][j] = 0.0;
+ A[i][i] = 1.0;
+ }
+ }
+
+ void Mat4Copy ( mat44 & A, mat44 & ACopy ) {
+ int i,j;
+ for (i=0;i<4;i++)
+ for (j=0;j<4;j++)
+ ACopy[i][j] = A[i][j];
+ }
+
+ void Mat3Copy ( mat33 & A, mat33 & ACopy ) {
+ int i,j;
+ for (i=0;i<3;i++)
+ for (j=0;j<3;j++)
+ ACopy[i][j] = A[i][j];
+ }
+
+ bool isMat4Eq ( mat44 & A, mat44 & B, realtype eps,
+ bool rotOnly ) {
+ // returns true if A is equal to B within precision eps
+ int i,j,k;
+ bool Eq;
+
+ if (rotOnly) k = 3;
+ else k = 4;
+
+ Eq = true;
+ for (i=0;(i<k) && Eq;i++)
+ for (j=0;(j<k) && Eq;j++)
+ Eq = (fabs(A[i][j]-B[i][j])<eps);
+
+ return Eq;
+
+ }
+
+
+ void TransformXYZ ( mat44 & T, realtype & X, realtype & Y,
+ realtype & Z ) {
+ realtype x1,y1,z1;
+ x1 = T[0][0]*X + T[0][1]*Y + T[0][2]*Z + T[0][3];
+ y1 = T[1][0]*X + T[1][1]*Y + T[1][2]*Z + T[1][3];
+ z1 = T[2][0]*X + T[2][1]*Y + T[2][2]*Z + T[2][3];
+ X = x1;
+ Y = y1;
+ Z = z1;
+ }
+
+ realtype TransformX ( mat44 & T, realtype X, realtype Y,
+ realtype Z ) {
+ return T[0][0]*X + T[0][1]*Y + T[0][2]*Z + T[0][3];
+ }
+
+ realtype TransformY ( mat44 & T, realtype X, realtype Y,
+ realtype Z ) {
+ return T[1][0]*X + T[1][1]*Y + T[1][2]*Z + T[1][3];
+ }
+
+ realtype TransformZ ( mat44 & T, realtype X, realtype Y,
+ realtype Z ) {
+ return T[2][0]*X + T[2][1]*Y + T[2][2]*Z + T[2][3];
+ }
+
+
+
+
+ char CIFErrorLocation[200] = "no error";
+
+ static cpstr msWrongSection =
+ "Wrong section. The sections in PDB file may be put in wrong order.";
+ static cpstr msWrongChainID =
+ "Wrong chain ID. The input may have changed to another chain.";
+ static cpstr msWrongEntryID =
+ "Entry ID does not match the header.";
+
+ static cpstr msSEQRES_serNum =
+ "Serial numbers of SEQRES records do not increment by 1.";
+ static cpstr msSEQRES_numRes =
+ "Different SEQRES records show different numbers of residues.";
+ static cpstr msSEQRES_extraRes =
+ "SEQRES records contain more residues than specified.";
+
+ static cpstr msNCSM_Unrecognized =
+ "Unrecognized numerical input in MTRIXn.";
+ static cpstr msNCSM_AlreadySet =
+ "Duplicate MTRIXn record.";
+ static cpstr msNCSM_WrongSerial =
+ "Serial number in MTRIXn record is wrong.";
+ static cpstr msNCSM_UnmatchIG =
+ "Different MTRIXn record show different iGiven flag.";
+
+ static cpstr msATOM_Unrecognized =
+ "Numerical information in ATOM record is not recognized.";
+ static cpstr msATOM_AlreadySet =
+ "Atom is already in the system.";
+ static cpstr msATOM_NoResidue =
+ "No residue is found for atom.";
+ static cpstr msATOM_Unmatch =
+ "Unmatch in different records for the same atom.";
+
+ static cpstr msCantOpenFile = "File can not be opened.";
+ static cpstr msUnrecognizedInteger =
+ "Wrong ASCII format of an integer.";
+ static cpstr msWrongModelNo = "Wrong model number.";
+ static cpstr msDuplicatedModel = "Duplicate model number.";
+ static cpstr msNoModel = "No model defined.";
+ static cpstr msForeignFile =
+ "Attempt to read unknown-type file.";
+ static cpstr msWrongEdition =
+ "Attempt to read a higher-version file.";
+
+ static cpstr msNoData = "Expected data field not found.";
+ static cpstr msUnrecognizedReal = "Wrong ASCII format of a real.";
+ static cpstr msNotACIFFile =
+ "Not a CIF file ('data_' missing).";
+ static cpstr msUnrecognCIFItems =
+ "Unrecognized item(s) in CIF file.";
+ static cpstr msMissingCIFField = "Expected CIF item(s) missing.";
+ static cpstr msEmptyCIFLoop = "Empty CIF loop encountered.";
+ static cpstr msUnexpEndOfCIF = "Unexpected end of CIF file.";
+ static cpstr msMissgCIFLoopField = "Inconsistent CIF loop.";
+ static cpstr msNotACIFStructure =
+ "Wrong use of CIF structure (as a loop?).";
+ static cpstr msNotACIFLoop =
+ "Wrong use of CIF loop (as a structure?).";
+
+ static cpstr msNoSheetID = "No Sheet ID on PDB ASCII card.";
+ static cpstr msWrongSheetID = "Wrong Sheet ID.";
+ static cpstr msWrongStrandNo =
+ "Wrong Strand number on PDB SHEET card.";
+
+ static cpstr msWrongNumberOfStrands =
+ "Wrong number of strands in CIF file.";
+ static cpstr msWrongSheetOrder = "Incomplete _struct_sheet_order.";
+ static cpstr msHBondInconsistency =
+ "Inconsistency in _struct_sheet_hbond.";
+
+ static cpstr msEmptyResidueName =
+ "No residue name on PDB ATOM or TER card.";
+ static cpstr msDuplicateSeqNum =
+ "Duplicate sequence number and insertion code.";
+
+ static cpstr msEmptyFile = "Non-existent or empty file.";
+
+ static cpstr msNoLogicalName = "Logical file name not found.";
+
+
+ cpstr GetErrorDescription ( ERROR_CODE ErrorCode ) {
+
+ switch (ErrorCode) {
+
+ case Error_NoError : return "No errors.";
+
+ case Error_WrongSection : return msWrongSection;
+ case Error_WrongChainID : return msWrongChainID;
+ case Error_WrongEntryID : return msWrongEntryID;
+
+ case Error_SEQRES_serNum : return msSEQRES_serNum;
+ case Error_SEQRES_numRes : return msSEQRES_numRes;
+ case Error_SEQRES_extraRes : return msSEQRES_extraRes;
+
+ case Error_NCSM_Unrecognized : return msNCSM_Unrecognized;
+ case Error_NCSM_AlreadySet : return msNCSM_AlreadySet;
+ case Error_NCSM_WrongSerial : return msNCSM_WrongSerial;
+ case Error_NCSM_UnmatchIG : return msNCSM_UnmatchIG;
+
+ case Error_ATOM_Unrecognized : return msATOM_Unrecognized;
+ case Error_ATOM_AlreadySet : return msATOM_AlreadySet;
+ case Error_ATOM_NoResidue : return msATOM_NoResidue;
+ case Error_ATOM_Unmatch : return msATOM_Unmatch;
+
+ case Error_CantOpenFile : return msCantOpenFile;
+ case Error_UnrecognizedInteger : return msUnrecognizedInteger;
+ case Error_WrongModelNo : return msWrongModelNo;
+ case Error_DuplicatedModel : return msDuplicatedModel;
+ case Error_NoModel : return msNoModel;
+ case Error_ForeignFile : return msForeignFile;
+ case Error_WrongEdition : return msWrongEdition;
+
+ case Error_NoData : return msNoData;
+ case Error_UnrecognizedReal : return msUnrecognizedReal;
+ case Error_NotACIFFile : return msNotACIFFile;
+ case Error_UnrecognCIFItems : return msUnrecognCIFItems;
+ case Error_MissingCIFField : return msMissingCIFField;
+ case Error_EmptyCIFLoop : return msEmptyCIFLoop;
+ case Error_UnexpEndOfCIF : return msUnexpEndOfCIF;
+ case Error_MissgCIFLoopField : return msMissgCIFLoopField;
+ case Error_NotACIFStructure : return msNotACIFStructure;
+ case Error_NotACIFLoop : return msNotACIFLoop;
+
+ case Error_NoSheetID : return msNoSheetID;
+ case Error_WrongSheetID : return msWrongSheetID;
+ case Error_WrongStrandNo : return msWrongStrandNo;
+
+ case Error_WrongNumberOfStrands : return msWrongNumberOfStrands;
+ case Error_WrongSheetOrder : return msWrongSheetOrder;
+ case Error_HBondInconsistency : return msHBondInconsistency;
+
+ case Error_EmptyResidueName : return msEmptyResidueName;
+ case Error_DuplicateSeqNum : return msDuplicateSeqNum;
+
+ case Error_EmptyFile : return msEmptyFile;
+
+ case Error_NoLogicalName : return msNoLogicalName;
+
+ default : return "Unknown error.";
+
+ }
+ }
+
+
+ // ============== ContainerClass ====================
+
+ ContainerClass::ContainerClass() : io::Stream() {
+ ContinuationNo = 0;
+ }
+
+ ContainerClass::ContainerClass ( io::RPStream Object )
+ : io::Stream(Object) {
+ ContinuationNo = 0;
+ }
+
+ bool ContainerClass::Append ( PContainerClass CC ) {
+ return (CC->ContinuationNo>1);
+ }
+
+
+ // =================== ContString =====================
+
+ ContString::ContString() : ContainerClass() {
+ InitString();
+ }
+
+ ContString::ContString ( cpstr S ) : ContainerClass() {
+ InitString();
+ ConvertPDBASCII ( S );
+ }
+
+ ContString::ContString ( io::RPStream Object )
+ : ContainerClass(Object) {
+ InitString();
+ }
+
+ ContString::~ContString() {
+ if (Line) delete[] Line;
+ if (CIFCategory) delete[] CIFCategory;
+ if (CIFTag) delete[] CIFTag;
+ }
+
+ void ContString::InitString() {
+ Line = NULL;
+ CIFCategory = NULL;
+ CIFTag = NULL;
+ }
+
+ ERROR_CODE ContString::ConvertPDBASCII ( cpstr S ) {
+ CreateCopy ( Line,S );
+ return Error_NoError;
+ }
+
+ void ContString::PDBASCIIDump ( pstr S, int ) {
+ if (Line) strcpy ( S,Line );
+ else strcpy ( S,"" );
+ }
+
+ bool ContString::PDBASCIIDump1 ( io::RFile f ) {
+ if (Line) f.WriteLine ( Line );
+ else f.LF();
+ return true;
+ }
+
+/*
+ void ContString::GetCIF1 ( mmcif::PData CIF, ERROR_CODE & Signal,
+ int & pos ) {
+ pstr F;
+ int i,RC;
+ char c;
+ if ((!CIFCategory) || (!CIFTag)) {
+ Signal = Error_EmptyCIF;
+ return;
+ }
+ F = CIF->GetString ( CIFCategory,CIFTag,RC );
+ if (RC || (!F)) {
+ Signal = Error_EmptyCIF;
+ return;
+ }
+ if (Signal>=(int)strlen(F)) {
+ CIF->DeleteField ( CIFCategory,CIFTag );
+ Signal = Error_EmptyCIF;
+ return;
+ }
+// i = Signal;
+// while (F[i] && (F[i]!='\n') && (F[i]!='\r')) i++;
+// if ((Signal==0) && (i==0)) {
+// i++;
+// if (((F[Signal]=='\n') && (F[i]=='\r')) ||
+// ((F[Signal]=='\r') && (F[i]=='\n'))) i++;
+// Signal = i;
+// while (F[i] && (F[i]!='\n') && (F[i]!='\r')) i++;
+// }
+// c = F[i];
+// F[i] = char(0);
+// CreateCopy ( Line,&(F[Signal]) );
+// if (c) {
+// F[i] = c;
+// Signal = i+1;
+// if (((c=='\n') && (F[Signal]=='\r')) ||
+// ((c=='\r') && (F[Signal]=='\n'))) Signal++;
+// } else
+// CIF->DeleteField ( CIFCategory,CIFTag );
+ i = pos;
+ while (F[i] && (F[i]!='\n') && (F[i]!='\r')) i++;
+ if ((pos==0) && (i==0)) {
+ i++;
+ if (((F[pos]=='\n') && (F[i]=='\r')) ||
+ ((F[pos]=='\r') && (F[i]=='\n'))) i++;
+ pos = i;
+ while (F[i] && (F[i]!='\n') && (F[i]!='\r')) i++;
+ }
+ c = F[i];
+ F[i] = char(0);
+ CreateCopy ( Line,&(F[pos]) );
+ if (c) {
+ F[i] = c;
+ pos = i+1;
+ if (((c=='\n') && (F[pos]=='\r')) ||
+ ((c=='\r') && (F[pos]=='\n'))) pos++;
+ } else
+ CIF->DeleteField ( CIFCategory,CIFTag );
+ }
+*/
+
+ void ContString::MakeCIF ( mmcif::PData CIF, int N ) {
+ pstr S;
+ if ((!CIFCategory) || (!CIFTag)) return;
+ S = new char[strlen(Line)+5];
+ strcpy ( S,"\n" );
+ strcat ( S,Line );
+ CIF->PutString ( S,CIFCategory,CIFTag,(N!=0) );
+ delete[] S;
+ }
+
+ bool ContString::Append ( PContainerClass CC ) {
+ if (ContainerClass::Append(CC)) {
+ if (!Line) {
+ Line = PContString(CC)->Line;
+ PContString(CC)->Line = NULL;
+ } else
+ CreateConcat ( Line,pstr("\n"),PContString(CC)->Line );
+ return true;
+ }
+ return false;
+ }
+
+ void ContString::Copy ( PContainerClass CString ) {
+ CreateCopy ( Line,PContString(CString)->Line );
+ }
+
+ void ContString::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.CreateWrite ( Line );
+ f.CreateWrite ( CIFCategory );
+ f.CreateWrite ( CIFTag );
+ }
+
+ void ContString::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ f.CreateRead ( Line );
+ f.CreateRead ( CIFCategory );
+ f.CreateRead ( CIFTag );
+ }
+
+ MakeStreamFunctions(ContString)
+
+
+
+ // ============== ClassContainer ====================
+
+ MakeStreamFunctions(ContainerClass)
+
+ ClassContainer::ClassContainer() : io::Stream() {
+ Init();
+ }
+
+ ClassContainer::ClassContainer ( io::RPStream Object )
+ : io::Stream(Object) {
+ Init();
+ }
+
+ void ClassContainer::Init() {
+ length = 0;
+ Container = NULL;
+ }
+
+ ClassContainer::~ClassContainer() {
+ FreeContainer();
+ }
+
+ void ClassContainer::FreeContainer() {
+ int i;
+ if (Container) {
+ for (i=0;i<length;i++)
+ if (Container[i])
+ delete Container[i];
+ delete[] Container;
+ }
+ Container = NULL;
+ length = 0;
+ }
+
+ void ClassContainer::AddData ( PContainerClass Data ) {
+ int i;
+ PPContainerClass C1;
+ if (!Data) return;
+ if (length>0) {
+ i = length-1;
+ while (i>=0) {
+ if (!Container[i]) i--;
+ else if (Container[i]->GetClassID()!=Data->GetClassID()) i--;
+ else break;
+ }
+ if (i>=0) {
+ if (Container[i]->Append(Data)) {
+ delete Data;
+ return;
+ }
+ }
+ }
+ C1 = new PContainerClass[length+1];
+ for (i=0;i<length;i++)
+ C1[i] = Container[i];
+ C1[length] = Data;
+ if (Container) delete[] Container;
+ Container = C1;
+ length++;
+ }
+
+ void ClassContainer::PDBASCIIDump ( io::RFile f ) {
+ char S[500];
+ int i,j;
+ for (i=0;i<length;i++)
+ if (Container[i]) {
+ if (!Container[i]->PDBASCIIDump1(f)) {
+ Container[i]->PDBASCIIDump ( S,i );
+ j = strlen(S);
+ while (j<80) S[j++] = ' ';
+ S[80] = char(0);
+ f.WriteLine ( S );
+ }
+ }
+ }
+
+ ERROR_CODE ClassContainer::GetCIF ( mmcif::PData CIF, int ClassID ) {
+ PContainerClass ContainerClass;
+ int n;
+ ERROR_CODE rc;
+ n = -1;
+ do {
+ ContainerClass = MakeContainerClass ( ClassID );
+ rc = ContainerClass->GetCIF ( CIF,n );
+ if (rc==Error_NoError)
+ AddData ( ContainerClass );
+ } while (rc==Error_NoError);
+ delete ContainerClass;
+ if (rc==Error_EmptyCIF)
+ rc = Error_NoError;
+ return rc;
+ }
+
+ void ClassContainer::MakeCIF ( mmcif::PData CIF ) {
+ int i;
+ for (i=0;i<length;i++)
+ if (Container[i])
+ Container[i]->MakeCIF ( CIF,i );
+ }
+
+ void ClassContainer::write ( io::RFile f ) {
+ int i,ClassID;
+ byte Version=1;
+ f.WriteByte ( &Version );
+ f.WriteInt ( &length );
+ for (i=0;i<length;i++)
+ if (Container[i]) {
+ ClassID = Container[i]->GetClassID();
+ f.WriteInt ( &ClassID );
+ Container[i]->write ( f );
+ } else {
+ ClassID = -1;
+ f.WriteInt ( &ClassID );
+ }
+ }
+
+ PContainerClass ClassContainer::MakeContainerClass ( int ClassID ) {
+ if (ClassID==ClassID_String) return new ContString();
+ return new ContainerClass();
+ }
+
+ PContainerClass ClassContainer::GetContainerClass (int ContClassNo) {
+ if ((ContClassNo<0) || (ContClassNo>=length)) return NULL;
+ return Container[ContClassNo];
+ }
+
+ void ClassContainer::Copy ( PClassContainer CContainer ) {
+ int i;
+ FreeContainer();
+ if (CContainer) {
+ length = CContainer->length;
+ if (length>0) {
+ Container = new PContainerClass[length];
+ for (i=0;i<length;i++)
+ if (CContainer->Container[i]) {
+ Container[i] = MakeContainerClass (
+ CContainer->Container[i]->GetClassID() );
+ Container[i]->Copy ( CContainer->Container[i] );
+ } else
+ Container[i] = NULL;
+ }
+ }
+ }
+
+ void ClassContainer::read ( io::RFile f ) {
+ int i,ClassID;
+ byte Version;
+ FreeContainer();
+ f.ReadByte ( &Version );
+ f.ReadInt ( &length );
+ if (length>0) {
+ Container = new PContainerClass[length];
+ for (i=0;i<length;i++) {
+ f.ReadInt ( &ClassID );
+ if (ClassID>=0) {
+ Container[i] = MakeContainerClass ( ClassID );
+ Container[i]->read ( f );
+ } else
+ Container[i] = NULL;
+ }
+ }
+ }
+
+ MakeStreamFunctions(ClassContainer)
+
+
+
+ // ====================== ID parsers ==========================
+
+
+ AtomPath::AtomPath() : io::Stream() {
+ InitAtomPath();
+ }
+
+ AtomPath::AtomPath ( cpstr ID ) : io::Stream() {
+ InitAtomPath();
+ SetPath ( ID );
+ }
+
+ AtomPath::AtomPath ( io::RPStream Object ) : io::Stream(Object) {
+ InitAtomPath();
+ }
+
+ AtomPath::~AtomPath() {}
+
+ void AtomPath::InitAtomPath() {
+ modelNo = 0;
+ chainID [0] = char(0);
+ seqNum = MinInt4;
+ insCode [0] = char(0);
+ resName [0] = char(0);
+ atomName[0] = char(0);
+ element [0] = char(0);
+ altLoc [0] = char(0);
+ isSet = 0;
+ }
+
+ int AtomPath::SetPath ( cpstr ID ) {
+ // 1. If ID starts with '/':
+ // /mdl/chn/seq(res).i/atm[elm]:a
+ //
+ // 2. If ID starts with a letter:
+ // chn/seq(res).i/atm[elm]:a
+ //
+ // 3. If ID starts with a number:
+ // seq(res).i/atm[elm]:a
+ //
+ // 4. If ID contains colon ':' then
+ // it may be just
+ // atm[elm]:a
+ //
+ // All spaces are ignored. isSet
+ // sets bit for each element present.
+ // Any element may be a wildcard '*'.
+ // Wildcard for model will set modelNo=0,
+ // for sequence number will set
+ // seqNum=MinInt4.
+ //
+ // Returns:
+ // 0 <-> Ok
+ // -1 <-> wrong numerical format for model
+ // -2 <-> wrong numerical format for sequence number
+ //
+ char N[100];
+ pstr p,p1;
+ int i,k;
+
+ isSet = 0; // clear all bits.
+
+ p = pstr(ID);
+ while (*p==' ') p++;
+
+ if (!(*p)) return 0;
+
+ if (*p=='/') {
+ // model number
+ p++;
+ i = 0;
+ while ((*p) && (*p!='/')) {
+ if (*p!=' ') N[i++] = *p;
+ p++;
+ }
+ N[i] = char(0);
+ if ((!N[0]) || (N[0]=='*')) modelNo = 0;
+ else {
+ modelNo = mround(strtod(N,&p1));
+ if ((modelNo==0) && (p1==N)) return -1;
+ }
+ isSet |= APATH_ModelNo;
+ if (*p!='/') return 0;
+ p++;
+ while (*p==' ') p++;
+ }
+
+ if ((*p<'0') || (*p>'9')) {
+ // chain ID
+ i = 0;
+ k = sizeof(ChainID)-1;
+ while ((*p) && (*p!='/')) {
+ if ((*p!=' ') && (i<k)) chainID[i++] = *p;
+ p++;
+ }
+ chainID[i] = char(0);
+ if (!chainID[0]) {
+ chainID[0] = '*';
+ chainID[1] = char(0);
+ }
+ isSet |= APATH_ChainID;
+ if (*p!='/') return 0;
+ p++;
+ while (*p==' ') p++;
+ }
+
+ if (((*p>='0') && (*p<='9')) || (*p=='-') ||
+ (*p=='(') || (*p=='.')) {
+ // sequence number, residue name and insertion code
+ i = 0;
+ while ((*p) && (*p!='/')) {
+ if (*p!=' ') N[i++] = *p;
+ p++;
+ }
+ N[i] = char(0);
+ i = ParseResID ( N,seqNum,insCode,resName );
+ if (i==2) return -2;
+ isSet |= APATH_SeqNum | APATH_InsCode | APATH_ResName;
+ if (*p!='/') return 0;
+ p++;
+ while (*p==' ') p++;
+ }
+
+ if (strchr(p,':') || strchr(p,'[')) {
+ // atom name, chemical element and alternative location
+ i = 0;
+ while (*p) {
+ if (*p!=' ') N[i++] = *p;
+ p++;
+ }
+ N[i] = char(0);
+ ParseAtomID ( N,atomName,element,altLoc );
+ isSet |= APATH_AtomName | APATH_Element | APATH_AltLoc;
+ }
+
+ return 0;
+
+ }
+
+ void AtomPath::write ( io::RFile f ) {
+ byte Version=1;
+ f.WriteByte ( &Version );
+ io::Stream::write ( f );
+ f.WriteInt ( &modelNo );
+ f.WriteInt ( &seqNum );
+ f.WriteInt ( &isSet );
+ f.WriteTerLine ( chainID ,false );
+ f.WriteTerLine ( insCode ,false );
+ f.WriteTerLine ( resName ,false );
+ f.WriteTerLine ( atomName,false );
+ f.WriteTerLine ( element ,false );
+ f.WriteTerLine ( altLoc ,false );
+ }
+
+ void AtomPath::read ( io::RFile f ) {
+ byte Version;
+ f.ReadByte ( &Version );
+ io::Stream::read ( f );
+ f.ReadInt ( &modelNo );
+ f.ReadInt ( &seqNum );
+ f.ReadInt ( &isSet );
+ f.ReadTerLine ( chainID ,false );
+ f.ReadTerLine ( insCode ,false );
+ f.ReadTerLine ( resName ,false );
+ f.ReadTerLine ( atomName,false );
+ f.ReadTerLine ( element ,false );
+ f.ReadTerLine ( altLoc ,false );
+ }
+
+
+ MakeStreamFunctions(AtomPath)
+
+
+
+ // --------------------------------------------------------
+
+ QuickSort::QuickSort() : io::Stream() {
+ selSortLimit = 15;
+ data = NULL;
+ dlen = 0;
+ }
+
+ QuickSort::QuickSort ( io::RPStream Object )
+ : io::Stream(Object) {
+ selSortLimit = 15;
+ data = NULL;
+ dlen = 0;
+ }
+
+ int QuickSort::Compare ( int i, int j ) {
+ // sort by increasing data[i]
+ if (((ivector)data)[i]<((ivector)data)[j]) return -1;
+ if (((ivector)data)[i]>((ivector)data)[j]) return 1;
+ return 0;
+ }
+
+ void QuickSort::Swap ( int i, int j ) {
+ int b;
+ b = ((ivector)data)[i];
+ ((ivector)data)[i] = ((ivector)data)[j];
+ ((ivector)data)[j] = b;
+ }
+
+ void QuickSort::SelectionSort ( int left, int right ) {
+ int i,j,imin;
+ for (i=left;i<right;i++) {
+ imin = i;
+ for (j=i+1;j<=right;j++)
+ if (Compare(j,imin)<0) imin = j;
+ Swap ( i,imin );
+ }
+ }
+
+ int QuickSort::Partition ( int left, int right ) {
+ int lv = left;
+ int lm = left-1;
+ int rm = right+1;
+ do {
+ do
+ rm--;
+ while ((rm>0) && (Compare(rm,lv)>0));
+ do
+ lm++;
+ while ((lm<dlen) && (Compare(lm,lv)<0));
+ if (lm<rm) {
+ if (lv==lm) lv = rm;
+ else if (lv==rm) lv = lm;
+ Swap ( lm,rm );
+ }
+ } while (lm<rm);
+ return rm;
+ }
+
+ void QuickSort::Quicksort ( int left, int right ) {
+ int split_pt;
+ if (left<(right-selSortLimit)) {
+ split_pt = Partition ( left,right );
+ Quicksort ( left,split_pt );
+ Quicksort ( split_pt+1,right );
+ } else
+ SelectionSort ( left,right );
+ }
+
+ void QuickSort::Sort ( void * sortdata, int data_len ) {
+ data = sortdata;
+ dlen = data_len-1;
+ if (data) Quicksort ( 0,data_len-1 );
+ }
+
+ // --------------------------------------------------------
+
+ void takeWord ( pstr & p, pstr wrd, cpstr ter, int l ) {
+ pstr p1;
+ int i;
+ p1 = strpbrk ( p,ter );
+ if (!p1)
+ p1 = p + strlen(p);
+ i = 0;
+ while ((p!=p1) && (i<l)) {
+ wrd[i++] = *p;
+ p++;
+ }
+ if (i>=l) i = l-1;
+ wrd[i] = char(0);
+ p = p1;
+ }
+
+
+ void ParseAtomID ( cpstr ID, AtomName aname, Element elname,
+ AltLoc aloc ) {
+ pstr p;
+
+ p = pstr(ID);
+ while (*p==' ') p++;
+
+ strcpy ( aname ,"*" );
+ strcpy ( elname,"*" );
+ if (*p) aloc[0] = char(0);
+ else strcpy ( aloc,"*" );
+
+ takeWord ( p,aname,pstr("[: "),sizeof(AtomName) );
+
+ if (*p=='[') {
+ p++;
+ takeWord ( p,elname,pstr("]: "),sizeof(Element) );
+ if (*p==']') p++;
+ }
+
+ if (*p==':') {
+ p++;
+ takeWord ( p,aloc,pstr(" "),sizeof(AltLoc) );
+ }
+
+ }
+
+ int ParseResID ( cpstr ID, int & sn, InsCode inscode,
+ ResName resname ) {
+ int RC;
+ pstr p,p1;
+ char N[100];
+
+ RC = 0;
+
+ p = pstr(ID);
+ while (*p==' ') p++;
+
+ sn = ANY_RES;
+ strcpy ( inscode,"*" );
+ strcpy ( resname,"*" );
+
+ N[0] = char(0);
+ takeWord ( p,N,pstr("(./ "),sizeof(N) );
+ if ((!N[0]) || (N[0]=='*')) {
+ sn = ANY_RES;
+ RC = 1;
+ }
+ if (!RC) {
+ sn = mround(strtod(N,&p1));
+ if (p1==N) RC = 2;
+ else inscode[0] = char(0);
+ }
+
+ if (*p=='(') {
+ p++;
+ takeWord ( p,resname,pstr(")./ "),sizeof(ResName) );
+ if (*p==')') p++;
+ }
+
+ if (*p=='.') {
+ p++;
+ takeWord ( p,inscode,pstr("/ "),sizeof(InsCode) );
+ }
+
+ return RC;
+
+ }
+
+ int ParseAtomPath ( cpstr ID,
+ int & mdl,
+ ChainID chn,
+ int & sn,
+ InsCode ic,
+ ResName res,
+ AtomName atm,
+ Element elm,
+ AltLoc aloc,
+ PAtomPath DefPath ) {
+ // /mdl/chn/seq(res).i/atm[elm]:a, may be partial
+ char N[100];
+ pstr p,p1;
+ int i,RC;
+ bool wasRes;
+
+ wasRes = false;
+
+ RC = 0;
+
+ p = pstr(ID);
+ while (*p==' ') p++;
+
+ mdl = 0;
+ if (*p=='/') {
+ p++;
+ N[0] = char(0);
+ takeWord ( p,N,pstr("/"),sizeof(N) );
+ if ((!N[0]) || (N[0]=='*')) mdl = 0;
+ else {
+ mdl = mround(strtod(N,&p1));
+ if ((mdl==0) && (p1==N)) return -1;
+ }
+ } else if (DefPath) {
+ if (DefPath->isSet & APATH_ModelNo)
+ mdl = DefPath->modelNo;
+ }
+
+ strcpy ( chn,"*" );
+ if (*p=='/') p++;
+ if ((*p<'0') || (*p>'9')) {
+ p1 = p;
+ chn[0] = char(0);
+ takeWord ( p,chn,pstr("/"),sizeof(ChainID) );
+ if (strpbrk(chn,"(.[:-")) { // this was not a chain ID!
+ if (DefPath) {
+ if (DefPath->isSet & APATH_ChainID)
+ strcpy ( chn,DefPath->chainID );
+ } else
+ strcpy ( chn,"*" );
+ p = p1;
+ }
+ } else if (DefPath) {
+ if (DefPath->isSet & APATH_ChainID)
+ strcpy ( chn,DefPath->chainID );
+ }
+
+ if (*p=='/') p++;
+ sn = ANY_RES;
+ strcpy ( ic ,"*" );
+ strcpy ( res,"*" );
+ if (((*p>='0') && (*p<='9')) || (*p=='-') ||
+ (*p=='(') || (*p=='.')) {
+ wasRes = true;
+ N[0] = char(0);
+ takeWord ( p,N,pstr("/"),sizeof(N) );
+ i = ParseResID ( N,sn,ic,res );
+ if (i==2) return -2;
+ } else if (DefPath) {
+ wasRes = (*p=='/');
+ if (DefPath->isSet & APATH_SeqNum)
+ sn = DefPath->seqNum;
+ if (DefPath->isSet & APATH_InsCode)
+ strcpy ( ic,DefPath->insCode );
+ if (DefPath->isSet & APATH_ResName)
+ strcpy ( res,DefPath->resName );
+ }
+
+ if (*p=='/') p++;
+ strcpy ( atm ,"*" );
+ strcpy ( elm ,"*" );
+ strcpy ( aloc,"*" );
+ if (wasRes || strchr(p,':') || strchr(p,'[')) {
+ ParseAtomID ( p,atm,elm,aloc );
+ } else if (DefPath) {
+ if (DefPath->isSet & APATH_AtomName)
+ strcpy ( atm,DefPath->atomName );
+ if (DefPath->isSet & APATH_Element)
+ strcpy ( elm,DefPath->element );
+ if (DefPath->isSet & APATH_ResName)
+ strcpy ( aloc,DefPath->altLoc );
+ }
+
+ if (mdl<=0) RC |= APATH_WC_ModelNo;
+ if (chn[0]=='*') RC |= APATH_WC_ChainID;
+ if (sn==ANY_RES) RC |= APATH_WC_SeqNum;
+ if (ic[0]=='*') RC |= APATH_WC_InsCode;
+ if (res[0]=='*') RC |= APATH_WC_ResName;
+ if (atm[0]=='*') RC |= APATH_WC_AtomName;
+ if (elm[0]=='*') RC |= APATH_WC_Element;
+ if (aloc[0]=='*') RC |= APATH_WC_AltLoc;
+
+ if (RC & (APATH_WC_ModelNo | APATH_WC_ChainID |
+ APATH_WC_SeqNum | APATH_WC_InsCode |
+ APATH_WC_AtomName | APATH_WC_AltLoc))
+ RC |= APATH_Incomplete;
+
+ return RC;
+
+ }
+
+
+ int ParseSelectionPath (
+ cpstr CID,
+ int & iModel,
+ pstr Chains,
+ int & sNum1,
+ InsCode ic1,
+ int & sNum2,
+ InsCode ic2,
+ pstr RNames,
+ pstr ANames,
+ pstr Elements,
+ pstr altLocs
+ ) {
+ int l,j;
+ pstr p,p1;
+ pstr N;
+ int seqNum [2];
+ InsCode insCode[2];
+ pstr ID;
+ bool wasModel,wasChain,wasRes,haveNeg;
+
+ l = IMax(10,strlen(CID))+1;
+ ID = new char[l];
+ N = new char[l];
+
+ p = pstr(CID);
+ p1 = ID;
+ while (*p) {
+ if (*p!=' ') {
+ *p1 = *p;
+ p1++;
+ }
+ p++;
+ }
+ *p1 = char(0);
+
+ p = ID;
+
+ iModel = 0;
+ strcpy ( Chains,"*" );
+ seqNum[0] = ANY_RES;
+ seqNum[1] = ANY_RES;
+ strcpy ( insCode[0],"*" );
+ strcpy ( insCode[1],"*" );
+ strcpy ( RNames ,"*" );
+ strcpy ( ANames ,"*" );
+ strcpy ( Elements ,"*" );
+ strcpy ( altLocs ,"*" );
+
+ wasModel = false;
+ wasChain = false;
+ wasRes = false;
+
+ if (*p=='/') {
+ // CID starts with the slash -- take model number first
+ p++;
+ N[0] = char(0);
+ takeWord ( p,N,pstr("/"),l );
+ if ((!N[0]) || (N[0]=='*')) iModel = 0;
+ else {
+ iModel = mround(strtod(N,&p1));
+ if ((iModel==0) && (p1==N)) return -1;
+ }
+ if (*p=='/') p++;
+ wasModel = true;
+ }
+
+ if ((*p) && (wasModel || (*p<'0') || (*p>'9'))) {
+ p1 = p;
+ Chains[0] = char(0);
+ takeWord ( p,Chains,pstr("/"),l );
+ if (strpbrk(Chains,"(.[:-")) { // this was not a chain ID!
+ strcpy ( Chains,"*" );
+ p = p1;
+ } else
+ wasChain = true;
+ if (*p=='/') p++;
+ }
+
+ if ((*p) && (wasChain || ((*p>='0') && (*p<='9')) || (*p=='-') ||
+ (*p=='(') || (*p=='.') || (*p=='*'))) {
+ j = 0;
+ do {
+ // take the sequence number
+ haveNeg = false;
+ if (*p=='-') {
+ haveNeg = true;
+ p++;
+ }
+ N[0] = char(0);
+ takeWord ( p,N,pstr("(.-/"),l );
+ if ((!N[0]) || (N[0]=='*'))
+ seqNum[j] = ANY_RES;
+ else {
+ seqNum[j] = mround(strtod(N,&p1));
+ if (p1==N) return -2;
+ if (haveNeg) seqNum[j] = - seqNum[j];
+ }
+ // take the residue list
+ if (*p=='(') {
+ p++;
+ takeWord ( p,RNames,pstr(").-/"),l );
+ if (*p==')') p++;
+ }
+ // take the insertion code
+ if (seqNum[j]!=ANY_RES)
+ insCode[j][0] = char(0);
+ if (*p=='.') {
+ p++;
+ takeWord ( p,insCode[j],pstr("-/"),sizeof(InsCode) );
+ }
+ if (*p=='-') {
+ p++;
+ j++;
+ } else {
+ if (j==0) {
+ seqNum[1] = seqNum[0];
+ strcpy ( insCode[1],insCode[0] );
+ }
+ j = 10;
+ }
+ } while (j<2);
+ wasRes = true;
+ } else
+ wasRes = (*p=='/');
+
+ if (*p=='/') p++;
+ if ((*p) && (wasRes || strchr(p,':') || strchr(p,'['))) {
+ if (*p) altLocs[0] = char(0);
+ takeWord ( p,ANames,pstr("[:"),l );
+ if (!ANames[0]) strcpy ( ANames,"*" );
+ if (*p=='[') {
+ p++;
+ takeWord ( p,Elements,pstr("]:"),l );
+ if (*p==']') p++;
+ }
+ if (*p==':') {
+ p++;
+ takeWord ( p,altLocs,pstr(" "),l );
+ }
+ }
+
+ /*
+ printf ( " iModel = %i\n"
+ " Chains = '%s'\n"
+ " seqNum1 = %i\n"
+ " insCode1 = '%s'\n"
+ " seqNum2 = %i\n"
+ " insCode2 = '%s'\n"
+ " RNames = '%s'\n"
+ " ANames = '%s'\n"
+ " Elements = '%s'\n"
+ " altLocs = '%s'\n",
+ iModel,Chains,seqNum[0],insCode[0],
+ seqNum[1],insCode[1],RNames,ANames,
+ Elements,altLocs );
+ */
+
+ sNum1 = seqNum[0];
+ sNum2 = seqNum[1];
+ strcpy ( ic1,insCode[0] );
+ strcpy ( ic2,insCode[1] );
+
+ delete[] ID;
+ delete[] N;
+
+ return 0;
+
+ }
+
+
+ void MakeSelectionPath (
+ pstr CID,
+ int iModel,
+ cpstr Chains,
+ int sNum1,
+ const InsCode ic1,
+ int sNum2,
+ const InsCode ic2,
+ cpstr RNames,
+ cpstr ANames,
+ cpstr Elements,
+ cpstr altLocs
+ ) {
+ char S[100];
+ int k;
+
+ if (iModel>0) {
+ sprintf ( CID,"/%i",iModel );
+ k = 1;
+ } else {
+ CID[0] = char(0);
+ k = 0;
+ }
+
+ if (Chains[0]!='*') {
+ if (k>0) strcat ( CID,"/" );
+ strcat ( CID,Chains );
+ k = 2;
+ }
+
+ if ((sNum1!=-MaxInt4) || (ic1[0]!='*')) {
+ if (k>0) {
+ if (k<2) strcat ( CID,"/*" );
+ strcat ( CID,"/" );
+ }
+ if (sNum1>-MaxInt4) sprintf ( S,"%i",sNum1 );
+ else strcpy ( S,"*" );
+ if (ic1[0]!='*') {
+ strcat ( S,"." );
+ strcat ( S,ic1 );
+ }
+ strcat ( CID,S );
+
+ if ((sNum2!=-MaxInt4) || (ic2[0]!='*')) {
+ strcat ( CID,"-" );
+ if (sNum1>-MaxInt4) sprintf ( S,"%i",sNum2 );
+ else strcpy ( S,"*" );
+ if (ic2[0]!='*') {
+ strcat ( S,"." );
+ strcat ( S,ic2 );
+ }
+ strcat ( CID,S );
+ }
+
+ k = 3;
+
+ }
+
+ if (RNames[0]!='*') {
+ if (k<1) strcat ( CID,"(" );
+ else if (k<2) strcat ( CID,"*/*(" );
+ else if (k<3) strcat ( CID,"/*(" );
+ strcat ( CID,RNames );
+ strcat ( CID,")" );
+ k = 4;
+ }
+
+ if (ANames[0]!='*') {
+ if (k<1) strcat ( CID,"/*/*/*/" ); // full path
+ else if (k<2) strcat ( CID,"/*/*/" ); // /mdl + /*/*/
+ else if (k<3) strcat ( CID,"/*/" ); // /mdl/chn + /*/
+ else if (k<4) strcat ( CID,"/" ); // /mdl/chn/res + /
+ strcat ( CID,ANames );
+ strcat ( CID,")" );
+ k = 5;
+ }
+
+ if (Elements[0]!='*') {
+ if (k<1) strcat ( CID,"[" );
+ else if (k<2) strcat ( CID,"/*/*/*[" );
+ else if (k<3) strcat ( CID,"/*/*[" );
+ else if (k<4) strcat ( CID,"/*[" );
+ else if (k<5) strcat ( CID,"[" );
+ strcat ( CID,Elements );
+ strcat ( CID,"]" );
+ k = 6;
+ }
+
+ if (altLocs[0]!='*') {
+ if (k<1) strcat ( CID,":" );
+ else if (k<2) strcat ( CID,"/*/*/*:" );
+ else if (k<3) strcat ( CID,"/*/*:" );
+ else if (k<4) strcat ( CID,"/*:" );
+ else if (k<6) strcat ( CID,":" );
+ strcat ( CID,altLocs );
+ }
+
+ }
+
+} // namespace mmdb
+
diff --git a/mmdb2/mmdb_utils.h b/mmdb2/mmdb_utils.h
new file mode 100644
index 0000000..e17ed74
--- /dev/null
+++ b/mmdb2/mmdb_utils.h
@@ -0,0 +1,633 @@
+// $Id: mmdb_utils.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2008.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 12.09.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDBF_Utils <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+//
+// **** Classes : mmdb::ContainerClass ( containered class template )
+// ~~~~~~~~~ mmdb::ContString ( containered string )
+// mmdb::ClassContainer ( container of classes )
+// mmdb::AtomPath ( atom path ID )
+// mmdb::QuickSort ( quick sort of integers )
+//
+// **** Functions : Date9to11 ( DD-MMM-YY -> DD-MMM-YYYY )
+// ~~~~~~~~~~~ Date11to9 ( DD-MMM-YYYY -> DD-MMM-YY )
+// Date9toCIF ( DD-MMM-YY -> YYYY-MM-DD )
+// Date11toCIF( DD-MMM-YYYY -> YYYY-MM-DD )
+// DateCIFto9 ( YYYY-MM-DD -> DD-MMM-YY )
+// DateCIFto11( YYYY-MM-DD -> DD-MMM-YYYY )
+// GetInteger ( reads integer from a string )
+// GetReal ( reads real from a string )
+// GetIntIns ( reads integer and insert code )
+// PutInteger ( writes integer into a string )
+// PutRealF ( writes real in F-form into a string )
+// PutIntIns ( writes integer and insert code )
+// CIFGetInteger ( reads and deletes int from CIF )
+// CIFGetReal ( reads and deletes real from CIF )
+// CIFGetString ( reads and deletes string from CIF)
+// CIFGetInteger1 (reads and del-s int from CIF loop)
+// CIFGetReal1 (reads and del-s int from CIF loop)
+// Mat4Inverse ( inversion of 4x4 matrices )
+// GetErrorDescription (ascii line to an Error_XXXXX)
+// ParseAtomID ( parses atom ID line )
+// ParseResID ( parses residue ID line )
+// ParseAtomPath ( parses full atom path )
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_Utils__
+#define __MMDB_Utils__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_mmcif_.h"
+#include "mmdb_defs.h"
+
+namespace mmdb {
+
+ // ================== Date functions ===================
+
+ // converts DD-MMM-YY to DD-MMM-YYYY; appends terminating zero
+ extern void Date9to11 ( cpstr Date9, pstr Date11 );
+
+ // converts DD-MMM-YYYY to DD-MMM-YY; does not append terminating zero
+ extern void Date11to9 ( cpstr Date11, pstr Date9 );
+
+ // converts DD-MMM-YY to YYYY-MM-DD; appends terminating zero
+ extern void Date9toCIF ( cpstr Date9, pstr DateCIF );
+
+ // converts DD-MMM-YYYY to YYYY-MM-DD; appends terminating zero
+ extern void Date11toCIF ( cpstr Date11, pstr DateCIF );
+
+ // converts YYYY-MM-DD to DD-MMM-YY; appends terminating zero
+ extern void DateCIFto9 ( cpstr DateCIF, pstr Date9 );
+
+ // converts YYYY-MM-DD to DD-MMM-YYYY; appends terminating zero
+ extern void DateCIFto11 ( cpstr DateCIF, pstr Date11 );
+
+
+ // ================= Format functions ==================
+
+ // Returns true if S contains an integer number in its
+ // first M characters. This number is returned in N.
+ // The return is false if no integer number may be
+ // recognized. In this case, N is assigned MinInt4 value.
+ extern bool GetInteger ( int & N, cpstr S, int M );
+
+ // Returns true if S contains a real number in its
+ // first M characters. This number is returned in R.
+ // The return is false if no real number may be
+ // recognized. In this case, R is assigned -MaxReal value.
+ extern bool GetReal ( realtype & R, cpstr S, int M );
+
+ // Returns true if S contains an integer number in its
+ // first M characters. This number is returned in N. In addition
+ // to that, GetIntIns() retrieves the insertion code which may
+ // follow the integer and returns it in "ins" (1 character +
+ // terminating 0).
+ // The return is false if no integer number may be
+ // recognized. In this case, N is assigned MinInt4 value,
+ // "ins" just returns (M+1)th symbol of S (+terminating 0).
+ extern bool GetIntIns ( int & N, pstr ins, cpstr S, int M );
+
+ // Integer N is converted into ASCII string of length M
+ // and pasted onto first M characters of string S. No
+ // terminating zero is added.
+ // If N is set to MinInt4, then first M characters of
+ // string S are set to space.
+ extern void PutInteger ( pstr S, int N, int M );
+
+ // Real R is converted into ASCII string of length M
+ // and pasted onto first M characters of string S. No
+ // terminating zero is added. The conversion is done
+ // according to fixed format FM.L
+ // If R is set to -MaxReal, then first M characters of
+ // string S are set to the space character.
+ extern void PutRealF ( pstr S, realtype R, int M, int L );
+
+ // Integer N is converted into ASCII string of length M
+ // and pasted onto first M characters of string S. No
+ // terminating zero is added. The insert code ins is put
+ // immediately after the integer.
+ // If N is set to MinInt4, then first M+1 characters of
+ // string S are set to space, and no insert code are
+ // appended.
+ extern void PutIntIns ( pstr S, int N, int M, cpstr ins );
+
+
+ // CIFInteger(..), CIFReal(..) and CIFGetString(..) automate
+ // extraction and analysis of data from CIF file. If the data
+ // is erroneous or absent, they store an error message in
+ // CIFErrorLocation string (below) and return non-zero.
+ extern ERROR_CODE CIFGetInteger ( int & I, mmcif::PStruct Struct,
+ cpstr Tag,
+ bool Remove=true );
+ extern ERROR_CODE CIFGetReal ( realtype & R, mmcif::PStruct Struct,
+ cpstr Tag,
+ bool Remove=true );
+ extern ERROR_CODE CIFGetString ( pstr S, mmcif::PStruct Struct,
+ cpstr Tag, int SLen,
+ cpstr DefS,
+ bool Remove=true );
+
+ extern ERROR_CODE CIFGetInteger ( int & I, mmcif::PLoop Loop, cpstr Tag,
+ int & Signal );
+ extern ERROR_CODE CIFGetIntegerD ( int & I, mmcif::PLoop Loop, cpstr Tag,
+ int defValue=MinInt4 );
+ extern ERROR_CODE CIFGetInteger1 ( int & I, mmcif::PLoop Loop, cpstr Tag,
+ int nrow );
+
+ extern ERROR_CODE CIFGetReal ( realtype & R, mmcif::PLoop Loop,
+ cpstr Tag, int & Signal );
+ extern ERROR_CODE CIFGetReal1 ( realtype & R, mmcif::PLoop Loop,
+ cpstr Tag, int nrow );
+
+ extern ERROR_CODE CIFGetString ( pstr S, mmcif::PLoop Loop, cpstr Tag,
+ int row, int SLen, cpstr DefS );
+
+ // Calculates AI=A^{-1}
+ extern void Mat4Inverse ( mat44 & A, mat44 & AI );
+ // Calculates A=B*C
+ extern void Mat4Mult ( mat44 & A, mat44 & B, mat44 & C );
+ // Calculates A=B^{-1}*C
+ extern void Mat4Div1 ( mat44 & A, mat44 & B, mat44 & C );
+ // Calculates A=B*C^{-1}
+ extern void Mat4Div2 ( mat44 & A, mat44 & B, mat44 & C );
+ // Calculates determinant of the rotation part
+ extern realtype Mat4RotDet ( mat44 & T );
+
+ // Sets up a unit matrix
+ extern void Mat4Init ( mat44 & A );
+ extern void Mat3Init ( mat33 & A );
+
+ // Calculates AI=A^{-1}, returns determinant
+ extern realtype Mat3Inverse ( mat33 & A, mat33 & AI );
+
+ extern bool isMat4Unit ( mat44 & A, realtype eps, bool rotOnly );
+
+ // Copies A into AC
+ extern void Mat4Copy ( mat44 & A, mat44 & ACopy );
+ extern void Mat3Copy ( mat33 & A, mat33 & ACopy );
+ extern bool isMat4Eq ( mat44 & A, mat44 & B, realtype eps,
+ bool rotOnly );
+
+ extern void TransformXYZ ( mat44 & T,
+ realtype & X, realtype & Y, realtype & Z );
+ extern realtype TransformX ( mat44 & T,
+ realtype X, realtype Y, realtype Z );
+ extern realtype TransformY ( mat44 & T,
+ realtype X, realtype Y, realtype Z );
+ extern realtype TransformZ ( mat44 & T,
+ realtype X, realtype Y, realtype Z );
+
+
+ extern char CIFErrorLocation[200];
+
+ // Returns ASCII string explaining the nature of
+ // Error_xxxx error code.
+ extern cpstr GetErrorDescription ( ERROR_CODE ErrorCode );
+
+
+
+ // ================ ContainerClass ====================
+
+ DefineClass(ContainerClass);
+ DefineStreamFunctions(ContainerClass);
+
+ class ContainerClass : public io::Stream {
+
+ friend class ClassContainer;
+
+ public :
+
+ ContainerClass ();
+ ContainerClass ( io::RPStream Object );
+ ~ContainerClass() {}
+
+ // ConvertPDBASCII(..) will return one of the Error_XXXXX
+ // constants, see <mmdb_defs.h>
+ virtual ERROR_CODE ConvertPDBASCII ( cpstr )
+ { return Error_NoError; }
+ virtual void PDBASCIIDump ( pstr, int ) {}
+ virtual bool PDBASCIIDump1 ( io::RFile ) { return false; }
+ virtual void MakeCIF ( mmcif::PData, int ) {}
+
+ // Append(..) should return true if CC is appended to this class.
+ // If this is not the case, CC is merely put on the top of
+ // container.
+ // Note: Append(..) detects the necessity to append CC and
+ // performs all the necessary actions for that. The rest of CC
+ // will be disposed by Class Container.
+ // Note: Class Container checks every new class, which is
+ // being added to it (see CClassContainer::AddData(..)), only
+ // against the top of container.
+ virtual bool Append ( PContainerClass CC );
+
+ // GetCIF(..) extracts any necessary information from CIF and
+ // returns in Signal:
+ // Error_noError : the information was successfully extracted,
+ // this instance of container class should be
+ // stored, and unchanged value of Signal should
+ // be passed to the next (newly created) instance
+ // of this container class.
+ // Error_EmptyCIF : there is no information for this type of
+ // containers to extract. This instance of
+ // container class should be deleted and input
+ // for this type of container class terminated.
+ // Other : the corresponding error. This instance of
+ // container class should be deleted and the
+ // whole input stopped.
+ virtual ERROR_CODE GetCIF ( mmcif::PData, int & n )
+ { n = -1; return Error_EmptyCIF; }
+ virtual CLASS_ID GetClassID () { return ClassID_Template; }
+
+ virtual void Copy ( PContainerClass ) {}
+
+ void write ( io::RFile ) {}
+ void read ( io::RFile ) {}
+
+ protected :
+ int ContinuationNo;
+
+ };
+
+
+ // ======================== ContString =========================
+
+ DefineClass(ContString);
+ DefineStreamFunctions(ContString);
+
+ class ContString : public ContainerClass {
+
+ public :
+
+ pstr Line; // a string
+
+ ContString ();
+ ContString ( cpstr S );
+ ContString ( io::RPStream Object );
+ ~ContString();
+
+ ERROR_CODE ConvertPDBASCII ( cpstr S );
+ void PDBASCIIDump ( pstr S, int N );
+ bool PDBASCIIDump1 ( io::RFile f );
+ void MakeCIF ( mmcif::PData CIF, int N );
+// void GetCIF1 ( mmcif::PData CIF, ERROR_CODE & Signal,
+// int & pos );
+ bool Append ( PContainerClass ContString );
+ CLASS_ID GetClassID () { return ClassID_String; }
+
+ void Copy ( PContainerClass CString );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ pstr CIFCategory,CIFTag;
+
+ void InitString();
+
+ };
+
+
+ // ============== ClassContainer ====================
+
+ DefineClass(ClassContainer);
+ DefineStreamFunctions(ClassContainer);
+
+ class ClassContainer : public io::Stream {
+
+ public :
+
+ ClassContainer ();
+ ClassContainer ( io::RPStream Object );
+ ~ClassContainer ();
+
+ void FreeContainer ();
+ void AddData ( PContainerClass Data );
+ virtual void PDBASCIIDump ( io::RFile f );
+ virtual void MakeCIF ( mmcif::PData CIF );
+ // GetCIF(..) will return one of the Error_XXXXX constants,
+ // see <mmdb_defs.h>
+ virtual ERROR_CODE GetCIF ( mmcif::PData CIF, int ClassID );
+ virtual PContainerClass MakeContainerClass ( int ClassID );
+
+ // Copy will empty the class if parameter is set to NULL
+ virtual void Copy ( PClassContainer CContainer );
+
+ inline int Length() { return length; }
+ PContainerClass GetContainerClass ( int ContClassNo );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ int length;
+ PPContainerClass Container;
+
+ void Init();
+
+ };
+
+
+ // ====================== ID parsers ==========================
+
+ DefineClass(AtomPath);
+ DefineStreamFunctions(AtomPath);
+
+ enum APATH_FLAG {
+ APATH_ModelNo = 0x00000001,
+ APATH_ChainID = 0x00000002,
+ APATH_SeqNum = 0x00000004,
+ APATH_InsCode = 0x00000008,
+ APATH_ResName = 0x00000010,
+ APATH_AtomName = 0x00000020,
+ APATH_Element = 0x00000040,
+ APATH_AltLoc = 0x00000080,
+ APATH_Incomplete = 0x00000100,
+ APATH_WC_ModelNo = 0x00001000,
+ APATH_WC_ChainID = 0x00002000,
+ APATH_WC_SeqNum = 0x00004000,
+ APATH_WC_InsCode = 0x00008000,
+ APATH_WC_ResName = 0x00010000,
+ APATH_WC_AtomName = 0x00020000,
+ APATH_WC_Element = 0x00040000,
+ APATH_WC_AltLoc = 0x00080000
+ };
+
+ class AtomPath : public io::Stream {
+
+ public :
+
+ int modelNo;
+ ChainID chainID;
+ int seqNum;
+ InsCode insCode;
+ ResName resName;
+ AtomName atomName;
+ Element element;
+ AltLoc altLoc;
+ int isSet;
+
+ AtomPath ();
+ AtomPath ( cpstr ID );
+ AtomPath ( io::RPStream Object );
+ ~AtomPath ();
+
+ // SetPath(..) parses the Atom Path ID string, which
+ // may be incomplete. Below {..} means blocks that
+ // may be omitted; any elements within such blocks
+ // may be omitted as well.
+ //
+ // 1. If ID starts with '/' then the ID must be of
+ // the following form:
+ // /mdl{/chn{/seq(res).i{/atm[elm]:a}}}
+ //
+ // 2. If ID starts with a letter:
+ // chn{/seq(res).i{/atm[elm]:a}}
+ //
+ // 3. If ID starts with a number or '(':
+ // seq(res).i{/atm[elm]:a}
+ //
+ // 4. If ID contains colon ':' or '[' then
+ // it may be just
+ // atm[elm]:a
+ //
+ // The following are valid samples of IDs:
+ //
+ // /1 model number 1
+ // /1/A/23(GLU).A/CA[C]:A model number 1, chain A,
+ // residue 23 GLU insertion code A, C-alpha
+ // atom in alternative location A
+ // A/23 residue 23 of chain A
+ // CA[C]: atom C-alpha
+ // [C] a carbon
+ // *[C]:* same as above
+ // :A an atom with insertion code A
+ // 5 residue number 5
+ // (GLU) residue GLU
+ //
+ // All spaces are ignored. SetPath(..) sets bit of isSet
+ // for each element present. Any element may be a wildcard
+ // '*'. Wildcard for model will set modelNo=0, for sequence
+ // number will set seqNum=MinInt4.
+ //
+ // Returns:
+ // 0 <-> Ok
+ // -1 <-> wrong numerical format for model
+ // -2 <-> wrong numerical format for sequence number
+ int SetPath ( cpstr ID );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected :
+ void InitAtomPath();
+
+ };
+
+
+ // --------------------------------------------------------------
+
+ DefineClass(QuickSort);
+
+ class QuickSort : public io::Stream {
+
+ public :
+ QuickSort ();
+ QuickSort ( io::RPStream Object );
+ ~QuickSort() {}
+ virtual int Compare ( int i, int j );
+ virtual void Swap ( int i, int j );
+ void Sort ( void * sortdata, int data_len );
+
+ protected :
+ int selSortLimit,dlen;
+ void * data;
+
+ void SelectionSort ( int left, int right );
+ int Partition ( int left, int right );
+ void Quicksort ( int left, int right );
+
+ };
+
+
+ // --------------------------------------------------------------
+
+ extern void takeWord ( pstr & p, pstr wrd, cpstr ter, int l );
+
+ // ParseAtomID(..) reads the atom ID of the following form:
+ // {name} {[element]} {:altcode}
+ // (here {} means that the item may be omitted; any field may have
+ // value of wildcard '*'), and returns the atom name in aname,
+ // element name - in elname, and alternate location code - in aloc.
+ // Except for the alternate location code, missing items are
+ // replaced by wildcards. Missing alternate location code is
+ // returned as empty string "".
+ // Leading spaces are allowed; any other space will terminate
+ // the parsing.
+ // The followings are perfectly valid atom IDs:
+ // CA[C]:A (carbon C_alpha in location A)
+ // CA[*]:A (either C_alpha or Ca in location A)
+ // CA:A (same as above)
+ // CA (either C_alpha or Ca with no location indicator)
+ // CA[] (same as above)
+ // CA[C]: (C_alpha with no location indicator)
+ // [C] (any carbon with no location indicator)
+ // [C]:* (any carbon with any location indicator)
+ // *[C]:* (same as above)
+ // :A (any atom in location A)
+ // *[*]:A (same as above)
+ // *[*]:* (any atom)
+ // * (any atom with no alternate location indicator)
+ extern void ParseAtomID ( cpstr ID, AtomName aname,
+ Element elname, AltLoc aloc );
+
+ // ParseResID(..) reads the residue ID of the following form:
+ // {seqnum} {(name)} {.inscode}
+ // (here {} means that the item may be omitted; any field may have
+ // value of wildcard '*'), and returns the sequence number in sn,
+ // insertion code - in inscode, and residue name - in resname.
+ // If a wildcard was specified for the sequence number, then
+ // ParseResID(..) returns 1. Missing residue name is replaced by
+ // the wildcard '*', and misisng insertion code is returned as empty
+ // string "".
+ // Leading spaces are allowed; any other space will terminate
+ // the parsing.
+ // Return 0 means Ok, 1 - wildcard for the sequence number,
+ // 2 - an error in numerical format of the sequence number
+ // (other items are parsed).
+ // The followings are perfectly valid residue IDs:
+ // 27(ALA).A (residue 27A ALA)
+ // 27().A (residue 27A)
+ // 27(*).A (same as above)
+ // 27.A (same as above)
+ // 27 (residue 27)
+ // 27(). (same as above)
+ // (ALA) (any ALA without insertion code)
+ // (ALA). (same as above)
+ // (ALA).* (any ALA)
+ // *(ALA).* (any ALA)
+ // .A (any residue with insertion code A)
+ // *(*).A (same as above)
+ // *(*).* (any residue)
+ // * (any residue with no insertion code)
+ extern int ParseResID ( cpstr ID, int & sn,
+ InsCode inscode, ResName resname );
+
+
+ // ParseAtomPath(..) parses an atom path string of the following
+ // structure:
+ // /mdl/chn/seq(res).i/atm[elm]:a
+ // where all items may be represented by a wildcard '*' and
+ // mdl - model number (mandatory); at least model #1 is always
+ // present; returned in mdl; on a wildcard mdl is set to 0
+ // chn - chain identifier ( mandatory); returned in chn; on a
+ // wildcard chn is set to '*'
+ // seq - residue sequence number (mandatory); returned in sn;
+ // on a wild card ParseAtomPath(..) returns 1
+ // (res) - residue name in round brackets (may be omitted);
+ // returnded in res; on a wildcard res is set to '*'
+ // .i - insert code after a dot; if '.i' or 'i' is missing
+ // then a residue without an insertion code is looked for;
+ // returned in ic; on a wildcard (any insertion code would
+ // do) ic is set to '*'
+ // atm - atom name (mandatory); returned in atm; on a wildcard
+ // atm is set to '*'
+ // [elm] - chemical element code in square brackets; it may
+ // be omitted but could be helpful for e.g.
+ // distinguishing C_alpha and CA; returned in elm;
+ // in a wildcard elm is set to '*'
+ // :a - alternate location indicator after colon; if
+ // ':a' or 'a' is missing then an atom without
+ // alternate location indicator is looked for; returned
+ // in aloc; on a wildcard (any alternate code would do)
+ // aloc is set to '*'.
+ // All spaces are ignored, all identifiers should be in capital
+ // letters (comparisons are case-sensitive).
+ // The atom path string may be incomplete. If DefPath is supplied,
+ // the function will try to get missing elements from there. If
+ // missing items may not be found in DefPath, they are replaced by
+ // wildcards.
+ // ParseAtomPath(..) returns the following bits:
+ // 0 - Ok
+ // APATH_Incomplete - if path contains wildcards. Wildcards for
+ // residue name and chemical element will be
+ // ignored here if sequence number and
+ // atom name, correspondingly, are provided.
+ // APATH_WC_XXXXX - wildcard for different elements
+ // -1 - wrong numerical format for model (fatal)
+ // -2 - wrong numerical format for seqNum (fatal)
+
+ extern int ParseAtomPath ( cpstr ID,
+ int & mdl,
+ ChainID chn,
+ int & sn,
+ InsCode ic,
+ ResName res,
+ AtomName atm,
+ Element elm,
+ AltLoc aloc,
+ PAtomPath DefPath=NULL );
+
+
+
+ extern int ParseSelectionPath ( cpstr CID,
+ int & iModel,
+ pstr Chains,
+ int & sNum1,
+ InsCode ic1,
+ int & sNum2,
+ InsCode ic2,
+ pstr RNames,
+ pstr ANames,
+ pstr Elements,
+ pstr altLocs );
+
+
+
+ extern void MakeSelectionPath ( pstr CID,
+ int iModel,
+ cpstr Chains,
+ int sNum1,
+ const InsCode ic1,
+ int sNum2,
+ const InsCode ic2,
+ cpstr RNames,
+ cpstr ANames,
+ cpstr Elements,
+ cpstr altLocs );
+
+} // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_xml_.cpp b/mmdb2/mmdb_xml_.cpp
new file mode 100644
index 0000000..da0c532
--- /dev/null
+++ b/mmdb2/mmdb_xml_.cpp
@@ -0,0 +1,986 @@
+// $Id: mmdb_xml_.cpp $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 06.12.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_XML <implementation>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::xml::XMLObject
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mmdb_xml_.h"
+
+namespace mmdb {
+
+ namespace xml {
+
+ // ====================== XMLObject ==========================
+
+ XMLObject::XMLObject() : io::Stream() {
+ InitXMLObject();
+ }
+
+ XMLObject::XMLObject ( cpstr Tag ) : io::Stream() {
+ InitXMLObject();
+ SetTag ( Tag );
+ }
+
+ XMLObject::XMLObject ( cpstr Tag, cpstr Data ) : io::Stream() {
+ InitXMLObject();
+ SetTag ( Tag );
+ SetData ( Data );
+ }
+
+ XMLObject::XMLObject ( cpstr Tag, realtype V, int length )
+ : io::Stream() {
+ InitXMLObject();
+ SetTag ( Tag );
+ SetData ( V,length );
+ }
+
+ XMLObject::XMLObject ( cpstr Tag, int iV, int length )
+ : io::Stream() {
+ InitXMLObject();
+ SetTag ( Tag );
+ SetData ( iV,length );
+ }
+
+ XMLObject::XMLObject ( cpstr Tag, bool bV ) : io::Stream() {
+ InitXMLObject();
+ SetTag ( Tag );
+ SetData ( bV );
+ }
+
+ XMLObject::XMLObject ( cpstr Tag, PXMLObject XMLObject )
+ : io::Stream() {
+ InitXMLObject();
+ SetTag ( Tag );
+ AddObject ( XMLObject );
+ }
+
+
+ XMLObject::XMLObject ( io::RPStream Object ) : io::Stream(Object) {
+ InitXMLObject();
+ }
+
+ XMLObject::~XMLObject() {
+ FreeMemory();
+ }
+
+ void XMLObject::InitXMLObject() {
+ parent = NULL;
+ objTag = NULL;
+ objData = NULL;
+ nObjects = 0;
+ nAlloc = 0;
+ object = NULL;
+ nAttributes = 0;
+ nAttrAlloc = 0;
+ attr_name = NULL;
+ attr_value = NULL;
+ }
+
+ void XMLObject::FreeMemory() {
+ int i;
+
+ if (objTag) delete[] objTag;
+ if (objData) delete[] objData;
+
+ objTag = NULL;
+ objData = NULL;
+
+ if (object) {
+ for (i=0;i<nAlloc;i++)
+ if (object[i]) delete object[i];
+ delete[] object;
+ }
+
+ nObjects = 0;
+ nAlloc = 0;
+ object = NULL;
+
+ if (attr_name) {
+ for (i=0;i<nAttrAlloc;i++) {
+ if (attr_name [i]) delete[] attr_name [i];
+ if (attr_value[i]) delete[] attr_value[i];
+ }
+ FreeVectorMemory ( attr_name ,0 );
+ FreeVectorMemory ( attr_value,0 );
+ }
+
+ nAttributes = 0;
+ nAttrAlloc = 0;
+ attr_name = NULL;
+ attr_value = NULL;
+
+ }
+
+ void XMLObject::SetTag ( cpstr Tag ) {
+ pstr p,t;
+ int n;
+
+ // count ampersands
+ p = pstr(Tag);
+ n = 0;
+ while (*p) {
+ if (*p=='&') n++;
+ p++;
+ }
+ // calculate the tag length
+ n = n*4 + strlen(Tag) + 1;
+ // substract leading underscores
+ p = pstr(Tag);
+ while (*p=='_') {
+ p++;
+ n--;
+ }
+ // allocate tag space
+ if (objTag) delete[] objTag;
+ objTag = new char[n];
+ // copy tag, replacing square brackets and ampersands
+ t = objTag;
+ while (*p) {
+ if (*p=='[') {
+ *t = '-';
+ t++;
+ } else if (*p==']') {
+ if ((p[1]) && (p[1]!='[')) {
+ *t = '-';
+ t++;
+ }
+ } else if (*p=='&') {
+ strcpy ( t,"_and_" );
+ if (p[1]) t += 5;
+ else t += 4;
+ } else {
+ *t = *p;
+ t++;
+ }
+ p++;
+ }
+ *t = char(0);
+ }
+
+ void XMLObject::AddAttribute ( cpstr name, cpstr value ) {
+ psvector an,av;
+ int i;
+
+ if (nAttributes>=nAttrAlloc) {
+ nAttrAlloc = nAttributes + 10;
+ GetVectorMemory ( an,nAttrAlloc,0 );
+ GetVectorMemory ( av,nAttrAlloc,0 );
+ for (i=0;i<nAttrAlloc;i++) {
+ an[i] = NULL;
+ av[i] = NULL;
+ }
+ for (i=0;i<nAttributes;i++) {
+ CreateCopy ( an[i],attr_name [i] );
+ CreateCopy ( av[i],attr_value[i] );
+ if (attr_name [i]) delete[] attr_name [i];
+ if (attr_value[i]) delete[] attr_value[i];
+ }
+ FreeVectorMemory ( attr_name ,0 );
+ FreeVectorMemory ( attr_value,0 );
+ attr_name = an;
+ attr_value = av;
+ }
+
+ CreateCopy ( attr_name [nAttributes],name );
+ CreateCopy ( attr_value[nAttributes],value );
+ nAttributes++;
+
+ }
+
+ void XMLObject::AddAttribute ( cpstr name, const int iV ) {
+ char S[100];
+ sprintf ( S,"%i",iV );
+ AddAttribute ( name,S );
+ }
+
+ void XMLObject::AddAttribute ( cpstr name, const bool bV ) {
+ if (bV) AddAttribute ( name,"Yes" );
+ else AddAttribute ( name,"No" );
+ }
+
+ void XMLObject::SetData ( cpstr Data ) {
+ pstr p,d;
+ int n;
+ // count ampersands
+ p = pstr(Data);
+ n = 0;
+ while (*p) {
+ if (*p=='&') n += 4;
+ p++;
+ }
+ // calculate the Data length
+ n += strlen(Data) + 1; // eugene
+ // allocate data space
+ if (objData) delete[] objData;
+ objData = new char[n];
+ // copy data, preceeding ampersands with the escape
+ p = pstr(Data);
+ d = objData;
+ while (*p) {
+ if (*p=='&') {
+ d[0] = '&';
+ d[1] = 'a';
+ d[2] = 'm';
+ d[3] = 'p';
+ d[4] = ';';
+ d += 5;
+ } else {
+ *d = *p;
+ d++;
+ }
+ p++;
+ }
+ *d = char(0);
+ }
+
+ void XMLObject::AddData ( cpstr Data ) {
+ pstr d1,d2;
+ d1 = objData;
+ objData = NULL;
+ SetData ( Data );
+ d2 = objData;
+ objData = NULL;
+ CreateConcat ( objData,d1,d2 );
+ }
+
+ void XMLObject::SetData ( const realtype V, const int length ) {
+ char N[500];
+ sprintf ( N,"%-.*g",length,V );
+ CreateCopy ( objData,N );
+ }
+
+ void XMLObject::SetData ( const int iV, const int length ) {
+ char N[500];
+ sprintf ( N,"%*i",length,iV );
+ CreateCopy ( objData,N );
+ }
+
+ void XMLObject::SetData ( const bool bV ) {
+ if (bV) CreateCopy ( objData,pstr("Yes") );
+ else CreateCopy ( objData,pstr("No") );
+ }
+
+
+ int XMLObject::AddMMCIFCategory ( mmcif::PCategory mmCIFCat ) {
+ if (mmCIFCat->GetCategoryID()==mmcif::MMCIF_Loop)
+ return AddMMCIFLoop ( mmcif::PLoop(mmCIFCat) );
+ if (mmCIFCat->GetCategoryID()==mmcif::MMCIF_Struct)
+ return AddMMCIFStruct ( mmcif::PStruct(mmCIFCat) );
+ return -1;
+ }
+
+ pstr getCCIFTag ( pstr & ccifTag, cpstr Tag ) {
+ if (Tag[0]=='_') return CreateCopCat ( ccifTag,pstr("ccif") ,Tag );
+ else return CreateCopCat ( ccifTag,pstr("ccif_"),Tag );
+ }
+
+ int XMLObject::AddMMCIFStruct ( mmcif::PStruct mmCIFStruct ) {
+ PXMLObject XMLObject1,XMLObject2;
+ pstr SName,Tag,Field, ccifTag;
+ int nTags,i,k;
+
+ XMLObject1 = this;
+
+ ccifTag = NULL;
+
+ SName = mmCIFStruct->GetCategoryName();
+ if (SName) {
+ if (SName[0]!=char(1))
+ XMLObject1 = new XMLObject ( getCCIFTag(ccifTag,SName) );
+ }
+
+ k = 0;
+ nTags = mmCIFStruct->GetNofTags();
+ for (i=0;i<nTags;i++) {
+ Tag = mmCIFStruct->GetTag ( i );
+ if (Tag) {
+ XMLObject2 = new XMLObject ( getCCIFTag(ccifTag,Tag) );
+ Field = mmCIFStruct->GetField ( i );
+ if (Field) {
+ if (Field[0]!=char(2)) XMLObject2->SetData ( Field );
+ else XMLObject2->SetData ( &(Field[1]) );
+ }
+ XMLObject1->AddObject ( XMLObject2 );
+ k++;
+ }
+ }
+
+ if (SName) {
+ if (SName[0]!=char(1))
+ AddObject ( XMLObject1 );
+ }
+
+ if (ccifTag) delete[] ccifTag;
+
+ return k;
+
+ }
+
+ int XMLObject::AddMMCIFLoop ( mmcif::PLoop mmCIFLoop ) {
+ PXMLObject XMLObject1,XMLObject2,XMLObject3;
+ pstr SName,Tag,Field,ccifTag;
+ int nTags,nRows,i,j,k;
+
+ XMLObject1 = this;
+
+ ccifTag = NULL;
+
+ SName = mmCIFLoop->GetCategoryName();
+ if (SName) {
+ if (SName[0]!=char(1))
+ XMLObject1 = new XMLObject ( getCCIFTag(ccifTag,SName) );
+ }
+
+ k = 0;
+ nTags = mmCIFLoop->GetNofTags ();
+ nRows = mmCIFLoop->GetLoopLength();
+ for (i=0;i<nRows;i++) {
+ XMLObject2 = new XMLObject ( pstr("row"),
+ new XMLObject(pstr("_sernum_"),i+1) );
+ for (j=0;j<nTags;j++) {
+ Tag = mmCIFLoop->GetTag ( j );
+ if (Tag) {
+ XMLObject3 = new XMLObject ( getCCIFTag(ccifTag,Tag) );
+ Field = mmCIFLoop->GetField ( i,j );
+ if (Field) {
+ if (Field[0]!=char(2)) XMLObject3->SetData ( Field );
+ else XMLObject3->SetData ( &(Field[1]) );
+ }
+ XMLObject2->AddObject ( XMLObject3 );
+ k++;
+ }
+ }
+ XMLObject1->AddObject ( XMLObject2 );
+ }
+
+ if (SName) {
+ if (SName[0]!=char(1))
+ AddObject ( XMLObject1 );
+ }
+
+ if (ccifTag) delete[] ccifTag;
+
+ return k;
+
+ }
+
+ int XMLObject::AddMMCIFData ( mmcif::PData mmCIFData ) {
+ mmcif::PCategory mmCIFCat;
+ int nCats,i,k,n;
+ nCats = mmCIFData->GetNumberOfCategories();
+ k = 0;
+ n = 0;
+ for (i=0;(i<nCats) && (n>=0);i++) {
+ mmCIFCat = mmCIFData->GetCategory ( i );
+ if (mmCIFCat) {
+ if (mmCIFCat->GetCategoryID()==mmcif::MMCIF_Loop)
+ n = AddMMCIFLoop ( mmcif::PLoop(mmCIFCat) );
+ else if (mmCIFCat->GetCategoryID()==mmcif::MMCIF_Struct)
+ n = AddMMCIFStruct ( mmcif::PStruct(mmCIFCat) );
+ else
+ n = -1;
+ if (n>=0) k += n;
+ }
+ }
+ if (n<0) return -(k+1);
+ return k;
+ }
+
+ pstr XMLObject::GetData ( cpstr Tag, int objNo ) {
+ PXMLObject XMLObject;
+ XMLObject = GetObject ( Tag,objNo );
+ if (XMLObject) return XMLObject->objData;
+ return NULL;
+ }
+
+ XML_RC XMLObject::GetData ( pstr & Data, cpstr Tag, int objNo ) {
+ PXMLObject XMLObject;
+ XMLObject = GetObject ( Tag,objNo );
+ if (XMLObject) {
+ Data = XMLObject->objData;
+ return XMLRC_Ok;
+ } else {
+ Data = NULL;
+ return XMLRC_NoTag;
+ }
+ }
+
+ XML_RC XMLObject::GetData ( realtype & V, cpstr Tag, int objNo ) {
+ pstr d,p;
+ XML_RC rc;
+ rc = GetData ( d,Tag,objNo );
+ if (d) {
+ V = strtod(d,&p);
+ if ((V==0.0) && (p==d)) rc = XMLRC_RFormatError;
+ else rc = XMLRC_Ok;
+ } else if (!rc)
+ rc = XMLRC_NoTag;
+ return rc;
+ }
+
+ XML_RC XMLObject::GetData ( int & iV, cpstr Tag, int objNo ) {
+ pstr d,p;
+ XML_RC rc;
+ rc = GetData ( d,Tag,objNo );
+ if (d) {
+ iV = mround(strtod(d,&p));
+ if ((iV==0) && (p==d)) rc = XMLRC_IFormatError;
+ else rc = XMLRC_Ok;
+ } else if (!rc)
+ rc = XMLRC_NoTag;
+ return rc;
+ }
+
+ XML_RC XMLObject::GetData ( bool & bV, cpstr Tag, int objNo ) {
+ pstr d;
+ XML_RC rc;
+ rc = GetData ( d,Tag,objNo );
+ if (d) {
+ if (!strcasecmp(d,"Yes"))
+ bV = true;
+ else {
+ bV = false;
+ if (strcasecmp(d,"No")) rc = XMLRC_OFormatError;
+ }
+ } else if (rc==XMLRC_Ok)
+ rc = XMLRC_NoTag;
+ return rc;
+ }
+
+ PXMLObject XMLObject::GetObject ( cpstr Tag, int objNo ) {
+ // allow for "tag1>tag2>tag3>..."
+ PXMLObject XMLObject;
+ pstr p,p1;
+ int i,j,k,l;
+ XMLObject = this;
+ if (Tag) {
+ p = pstr(Tag);
+ do {
+ p1 = p;
+ l = 0;
+ while (*p1 && (*p1!='>')) {
+ p1++;
+ l++;
+ }
+ if (l>0) {
+ k = -1;
+ j = 0;
+ for (i=0;(i<XMLObject->nObjects) && (k<0);i++)
+ if (XMLObject->object[i]) {
+ if (!strncmp(XMLObject->object[i]->objTag,p,l)) {
+ j++;
+ if (j==objNo) k = i;
+ }
+ }
+ if (k<0) {
+ XMLObject = NULL;
+ l = 0;
+ } else {
+ XMLObject = XMLObject->object[k];
+ if (*p1) p = p1 + 1;
+ else l = 0;
+ }
+ }
+ } while (l>0);
+ }
+ return XMLObject;
+ }
+
+ PXMLObject XMLObject::GetFirstObject() {
+ if (nObjects>0) return object[0];
+ return NULL;
+ }
+
+ PXMLObject XMLObject::GetLastObject() {
+ if (nObjects>0) return object[nObjects-1];
+ return NULL;
+ }
+
+ PXMLObject XMLObject::GetObject ( int objectNo ) {
+ if ((0<=objectNo) && (objectNo<nObjects))
+ return object[objectNo];
+ return NULL;
+ }
+
+ void XMLObject::AddObject ( PXMLObject XMLObject, int lenInc ) {
+ PPXMLObject obj1;
+ int i;
+
+ if (!XMLObject) return;
+
+ if (nObjects>=nAlloc) {
+ nAlloc += lenInc;
+ obj1 = new PXMLObject[nAlloc];
+ for (i=0;i<nObjects;i++)
+ obj1[i] = object[i];
+ for (i=nObjects;i<nAlloc;i++)
+ obj1[i] = NULL;
+ if (object) delete[] object;
+ object = obj1;
+ }
+
+ if (object[nObjects]) delete object[nObjects];
+ object[nObjects] = XMLObject;
+ XMLObject->SetParent ( this );
+ nObjects++;
+
+ }
+
+
+ void XMLObject::InsertObject ( PXMLObject XMLObject, int pos,
+ int lenInc ) {
+ PPXMLObject obj1;
+ int i;
+
+ if (!XMLObject) return;
+ if (pos>=nObjects) {
+ AddObject ( XMLObject,lenInc );
+ return;
+ }
+
+ if (nObjects>=nAlloc) {
+ nAlloc += lenInc;
+ obj1 = new PXMLObject[nAlloc];
+ for (i=0;i<nObjects;i++)
+ obj1[i] = object[i];
+ for (i=nObjects;i<nAlloc;i++)
+ obj1[i] = NULL;
+ if (object) delete[] object;
+ object = obj1;
+ }
+
+ for (i=nObjects;i>pos;i--)
+ object[i] = object[i-1];
+
+ object[pos] = XMLObject;
+ XMLObject->SetParent ( this );
+ nObjects++;
+
+ }
+
+ XML_RC XMLObject::WriteObject ( cpstr FName, int pos, int indent ) {
+ io::File f;
+ f.assign ( FName,true );
+ if (f.rewrite()) {
+ WriteObject ( f,pos,indent );
+ f.shut();
+ return XMLRC_Ok;
+ }
+ return XMLRC_CantOpenFile;
+ }
+
+ void XMLObject::WriteObject ( io::RFile f, int pos, int indent ) {
+ int i,pos1,lm,rm,tl;
+ pstr indstr,p,p1,q;
+ bool sngline;
+
+ if (objTag) {
+
+ pos1 = pos + indent;
+ indstr = new char[pos1+1];
+ for (i=0;i<pos1;i++) indstr[i] = ' ';
+ indstr[pos1] = char(0);
+
+ indstr[pos] = char(0);
+ f.Write ( indstr );
+ f.Write ( pstr("<") );
+ f.Write ( objTag );
+ for (i=0;i<nAttributes;i++) {
+ f.Write ( " " );
+ f.Write ( attr_name[i] );
+ f.Write ( "=\"" );
+ f.Write ( attr_value[i] );
+ f.Write ( "\"" );
+ }
+ if ((!objData) && (nObjects<=0)) {
+ f.WriteLine ( pstr("/>") );
+ delete[] indstr;
+ return;
+ }
+ f.Write ( pstr(">") );
+
+ sngline = false;
+ if (objData) {
+ rm = 72; // right margin
+ lm = IMin ( pos1,36 ); // left margin
+ tl = strlen(objTag);
+ if ((pos+tl+2+(int)strlen(objData)<rm-tl-2) &&
+ (nObjects<=0)) {
+ // single-line output
+ sngline = true;
+ f.Write ( objData );
+ } else {
+ // multiple-line output with indentation
+ indstr[pos] = ' ';
+ indstr[lm] = char(0);
+ f.LF();
+ p = objData;
+ do {
+ p1 = p;
+ i = lm;
+ q = NULL;
+ while ((*p1) && ((i<rm) || (!q))) {
+ if (*p1==' ') q = p1;
+ p1++;
+ i++;
+ }
+ f.Write ( indstr );
+ if (*p1) { // wrap data
+ *q = char(0);
+ f.WriteLine ( p );
+ *q = ' ';
+ p = q;
+ while (*p==' ') p++;
+ if (*p==char(0)) p = NULL;
+
+ } else { // data exchausted
+ f.WriteLine ( p );
+ p = NULL;
+ }
+ } while (p);
+ indstr[lm] = ' ';
+ indstr[pos] = char(0);
+ }
+ } else
+ f.LF();
+
+ for (i=0;i<nObjects;i++)
+ if (object[i])
+ object[i]->WriteObject ( f,pos+indent,indent );
+
+ if (!sngline) f.Write ( indstr );
+ f.Write ( pstr("</") );
+ f.Write ( objTag );
+ f.WriteLine ( pstr(">") );
+
+ delete[] indstr;
+
+ }
+
+ }
+
+
+ XML_RC XMLObject::ReadObject ( cpstr FName ) {
+ io::File f;
+ char S[500];
+ int i;
+ XML_RC rc;
+
+ f.assign ( FName,true );
+ if (f.reset(true)) {
+ S[0] = char(0);
+ i = 0;
+ rc = ReadObject ( f,S,i,sizeof(S) );
+ f.shut();
+ } else
+ rc = XMLRC_NoFile;
+
+ if (rc!=XMLRC_Ok) FreeMemory();
+
+ return rc;
+
+ }
+
+ XML_RC XMLObject::ReadObject ( io::RFile f, pstr S,
+ int & pos, int slen ) {
+ PXMLObject xmlObject;
+ pstr S1;
+ int k,k1,k2;
+ XML_RC rc;
+ bool Done;
+
+ FreeMemory();
+
+ rc = XMLRC_Ok;
+
+ k1 = -1;
+ k2 = -1;
+ while ((!f.FileEnd()) && (k1<0)) {
+ k = strlen(S);
+ while ((pos<k) && (k1<0))
+ if (S[pos]=='<') {
+ if (S[pos+1]=='?') // in this version, ignore <?xxx ?>
+ // constructions
+ pos++;
+ else if (S[pos+1]!='<')
+ k1 = pos;
+ else pos += 2;
+ } else
+ pos++;
+ if (k1>=0) {
+ k2 = -1;
+ while ((pos<k) && (k2<0))
+ if (S[pos]=='>') {
+ if (S[pos+1]!='>') k2 = pos;
+ else pos += 2;
+ } else
+ pos++;
+ if (k2<0) rc = XMLRC_BrokenTag;
+ }
+ if (k1<0) {
+ f.ReadLine ( S,slen );
+ pos = 0;
+ }
+ }
+
+ if (k1<0) return XMLRC_NoTag;
+ if (rc!=XMLRC_Ok) return rc;
+
+ pos++;
+ if (S[k2-1]=='/') { // <Tag/>
+ S[k2-1] = char(0);
+ CreateCopy ( objTag,&(S[k1+1]) );
+ return XMLRC_Ok;
+ }
+
+ S[k2] = char(0);
+ CreateCopy ( objTag,&(S[k1+1]) );
+ S[k2] = '>';
+
+ S1 = new char[slen+1];
+ Done = false;
+ while ((!f.FileEnd()) && (!Done)) {
+ k = strlen(S);
+ while ((pos<k) && (!Done)) {
+ k1 = pos;
+ k2 = -1;
+ while ((pos<k) && (k2<0))
+ if (S[pos]=='<') {
+ if (S[pos+1]!='<') k2 = pos;
+ else pos +=2;
+ } else
+ pos++;
+ if (k2>=0) S[k2] = char(0);
+ strcpy_des ( S1,&(S[k1]) );
+ if (S1[0]) {
+ if (objData) CreateConcat ( objData,pstr(" "),S1 );
+ else CreateConcat ( objData,S1 );
+ }
+ if (k2>=0) {
+ S[k2] = '<';
+ if (S[k2+1]!='/') {
+ xmlObject = new XMLObject();
+ AddObject ( xmlObject );
+ rc = xmlObject->ReadObject ( f,S,pos,slen );
+ Done = (rc!=XMLRC_Ok);
+ } else {
+ Done = true;
+ k1 = k2+2;
+ k2 = -1;
+ while ((pos<k) && (k2<0))
+ if (S[pos]=='>') {
+ if (S[pos+1]!='>') k2 = pos;
+ else pos += 2;
+ } else
+ pos++;
+ if (k2<0)
+ rc = XMLRC_BrokenTag;
+ else {
+ S[k2] = char(0);
+ if (strcmp(objTag,&(S[k1]))) rc = XMLRC_UnclosedTag;
+ else pos++;
+ }
+ }
+ }
+ }
+ if (!Done) {
+ f.ReadLine ( S,slen );
+ pos = 0;
+ }
+ }
+
+ delete[] S1;
+
+ // this keeps pairs <tag></tag> instead of replacing them for <tag/>
+ // on output
+ if ((!objData) && (nObjects<=0))
+ CreateCopy ( objData,pstr("") );
+
+ if (rc!=XMLRC_Ok) FreeMemory();
+ return rc;
+
+ }
+
+
+ void XMLObject::Copy ( PXMLObject xmlObject ) {
+ int i;
+
+ FreeMemory();
+
+ CreateCopy ( objTag ,xmlObject->objTag );
+ CreateCopy ( objData,xmlObject->objData );
+
+ nObjects = xmlObject->nObjects;
+ nAlloc = nObjects;
+ if (nObjects>0) {
+ object = new PXMLObject[nObjects];
+ for (i=0;i<nObjects;i++)
+ if (xmlObject->object[i]) {
+ object[i] = new XMLObject();
+ object[i]->Copy ( xmlObject->object[i] );
+ } else
+ object[i] = NULL;
+ }
+
+ nAttributes = xmlObject->nAttributes;
+ nAttrAlloc = nAttributes;
+ if (nAttributes>0) {
+ GetVectorMemory ( attr_name ,nAttrAlloc,0 );
+ GetVectorMemory ( attr_value,nAttrAlloc,0 );
+ for (i=0;i<nAttributes;i++) {
+ attr_name [i] = NULL;
+ attr_value[i] = NULL;
+ CreateCopy ( attr_name [i],xmlObject->attr_name [i] );
+ CreateCopy ( attr_value[i],xmlObject->attr_value[i] );
+ }
+ }
+
+ }
+
+
+ void XMLObject::write ( io::RFile f ) {
+ int i;
+ f.CreateWrite ( objTag );
+ f.CreateWrite ( objData );
+ f.WriteInt ( &nObjects );
+ for (i=0;i<nObjects;i++)
+ StreamWrite ( f,object[i] );
+ f.WriteInt ( &nAttributes );
+ for (i=0;i<nAttributes;i++) {
+ f.CreateWrite ( attr_name [i] );
+ f.CreateWrite ( attr_value[i] );
+ }
+ }
+
+ void XMLObject::read ( io::RFile f ) {
+ int i;
+
+ FreeMemory();
+
+ f.CreateRead ( objTag );
+ f.CreateRead ( objData );
+
+ f.ReadInt ( &nObjects );
+ nAlloc = nObjects;
+ if (nObjects>0) {
+ object = new PXMLObject[nObjects];
+ for (i=0;i<nObjects;i++) {
+ object[i] = NULL;
+ StreamRead ( f,object[i] );
+ }
+ }
+
+ f.ReadInt ( &nAttributes );
+ nAttrAlloc = nAttributes;
+ if (nAttributes>0) {
+ GetVectorMemory ( attr_name ,nAttrAlloc,0 );
+ GetVectorMemory ( attr_value,nAttrAlloc,0 );
+ for (i=0;i<nAttributes;i++) {
+ attr_name [i] = NULL;
+ attr_value[i] = NULL;
+ f.CreateRead ( attr_name [i] );
+ f.CreateRead ( attr_value[i] );
+ }
+ }
+
+ }
+
+
+ MakeStreamFunctions(XMLObject)
+
+
+
+ PXMLObject mmCIF2XML ( mmcif::PData mmCIFData, int * rc ) {
+ PXMLObject xmlObject;
+ pstr dataName;
+ int k;
+ xmlObject = NULL;
+ if (rc) *rc = -2;
+ if (mmCIFData) {
+ dataName = mmCIFData->GetDataName();
+ if (dataName) {
+ if (dataName[0])
+ xmlObject = new XMLObject ( dataName );
+ }
+ if (!xmlObject)
+ xmlObject = new XMLObject ( pstr("no_data_name") );
+ k = xmlObject->AddMMCIFData ( mmCIFData );
+ if (rc) *rc = k;
+ }
+ return xmlObject;
+ }
+
+ PXMLObject mmCIF2XML ( cpstr XMLName, mmcif::PFile mmCIFFile,
+ int * rc ) {
+ PXMLObject xmlObject1,xmlObject2;
+ mmcif::PData mmCIFData;
+ int nData,i,k,rc1;
+ xmlObject1 = new XMLObject ( XMLName );
+ if (rc) *rc = -1;
+ if (mmCIFFile) {
+ nData = mmCIFFile->GetNofData();
+ k = 0;
+ rc1 = 0;
+ for (i=0;(i<nData) && (rc1>=0);i++) {
+ mmCIFData = mmCIFFile->GetCIFData ( i );
+ if (mmCIFData) {
+ xmlObject2 = mmCIF2XML ( mmCIFData,&rc1 );
+ if (xmlObject2) {
+ if (rc1>=0) {
+ xmlObject1->AddObject ( xmlObject2 );
+ k += rc1;
+ } else
+ delete xmlObject2;
+ }
+ }
+ }
+ if (rc1<0) {
+ delete xmlObject1;
+ if (rc) *rc = -2;
+ } else if (rc)
+ *rc = k;
+ }
+ return xmlObject1;
+ }
+
+
+ } // namespace xml
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_xml_.h b/mmdb2/mmdb_xml_.h
new file mode 100644
index 0000000..540334c
--- /dev/null
+++ b/mmdb2/mmdb_xml_.h
@@ -0,0 +1,162 @@
+// $Id: mmdb_xml_.h $
+// =================================================================
+//
+// CCP4 Coordinate Library: support of coordinate-related
+// functionality in protein crystallography applications.
+//
+// Copyright (C) Eugene Krissinel 2000-2013.
+//
+// This library is free software: you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License version 3, modified in accordance with the provisions
+// of the license to address the requirements of UK law.
+//
+// You should have received a copy of the modified GNU Lesser
+// General Public License along with this library. If not, copies
+// may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// =================================================================
+//
+// 06.12.13 <-- Date of Last Modification.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// -----------------------------------------------------------------
+//
+// **** Module : MMDB_XML <interface>
+// ~~~~~~~~~
+// **** Project : MacroMolecular Data Base (MMDB)
+// ~~~~~~~~~
+// **** Classes : mmdb::xml::XMLObject
+// ~~~~~~~~~
+//
+// (C) E. Krissinel 2000-2013
+//
+// =================================================================
+//
+
+#ifndef __MMDB_XML__
+#define __MMDB_XML__
+
+#include "mmdb_mmcif_.h"
+
+namespace mmdb {
+
+ namespace xml {
+
+
+ // ====================== XMLObject ==========================
+
+ enum XML_RC {
+ XMLRC_Ok = 0,
+ XMLRC_NoFile = 1,
+ XMLRC_CantOpenFile = 2,
+ XMLRC_NoTag = 3,
+ XMLRC_BrokenTag = 4,
+ XMLRC_UnclosedTag = 5,
+ XMLRC_RFormatError = 6,
+ XMLRC_IFormatError = 7,
+ XMLRC_OFormatError = 8
+ };
+
+ DefineClass(XMLObject);
+ DefineStreamFunctions(XMLObject);
+
+ class XMLObject : public io::Stream {
+
+ public :
+
+ XMLObject ();
+ XMLObject ( cpstr Tag );
+ XMLObject ( cpstr Tag, cpstr Data );
+ XMLObject ( cpstr Tag, realtype V, int length=11 );
+ XMLObject ( cpstr Tag, int iV, int length=0 );
+ XMLObject ( cpstr Tag, bool bV );
+ XMLObject ( cpstr Tag, PXMLObject XMLObject );
+ XMLObject ( io::RPStream Object );
+ ~XMLObject();
+
+ void SetTag ( cpstr Tag );
+ void AddAttribute ( cpstr name, cpstr value );
+ void AddAttribute ( cpstr name, const int iV );
+ void AddAttribute ( cpstr name, const bool bV );
+ void SetData ( cpstr Data );
+ void AddData ( cpstr Data );
+ void SetData ( const realtype V, const int length=11 );
+ void SetData ( const int iV, const int length=0 );
+ void SetData ( const bool bV );
+
+ int AddMMCIFCategory ( mmcif::PCategory mmCIFCat );
+ int AddMMCIFStruct ( mmcif::PStruct mmCIFStruct );
+ int AddMMCIFLoop ( mmcif::PLoop mmCIFLoop );
+ int AddMMCIFData ( mmcif::PData mmCIFData );
+
+ inline pstr GetTag() { return objTag; }
+
+ // Here and below the functions allow for "tag1>tag2>tag3>..."
+ // as a composite multi-level tag, e.g. the above may stand for
+ // <tag1><tag2><tag3>data</tag3></tag2></tag1>. NULL tag
+ // corresponds to "this" object.
+ // objNo counts same-tag objects of the *highest* level used
+ // (e.g. level tag3 for composite tag tag1>tag2>tag3 ).
+ // GetData ( pstr& ... ) only copies a pointer to data.
+ pstr GetData ( cpstr Tag=NULL, int objNo=1 );
+ XML_RC GetData ( pstr & Data, cpstr Tag=NULL, int objNo=1 );
+ XML_RC GetData ( realtype & V, cpstr Tag=NULL, int objNo=1 );
+ XML_RC GetData ( int & iV, cpstr Tag=NULL, int objNo=1 );
+ XML_RC GetData ( bool & bV, cpstr Tag=NULL, int objNo=1 );
+
+ PXMLObject GetObject ( cpstr Tag, int objNo=1 );
+ PXMLObject GetFirstObject();
+ PXMLObject GetLastObject ();
+ inline int GetNumberOfObjects() { return nObjects; }
+ PXMLObject GetObject ( int objectNo ); // 0,1,...
+
+ inline PXMLObject GetParent() { return parent; }
+
+ void AddObject ( PXMLObject XMLObject, int lenInc=10 );
+ void InsertObject ( PXMLObject XMLObject, int pos,
+ int lenInc=10 );
+
+ XML_RC WriteObject ( cpstr FName, int pos=0, int ident=2 );
+ void WriteObject ( io::RFile f, int pos=0, int ident=2 );
+ XML_RC ReadObject ( cpstr FName );
+ XML_RC ReadObject ( io::RFile f, pstr S, int & pos, int slen );
+
+ virtual void Copy ( PXMLObject xmlObject );
+
+ void write ( io::RFile f );
+ void read ( io::RFile f );
+
+ protected:
+ PXMLObject parent;
+ pstr objTag;
+ pstr objData;
+ int nObjects,nAlloc;
+ PPXMLObject object;
+ int nAttributes,nAttrAlloc;
+ psvector attr_name,attr_value;
+
+ void InitXMLObject();
+ virtual void FreeMemory ();
+
+ inline void SetParent ( PXMLObject p ) { parent = p; }
+
+ };
+
+
+ extern PXMLObject mmCIF2XML ( mmcif::PData mmCIFData,
+ int * rc=NULL );
+ extern PXMLObject mmCIF2XML ( cpstr XMLName, mmcif::PFile mmCIFFile,
+ int * rc=NULL );
+
+ } // namespace xml
+
+} // namespace mmdb
+
+#endif
+
+