diff options
author | Picca Frédéric-Emmanuel <picca@debian.org> | 2014-09-10 21:39:50 +0200 |
---|---|---|
committer | Picca Frédéric-Emmanuel <picca@debian.org> | 2014-09-10 21:39:50 +0200 |
commit | f3af8fbe7a5ae3222c781b26bad4c548b6166e65 (patch) | |
tree | dcb6fe70a09b76399814c43c8814a97c7d290a86 /mmdb2 | |
parent | 54c5247855a4da37b72d54b7c32e21d7a57daea3 (diff) |
Imported Upstream version 2.0.1
Diffstat (limited to 'mmdb2')
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 + + |