1 //  $Id: mmdb_model.cpp $
2 //  =================================================================
3 //
4 //   CCP4 Coordinate Library: support of coordinate-related
5 //   functionality in protein crystallography applications.
6 //
7 //   Copyright (C) Eugene Krissinel 2000-2013.
8 //
9 //    This library is free software: you can redistribute it and/or
10 //    modify it under the terms of the GNU Lesser General Public
11 //    License version 3, modified in accordance with the provisions
12 //    of the license to address the requirements of UK law.
13 //
14 //    You should have received a copy of the modified GNU Lesser
15 //    General Public License along with this library. If not, copies
16 //    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
17 //
18 //    This program is distributed in the hope that it will be useful,
19 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
20 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 //    GNU Lesser General Public License for more details.
22 //
23 //  =================================================================
24 //
25 //    11.09.15   <--  Date of Last Modification.
26 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 //  -----------------------------------------------------------------
28 //
29 //  **** Module  :  MMDB_Model <implementation>
30 //       ~~~~~~~~~
31 //  **** Project :  MacroMolecular Data Base (MMDB)
32 //       ~~~~~~~~~
33 //  **** Classes :  mmdb::HetCompound  ( description of het compounds  )
34 //       ~~~~~~~~~  mmdb::HetCompounds (HETNAM, HETSYN, FORMULA records)
35 //                  mmdb::SSContainer  (container for helixes and turns)
36 //                  mmdb::Helix        ( helix info                    )
37 //                  mmdb::Strand       ( strand info                   )
38 //                  mmdb::Sheet        ( sheet info                    )
39 //                  mmdb::Sheets       ( container for sheets          )
40 //                  mmdb::Turn         ( turn info                     )
41 //                  mmdb::LinkContainer   ( container for link data    )
42 //                  mmdb::Link            ( link data                  )
43 //                  mmdb::LinkRContainer  ( container for refmac link  )
44 //                  mmdb::LinkR           ( link data                  )
45 //                  mmdb::CisPepContainer ( container for CisPep data  )
46 //                  mmdb::CisPep          ( CisPep data                )
47 //                  mmdb::Model        ( PDB model                     )
48 //
49 //  Copyright (C) E. Krissinel 2000-2015
50 //
51 //  =================================================================
52 //
53 
54 #include <string.h>
55 #include <stdlib.h>
56 
57 #include "mmdb_model.h"
58 #include "mmdb_manager.h"
59 #include "mmdb_cifdefs.h"
60 
61 namespace mmdb  {
62 
63   //  ===================  HetCompound  =========================
64 
HetCompound(cpstr HetName)65   HetCompound::HetCompound ( cpstr HetName ) : io::Stream()  {
66     InitHetCompound ( HetName );
67   }
68 
HetCompound(io::RPStream Object)69   HetCompound::HetCompound ( io::RPStream Object ) : io::Stream(Object)  {
70     InitHetCompound ( pstr("---") );
71   }
72 
~HetCompound()73   HetCompound::~HetCompound() {
74     FreeMemory();
75   }
76 
InitHetCompound(cpstr HetName)77   void  HetCompound::InitHetCompound ( cpstr HetName )  {
78     strcpy_n0 ( hetID,HetName,sizeof(ResName) );
79     comment    = NULL;
80     nSynonyms  = 0;
81     hetSynonym = NULL;
82     compNum    = MinInt4;
83     wc         = ' ';
84     Formula    = NULL;
85   }
86 
FreeMemory()87   void  HetCompound::FreeMemory()  {
88   int i;
89     if (comment)  {
90       delete[] comment;
91       comment = NULL;
92     }
93     if (hetSynonym)  {
94       for (i=0;i<nSynonyms;i++)
95         if (hetSynonym[i])  delete[] hetSynonym[i];
96       delete[] hetSynonym;
97       hetSynonym = NULL;
98     }
99     nSynonyms = 0;
100     if (Formula)  {
101       delete[] Formula;
102       Formula = NULL;
103     }
104   }
105 
AddKeyWord(cpstr W,bool Closed)106   void  HetCompound::AddKeyWord ( cpstr W, bool Closed )  {
107   psvector HS1;
108   int      i;
109     if (Closed || (!hetSynonym))  {
110       // first synonym orthe previous synonym was closed by semicolon
111       // -- add a new one
112       HS1 = new pstr[nSynonyms+1];
113       for (i=0;i<nSynonyms;i++)
114         HS1[i] = hetSynonym[i];
115       if (hetSynonym)  delete[] hetSynonym;
116       hetSynonym = HS1;
117       hetSynonym[nSynonyms] = NULL;
118       CreateCopy ( hetSynonym[nSynonyms],W );
119       nSynonyms++;
120     } else  {
121       // just add W to the last synonym
122       CreateConcat ( hetSynonym[nSynonyms-1],pstr(" "),W );
123     }
124   }
125 
126 
HETNAM_PDBDump(io::RFile f)127   void HetCompound::HETNAM_PDBDump ( io::RFile f )  {
128   char S[100];
129   pstr p1,p2;
130   char c;
131   int  N,i;
132 
133     if (!comment)  return;
134 
135     c = ' ';
136     N  = 0;
137     p1 = comment;
138     do  {
139       N++;
140       if (N==1)  sprintf ( S,"HETNAM     %3s " ,hetID   );
141            else  sprintf ( S,"HETNAM  %2i %3s ",N,hetID );
142       while (*p1==' ')  p1++;
143       p2 = FirstOccurence(p1,'\n');
144       if (p2)  {
145         c   = *p2;
146         *p2 = char(0);
147       } else if (strlen(p1)>53)  {
148         i = 0;
149         while (p1[i] && (i<53) && (p1[i]!=' '))  i++;
150         p2  = &(p1[i]);
151         c   = *p2;
152         *p2 = char(0);
153       }
154       if (*p1)  {
155         strcat      ( S,p1 );
156         PadSpaces   ( S,80 );
157         f.WriteLine ( S );
158       } else
159         N--;
160       if (p2)  {
161         *p2 = c;
162         if (c)  p1 = p2+1;
163           else  p2 = NULL;
164       }
165     } while (p2);
166 
167   }
168 
169 
HETSYN_PDBDump(io::RFile f)170   void HetCompound::HETSYN_PDBDump ( io::RFile f )  {
171   char S[100];
172   pstr p;
173   char c;
174   int  N,k,i,l;
175     if (!hetSynonym)  return;
176     N = 0;
177     k = 0;
178     p = &(hetSynonym[0][0]);
179     do  {
180       N++;
181       if (N==1)  sprintf ( S,"HETSYN     %3s " ,hetID   );
182            else  sprintf ( S,"HETSYN  %2i %3s ",N,hetID );
183       i = 0;
184       do  {
185         l = strlen(p)+2;
186         if (i+l<54)  {
187           strcat ( S,p );
188           if (k<nSynonyms-1) strcat ( S,"; " );
189           k++;
190           i += l;
191           if (k<nSynonyms)  p = &(hetSynonym[k][0]);
192                       else  i = 60;  // break loop
193         } else  {
194           if (i==0)  {
195             // too long synonym, has to be split over several lines
196             i = l-3;
197             while (i>51)  {
198               i--;
199               while ((i>0) && (p[i]!=' '))  i--;
200             }
201             if (i<2)  i = 51;  // no spaces!
202             c    = p[i];
203             p[i] = char(0);
204             strcat ( S,p );
205             p[i] = c;
206             p    = &(p[i]);
207             while (*p==' ')  p++;
208           }
209           i = 60;  // break loop
210         }
211       } while (i<54);
212       PadSpaces ( S,80 );
213       f.WriteLine ( S );
214     } while (k<nSynonyms);
215   }
216 
217 
FORMUL_PDBDump(io::RFile f)218   void HetCompound::FORMUL_PDBDump ( io::RFile f )  {
219   char S[100];
220   pstr p1,p2;
221   char c;
222   int  N,i;
223     if (!Formula)  return;
224     N  = 0;
225     p1 = Formula;
226     do  {
227       N++;
228       if (compNum>MinInt4)  {
229         if (N==1)  sprintf ( S,"FORMUL  %2i  %3s    " ,compNum,hetID   );
230              else  sprintf ( S,"FORMUL  %2i  %3s %2i ",compNum,hetID,N );
231       } else  {
232         if (N==1)  sprintf ( S,"FORMUL      %3s    " ,hetID   );
233              else  sprintf ( S,"FORMUL      %3s %2i ",hetID,N );
234       }
235       S[18] = wc;
236       p2 = FirstOccurence(p1,'\n');
237       if (p2)  {
238         c   = *p2;
239         *p2 = char(0);
240       } else if (strlen(p1)>50)  {
241         while (*p1==' ')  p1++;
242         i = 0;
243         while (p1[i] && (i<50) && (p1[i]!=' '))  i++;
244         p2  = &(p1[i]);
245         c   = *p2;
246         *p2 = char(0);
247       }
248       strcat ( S,p1 );
249       if (p2)  {
250         *p2 = c;
251         p1  = p2+1;
252       }
253       PadSpaces ( S,80 );
254       f.WriteLine ( S );
255     } while (p2);
256   }
257 
258 
FormComString(pstr & F)259   void  HetCompound::FormComString ( pstr & F )  {
260   pstr p;
261   int  i;
262     if (F)  {
263       delete[] F;
264       F = NULL;
265     }
266     if (comment)  {
267       CreateCopy ( F,comment );
268       i = 0;
269       p = comment;
270       while (*p)  {
271         p++;
272         if (*p=='\n')  i = 0;
273                  else  i++;
274         if (i>68)  {
275           F[i] = char(0);
276           CreateConcat ( F,pstr("\n"),p );
277           i = 0;
278         }
279       }
280     }
281   }
282 
283 
FormSynString(pstr & F)284   void  HetCompound::FormSynString ( pstr & F )  {
285   pstr p;
286   char c;
287   int  i,k,l;
288     if (F)  {
289       delete[] F;
290       F = NULL;
291     }
292     if (hetSynonym)  {
293       CreateCopy ( F,pstr("  ") );
294       k = 0;
295       p = &(hetSynonym[0][0]);
296       do  {
297         l = strlen(p)+2;
298         if (l<=60)  {
299           if (k<nSynonyms-1)  CreateConcat ( F,p,pstr(";\n  ") );
300                         else  CreateConcat ( F,p );
301           k++;
302           if (k<nSynonyms)  p = &(hetSynonym[k][0]);
303         } else  {
304           // too long synonym, has to be split over several lines
305           i = l-3;
306           while (i>60)  {
307             i--;
308             while ((i>0) && (p[i]!=' '))  i--;
309           }
310           if (i<2)  i = 60;  // no spaces!
311           c    = p[i];
312           p[i] = char(0);
313           CreateConcat ( F,p,pstr("\n  ") );
314           p[i] = c;
315           p    = &(p[i]);
316           while (*p==' ')  p++;
317         }
318       } while (k<nSynonyms);
319     }
320   }
321 
FormForString(pstr & F)322   void  HetCompound::FormForString ( pstr & F )  {
323   pstr p;
324   int  i;
325     if (F)  {
326       delete[] F;
327       F = NULL;
328     }
329     if (Formula)  {
330       CreateCopy ( F,Formula );
331       i = 0;
332       p = &(Formula[0]);
333       while (*p)  {
334         p++;
335         if (*p=='\n')  i = 0;
336                  else  i++;
337         if (i>68)  {
338           F[i] = char(0);
339           CreateConcat ( F,pstr("\n"),p );
340           i = 0;
341         }
342       }
343     }
344   }
345 
346 
Copy(PHetCompound hetCompound)347   void  HetCompound::Copy ( PHetCompound hetCompound )  {
348   int i;
349     FreeMemory ();
350     strcpy     ( hetID  ,hetCompound->hetID   );
351     CreateCopy ( comment,hetCompound->comment );
352     nSynonyms = hetCompound->nSynonyms;
353     if (nSynonyms>0) {
354       hetSynonym = new pstr[nSynonyms];
355       for (i=0;i<nSynonyms;i++)  {
356         hetSynonym[i] = NULL;
357         CreateCopy ( hetSynonym[i],hetCompound->hetSynonym[i] );
358       }
359     }
360     compNum = hetCompound->compNum;
361     wc      = hetCompound->wc;
362     CreateCopy ( Formula,hetCompound->Formula );
363   }
364 
write(io::RFile f)365   void  HetCompound::write ( io::RFile f )  {
366   int  i;
367   byte Version=1;
368     f.WriteByte    ( &Version    );
369     f.WriteTerLine ( hetID,false );
370     f.CreateWrite  ( comment     );
371     f.WriteInt     ( &nSynonyms  );
372     for (i=0;i<nSynonyms;i++)
373       f.CreateWrite ( hetSynonym[i] );
374     f.WriteInt    ( &compNum       );
375     f.WriteFile   ( &wc,sizeof(wc) );
376     f.CreateWrite ( Formula        );
377   }
378 
read(io::RFile f)379   void  HetCompound::read ( io::RFile f )  {
380   int  i;
381   byte Version;
382     FreeMemory();
383     f.ReadByte    ( &Version    );
384     f.ReadTerLine ( hetID,false );
385     f.CreateRead  ( comment     );
386     f.ReadInt     ( &nSynonyms  );
387     if (nSynonyms>0) {
388       hetSynonym = new pstr[nSynonyms];
389       for (i=0;i<nSynonyms;i++)  {
390         hetSynonym[i] = NULL;
391         f.CreateRead ( hetSynonym[i] );
392       }
393     }
394     f.ReadInt    ( &compNum       );
395     f.ReadFile   ( &wc,sizeof(wc) );
396     f.CreateRead ( Formula        );
397   }
398 
MakeStreamFunctions(HetCompound)399   MakeStreamFunctions(HetCompound)
400 
401 
402   //  ====================  HetCompounds  =======================
403 
404 
405   HetCompounds::HetCompounds() : io::Stream()  {
406     InitHetCompounds();
407   }
408 
HetCompounds(io::RPStream Object)409   HetCompounds::HetCompounds ( io::RPStream Object )
410               : io::Stream(Object)  {
411     InitHetCompounds();
412   }
413 
~HetCompounds()414   HetCompounds::~HetCompounds() {
415     FreeMemory();
416   }
417 
InitHetCompounds()418   void  HetCompounds::InitHetCompounds()  {
419     nHets       = 0;
420     hetCompound = NULL;
421     Closed      = false;
422   }
423 
FreeMemory()424   void  HetCompounds::FreeMemory()  {
425   int i;
426     if (hetCompound)  {
427       for (i=0;i<nHets;i++)
428         if (hetCompound[i])  delete hetCompound[i];
429       delete[] hetCompound;
430       hetCompound = NULL;
431     }
432     nHets = 0;
433   }
434 
ConvertHETNAM(cpstr S)435   void  HetCompounds::ConvertHETNAM ( cpstr S )  {
436   ResName hetID;
437   char    L[100];
438   int     l,i;
439     l = strlen(S);
440     if (l>12)  {
441       strcpy_n0 ( hetID,&(S[11]),3 );
442       i = AddHetName ( hetID );
443       if (l>15)  {
444         if (hetCompound[i]->comment)  strcpy ( L,"\n" );
445                                 else  L[0] = char(0);
446         strcat       ( L,&(S[15])    );
447         CutSpaces    ( L,SCUTKEY_END );
448         CreateConcat ( hetCompound[i]->comment,L );
449       }
450     }
451   }
452 
ConvertHETSYN(cpstr S)453   void  HetCompounds::ConvertHETSYN ( cpstr S )  {
454   ResName hetID;
455   char    L[100];
456   int     l,i,j,k;
457     l = strlen(S);
458     if (l>12)  {
459       strcpy_n0 ( hetID,&(S[11]),3 );
460       i = AddHetName ( hetID );
461       if (l>15)  {
462         j = 15;
463         do {
464           while (S[j]==' ')  j++;
465           k = 0;
466           if (S[j])  {
467             while (S[j] && (S[j]!=';'))
468               L[k++] = S[j++];
469             L[k--] = char(0);
470             while ((k>0) && (L[k]==' '))  L[k--] = char(0);
471             if (L[0])  {
472               hetCompound[i]->AddKeyWord ( L,Closed );
473               Closed = (S[j]==';');
474             }
475             if (S[j])  j++;
476           }
477         } while (S[j]);
478         /*
479         p1 = &(S[15]);
480         do  {
481           p2 = FirstOccurence ( p1,';' );
482           if (p2)  {
483             c   = *p2;
484             *p2 = char(0);
485           }
486           strcpy_css ( L,p1 );
487           if (L[0])
488             hetCompound[i]->AddKeyWord ( L,Closed );
489           if (p2) {
490             if (L[0]) Closed = true;
491             *p2 = c;
492             p1 = p2+1;
493           } else if (L[0])
494             Closed = false;
495         } while (p2);
496         */
497       }
498     }
499   }
500 
ConvertFORMUL(cpstr S)501   void  HetCompounds::ConvertFORMUL ( cpstr S )  {
502   ResName hetID;
503   char    L[100];
504   int     l,i;
505     l = strlen(S);
506     if (l>13)  {
507       strcpy_n0 ( hetID,&(S[12]),3 );
508       i = AddHetName ( hetID );
509       if (l>18) {
510         GetInteger ( hetCompound[i]->compNum,&(S[9]),2 );
511         hetCompound[i]->wc = S[18];
512         if (strlen(S)>19)  {
513           if (hetCompound[i]->Formula)  strcpy ( L,"\n" );
514                                   else  L[0] = char(0);
515           strcat       ( L,&(S[19])    );
516           CutSpaces    ( L,SCUTKEY_END );
517           CreateConcat ( hetCompound[i]->Formula,L );
518         }
519       }
520     }
521   }
AddHetName(cpstr H)522   int  HetCompounds::AddHetName ( cpstr H )  {
523   PPHetCompound HC1;
524   int            i;
525     i = 0;
526     while (i<nHets)  {
527       if (hetCompound[i])  {
528         if (!strcmp(hetCompound[i]->hetID,H))  break;
529       }
530       i++;
531     }
532     if (i>=nHets)  {
533       HC1 = new PHetCompound[nHets+1];
534       for (i=0;i<nHets;i++)
535         HC1[i] = hetCompound[i];
536       if (hetCompound)  delete[] hetCompound;
537       hetCompound = HC1;
538       hetCompound[nHets] = new HetCompound ( H );
539       i = nHets;
540       nHets++;
541     }
542     return i;
543   }
544 
PDBASCIIDump(io::RFile f)545   void HetCompounds::PDBASCIIDump ( io::RFile f )  {
546   int  i;
547 
548     for (i=0;i<nHets;i++)
549       if (hetCompound[i])
550         hetCompound[i]->HETNAM_PDBDump ( f );
551 
552     for (i=0;i<nHets;i++)
553       if (hetCompound[i])
554         hetCompound[i]->HETSYN_PDBDump ( f );
555 
556     for (i=0;i<nHets;i++)
557       if (hetCompound[i])
558         hetCompound[i]->FORMUL_PDBDump ( f );
559 
560   }
561 
562 
MakeCIF(mmcif::PData CIF)563   void  HetCompounds::MakeCIF ( mmcif::PData CIF )  {
564   mmcif::PLoop Loop;
565   pstr        F;
566   int         RC;
567   int         i;
568 
569     if (!hetCompound)  return;
570 
571     RC = CIF->AddLoop ( CIFCAT_CHEM_COMP,Loop );
572     if (RC!=mmcif::CIFRC_Ok)  {
573       Loop->AddLoopTag ( CIFTAG_ID               );
574       Loop->AddLoopTag ( CIFTAG_NAME             );
575       Loop->AddLoopTag ( CIFTAG_NDB_SYNONYMS     );
576       Loop->AddLoopTag ( CIFTAG_NDB_COMPONENT_NO );
577       Loop->AddLoopTag ( CIFTAG_FORMULA          );
578     }
579 
580     F = NULL;
581     for (i=0;i<nHets;i++)
582       if (hetCompound[i])  {
583         Loop->AddString ( hetCompound[i]->hetID );
584         hetCompound[i]->FormComString ( F );
585         Loop->AddString ( F );
586         hetCompound[i]->FormSynString ( F );
587         Loop->AddString ( F );
588         if (hetCompound[i]->compNum>MinInt4)
589               Loop->AddInteger ( hetCompound[i]->compNum );
590         else  Loop->AddNoData  ( mmcif::CIF_NODATA_QUESTION );
591         hetCompound[i]->FormForString ( F );
592         Loop->AddString ( F );
593       }
594 
595     if (F)  delete[] F;
596 
597   }
598 
GetCIF(mmcif::PData CIF)599   ERROR_CODE HetCompounds::GetCIF ( mmcif::PData CIF )  {
600   mmcif::PLoop Loop;
601   char         L[100];
602   ResName      hetID;
603   pstr         F,p1,p2;
604   char         c;
605   int          RC,i,l,k;
606 
607     FreeMemory();
608     c = char(0);  // only to supress compiler warnings
609 
610     Loop = CIF->GetLoop ( CIFCAT_CHEM_COMP );
611     if (!Loop)  return Error_NoError;
612 
613     l = Loop->GetLoopLength();
614     F = NULL;
615 
616     for (i=0;i<l;i++)  {
617       CIFGetString    ( hetID,Loop,CIFTAG_ID,i,sizeof(hetID),
618                         pstr("---") );
619       k = AddHetName  ( hetID );
620       Loop->GetString ( hetCompound[k]->comment,CIFTAG_NAME,i,true );
621       RC = Loop->GetInteger ( hetCompound[k]->compNum,
622                                        CIFTAG_NDB_COMPONENT_NO,i,true );
623       if (RC)  hetCompound[i]->compNum = MinInt4;
624       Loop->GetString ( hetCompound[k]->Formula,CIFTAG_FORMULA,i,true );
625       RC = Loop->GetString ( F,CIFTAG_NDB_SYNONYMS,i,true );
626       if ((!RC) && F )  {
627         p1 = &(F[0]);
628         while (*p1)  {
629           if (*p1=='\n')  *p1 = ' ';
630           p1++;
631         }
632         p1 = &(F[0]);
633         do  {
634           p2 = FirstOccurence ( p1,';' );
635           if (p2)  {
636             c   = *p2;
637             *p2 = char(0);
638           }
639           strcpy_css ( L,p1 );
640           hetCompound[i]->AddKeyWord ( L,true );
641           if (p2) {
642             *p2 = c;
643             p1 = p2+1;
644           }
645         } while (p2);
646       }
647       hetCompound[i]->wc = ' ';
648     }
649 
650   //  CIF->DeleteLoop ( CIFCAT_CHEM_COMP );
651 
652     if (F)  delete[] F;
653 
654     return Error_NoError;
655 
656   }
657 
Copy(PHetCompounds HetCompounds)658   void  HetCompounds::Copy ( PHetCompounds HetCompounds )  {
659   int i;
660     FreeMemory();
661     nHets = HetCompounds->nHets;
662     if (nHets>0)  {
663       hetCompound = new PHetCompound[nHets];
664       for (i=0;i<nHets;i++)  {
665         hetCompound[i] = new HetCompound ( "" );
666         hetCompound[i]->Copy ( HetCompounds->hetCompound[i] );
667       }
668     }
669   }
670 
write(io::RFile f)671   void  HetCompounds::write ( io::RFile f )  {
672   int  i;
673   byte Version=1;
674     f.WriteByte ( &Version );
675     f.WriteInt  ( &nHets   );
676     for (i=0;i<nHets;i++)
677       hetCompound[i]->write ( f );
678   }
679 
read(io::RFile f)680   void  HetCompounds::read ( io::RFile f )  {
681   int  i;
682   byte Version;
683     FreeMemory();
684     f.ReadByte ( &Version );
685     f.ReadInt  ( &nHets   );
686     if (nHets>0)  {
687       hetCompound = new PHetCompound[nHets];
688       for (i=0;i<nHets;i++)  {
689         hetCompound[i] = new HetCompound ( "---" );
690         hetCompound[i]->read ( f );
691       }
692     }
693   }
694 
MakeStreamFunctions(HetCompounds)695   MakeStreamFunctions(HetCompounds)
696 
697 
698 
699   //  ====================  SSContainer  =========================
700 
701   PContainerClass SSContainer::MakeContainerClass ( int ClassID )  {
702     switch (ClassID)  {
703       default :
704       case ClassID_Template : return
705                           ClassContainer::MakeContainerClass(ClassID);
706       case ClassID_Helix    : return new Helix();
707       case ClassID_Turn     : return new Turn ();
708     }
709   }
710 
MakeStreamFunctions(SSContainer)711   MakeStreamFunctions(SSContainer)
712 
713 
714   //  ================  Helix  ===================
715 
716   Helix::Helix() : ContainerClass()  {
717     InitHelix();
718   }
719 
Helix(cpstr S)720   Helix::Helix ( cpstr S ) : ContainerClass()  {
721     InitHelix();
722     ConvertPDBASCII ( S );
723   }
724 
Helix(io::RPStream Object)725   Helix::Helix ( io::RPStream Object ) : ContainerClass(Object)  {
726     InitHelix();
727   }
728 
~Helix()729   Helix::~Helix() {
730     if (comment)  delete[] comment;
731   }
732 
InitHelix()733   void  Helix::InitHelix()  {
734 
735     serNum = 0;                   // serial number
736     strcpy ( helixID    ,"---" ); // helix ID
737     strcpy ( initResName,"---" ); // name of the helix's initial residue
738     strcpy ( initChainID,""    ); // chain ID for the chain
739                                   // containing the helix
740     initSeqNum = 0;               // sequence number of the initial
741                                   //    residue
742     strcpy ( initICode  ,""    ); // insertion code of the initial
743                                   //    residue
744     strcpy ( endResName ,"---" ); // name of the helix's terminal residue
745     strcpy ( endChainID ,""    ); // chain ID for the chain
746                                   // containing the helix
747     endSeqNum  = 0;               // sequence number of the terminal
748                                   //    residue
749     strcpy ( endICode   ,""    ); // insertion code of the terminal
750                                   //    residue
751     helixClass = 0;               // helix class
752     comment    = NULL;            // comment about the helix
753     length     = 0;               // length of the helix
754 
755   }
756 
PDBASCIIDump(pstr S,int N)757   void  Helix::PDBASCIIDump ( pstr S, int N )  {
758   UNUSED_ARGUMENT(N);
759   //  makes the ASCII PDB OBSLTE line number N
760   //  from the class' data
761     strcpy     ( S,"HELIX" );
762     PadSpaces  ( S,80 );
763     PutInteger ( &(S[7]) ,serNum     ,3  );
764     strcpy_n1  ( &(S[11]),helixID    ,3  );
765     strcpy_n1  ( &(S[15]),initResName,3  );
766     if (initChainID[0])  S[19] = initChainID[0];
767     PutIntIns  ( &(S[21]),initSeqNum ,4,initICode );
768     strcpy_n1  ( &(S[27]),endResName ,3  );
769     if (endChainID[0])   S[31] = endChainID[0];
770     PutIntIns  ( &(S[33]),endSeqNum  ,4,endICode  );
771     PutInteger ( &(S[38]),helixClass ,2  );
772     if (comment)
773       strcpy_n ( &(S[40]),comment    ,30 );
774     PutInteger ( &(S[71]),length     ,5  );
775   }
776 
AddStructConfTags(mmcif::PLoop Loop)777   void AddStructConfTags ( mmcif::PLoop Loop )  {
778     Loop->AddLoopTag ( CIFTAG_CONF_TYPE_ID               );
779     Loop->AddLoopTag ( CIFTAG_ID                         );
780     Loop->AddLoopTag ( CIFTAG_PDB_ID                     );
781     Loop->AddLoopTag ( CIFTAG_BEG_LABEL_COMP_ID          );
782     Loop->AddLoopTag ( CIFTAG_BEG_LABEL_ASYM_ID          );
783     Loop->AddLoopTag ( CIFTAG_BEG_LABEL_SEQ_ID           );
784     Loop->AddLoopTag ( CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB );
785     Loop->AddLoopTag ( CIFTAG_END_LABEL_COMP_ID          );
786     Loop->AddLoopTag ( CIFTAG_END_LABEL_ASYM_ID          );
787     Loop->AddLoopTag ( CIFTAG_END_LABEL_SEQ_ID           );
788     Loop->AddLoopTag ( CIFTAG_NDB_END_LABEL_INS_CODE_PDB );
789     Loop->AddLoopTag ( CIFTAG_NDB_HELIX_CLASS_PDB        );
790     Loop->AddLoopTag ( CIFTAG_DETAILS                    );
791     Loop->AddLoopTag ( CIFTAG_NDB_LENGTH                 );
792   }
793 
794   #define  HelixTypeID  "HELX_P"
795 
MakeCIF(mmcif::PData CIF,int N)796   void  Helix::MakeCIF ( mmcif::PData CIF, int N )  {
797   UNUSED_ARGUMENT(N);
798   mmcif::PLoop Loop;
799   int         RC;
800     RC = CIF->AddLoop ( CIFCAT_STRUCT_CONF,Loop );
801     if (RC!=mmcif::CIFRC_Ok)
802       // the category was (re)created, provide tags
803       AddStructConfTags ( Loop );
804     Loop->AddString  ( pstr(HelixTypeID) );
805     Loop->AddInteger ( serNum      );
806     Loop->AddString  ( helixID     );
807     Loop->AddString  ( initResName );
808     Loop->AddString  ( initChainID );
809     Loop->AddInteger ( initSeqNum  );
810     Loop->AddString  ( initICode,true );
811     Loop->AddString  ( endResName  );
812     Loop->AddString  ( endChainID  );
813     Loop->AddInteger ( endSeqNum   );
814     Loop->AddString  ( endICode ,true );
815     Loop->AddInteger ( helixClass  );
816     Loop->AddString  ( comment     );
817     Loop->AddInteger ( length      );
818   }
819 
ConvertPDBASCII(cpstr S)820   ERROR_CODE Helix::ConvertPDBASCII ( cpstr S )  {
821   char L[100];
822     GetInteger  ( serNum     ,&(S[7]) ,3  );
823     strcpy_ncss ( helixID    ,&(S[11]),3  );
824     strcpy_ncss ( initResName,&(S[15]),3  );
825     strcpy_ncss ( initChainID,&(S[19]),1  );
826     GetIntIns   ( initSeqNum,initICode,&(S[21]),4  );
827     strcpy_ncss ( endResName ,&(S[27]),3  );
828     strcpy_ncss ( endChainID ,&(S[31]),1  );
829     GetIntIns   ( endSeqNum ,endICode ,&(S[33]),4  );
830     GetInteger  ( helixClass ,&(S[38]),2  );
831     strcpy_ncss ( L          ,&(S[40]),30 );
832     CreateCopy  ( comment    ,L           );
833     GetInteger  ( length     ,&(S[71]),5  );
834     return Error_NoError;
835   }
836 
GetCIF(mmcif::PData CIF,int & n)837   ERROR_CODE Helix::GetCIF ( mmcif::PData CIF, int & n )  {
838   mmcif::PLoop Loop;
839   int          RC,l;
840   pstr         F;
841   bool         Done;
842   ERROR_CODE   rc;
843 
844     Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONF );
845     if (!Loop)  {
846       n = -1;  // signal to finish processing of this structure
847       return Error_EmptyCIF;
848     }
849 
850     l    = Loop->GetLoopLength();
851     Done = n>=l;
852     while (!Done) {
853       F = Loop->GetString ( CIFTAG_CONF_TYPE_ID,n,RC );
854       if ((!RC) && F)  Done = (strcmp(F,HelixTypeID)==0);
855                  else  Done = false;
856       if (!Done)  {
857         n++;
858         Done = n>=l;
859       }
860     }
861 
862     if (n>=l)  {
863       n = -1;  // finish processing of Helix
864       return Error_EmptyCIF;
865     }
866 
867     Loop->DeleteField ( CIFTAG_CONF_TYPE_ID,n );
868 
869     rc = CIFGetInteger ( serNum,Loop,CIFTAG_ID,n );
870     if (rc==Error_NoData)   return Error_EmptyCIF;
871     if (rc!=Error_NoError)  return rc;
872 
873     CIFGetString ( helixID    ,Loop,CIFTAG_PDB_ID,
874                                n,sizeof(helixID),pstr("   ") );
875 
876     CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
877                                n,sizeof(initResName),pstr("   ") );
878     CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
879                                n,sizeof(initChainID),pstr("") );
880     CIFGetString ( initICode  ,Loop,CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
881                                n,sizeof(initICode),pstr("") );
882     if (CIFGetInteger(initSeqNum,Loop,CIFTAG_BEG_LABEL_SEQ_ID,n))
883     if (rc==Error_NoData)   return Error_EmptyCIF;
884     if (rc!=Error_NoError)  return rc;
885 
886     CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
887                               n,sizeof(endResName),pstr("   ") );
888     CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
889                               n,sizeof(endChainID),pstr("") );
890     CIFGetString ( endICode  ,Loop,CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
891                               n,sizeof(endICode),pstr("") );
892     rc = CIFGetInteger(endSeqNum,Loop,CIFTAG_END_LABEL_SEQ_ID,n );
893     if (rc==Error_NoData)   return Error_EmptyCIF;
894     if (rc!=Error_NoError)  return rc;
895 
896     rc = CIFGetInteger(helixClass,Loop,CIFTAG_NDB_HELIX_CLASS_PDB,n );
897     if (rc==Error_NoData)   return Error_EmptyCIF;
898     if (rc!=Error_NoError)  return rc;
899 
900     CreateCopy     ( comment,Loop->GetString(CIFTAG_DETAILS,n,RC));
901     Loop->DeleteField ( CIFTAG_DETAILS,n );
902     rc = CIFGetInteger ( length,Loop,CIFTAG_NDB_LENGTH,n );
903     if (rc==Error_NoData)   return Error_EmptyCIF;
904     if (rc!=Error_NoError)  return rc;
905 
906     n++;
907 
908     return Error_NoError;
909 
910   }
911 
Copy(PContainerClass Helix)912   void  Helix::Copy ( PContainerClass Helix )  {
913     serNum     = PHelix(Helix)->serNum;
914     initSeqNum = PHelix(Helix)->initSeqNum;
915     endSeqNum  = PHelix(Helix)->endSeqNum;
916     helixClass = PHelix(Helix)->helixClass;
917     length     = PHelix(Helix)->length;
918     strcpy ( helixID    ,PHelix(Helix)->helixID     );
919     strcpy ( initResName,PHelix(Helix)->initResName );
920     strcpy ( initChainID,PHelix(Helix)->initChainID );
921     strcpy ( initICode  ,PHelix(Helix)->initICode   );
922     strcpy ( endResName ,PHelix(Helix)->endResName  );
923     strcpy ( endChainID ,PHelix(Helix)->endChainID  );
924     strcpy ( endICode   ,PHelix(Helix)->endICode    );
925     CreateCopy ( comment,PHelix(Helix)->comment );
926   }
927 
write(io::RFile f)928   void  Helix::write ( io::RFile f )  {
929   byte Version=1;
930     f.WriteByte ( &Version    );
931     f.WriteInt  ( &serNum     );
932     f.WriteInt  ( &initSeqNum );
933     f.WriteInt  ( &endSeqNum  );
934     f.WriteInt  ( &helixClass );
935     f.WriteInt  ( &length     );
936     f.WriteTerLine ( helixID    ,false );
937     f.WriteTerLine ( initResName,false );
938     f.WriteTerLine ( initChainID,false );
939     f.WriteTerLine ( initICode  ,false );
940     f.WriteTerLine ( endResName ,false );
941     f.WriteTerLine ( endChainID ,false );
942     f.WriteTerLine ( endICode   ,false );
943     f.CreateWrite ( comment );
944   }
945 
read(io::RFile f)946   void  Helix::read  ( io::RFile f ) {
947   byte Version;
948     f.ReadByte ( &Version );
949     f.ReadInt  ( &serNum     );
950     f.ReadInt  ( &initSeqNum );
951     f.ReadInt  ( &endSeqNum  );
952     f.ReadInt  ( &helixClass );
953     f.ReadInt  ( &length     );
954     f.ReadTerLine ( helixID    ,false );
955     f.ReadTerLine ( initResName,false );
956     f.ReadTerLine ( initChainID,false );
957     f.ReadTerLine ( initICode  ,false );
958     f.ReadTerLine ( endResName ,false );
959     f.ReadTerLine ( endChainID ,false );
960     f.ReadTerLine ( endICode   ,false );
961     f.CreateRead ( comment );
962   }
963 
MakeStreamFunctions(Helix)964   MakeStreamFunctions(Helix)
965 
966 
967 
968   //  ================  Strand  =====================
969 
970   Strand::Strand () : io::Stream()  {
971     InitStrand();
972   }
973 
Strand(io::RPStream Object)974   Strand::Strand ( io::RPStream Object ) : io::Stream(Object)  {
975     InitStrand();
976   }
977 
~Strand()978   Strand::~Strand() {
979   }
980 
InitStrand()981   void  Strand::InitStrand()  {
982     initSeqNum = MinInt4;
983     endSeqNum  = MinInt4;
984     sense      = 0;
985     curResSeq  = MinInt4;
986     prevResSeq = MinInt4;
987     strandNo   = 0;
988     strcpy ( sheetID    ,"sheet_0"  );
989     strcpy ( initResName,"   "      );
990     strcpy ( initChainID,""         );
991     strcpy ( initICode  ,""         );
992     strcpy ( endResName ,"   "      );
993     strcpy ( endChainID ,""         );
994     strcpy ( endICode   ,""         );
995     strcpy ( curAtom    ," "        );
996     strcpy ( curResName ,"   "      );
997     strcpy ( curChainID ,""         );
998     strcpy ( curICode   ,""         );
999     strcpy ( prevAtom   ," "        );
1000     strcpy ( prevResName,"   "      );
1001     strcpy ( prevChainID,""         );
1002     strcpy ( prevICode  ,""         );
1003   }
1004 
PDBASCIIDump(pstr S)1005   void  Strand::PDBASCIIDump ( pstr S )  {
1006   //   Finishes making the ASCII PDB SHEET line number N
1007   // from the class' data. Making is initiated by Sheet.
1008 
1009     strcpy_n1  ( &(S[17]),initResName,3 );
1010     if (initChainID[0])  S[21] = initChainID[0];
1011     PutIntIns  ( &(S[22]),initSeqNum ,4,initICode );
1012 
1013     strcpy_n1  ( &(S[28]),endResName ,3 );
1014     if (endChainID[0])   S[32] = endChainID[0];
1015     PutIntIns  ( &(S[33]),endSeqNum  ,4,endICode  );
1016 
1017     PutInteger ( &(S[38]),sense      ,2 );
1018 
1019     strcpy_n1  ( &(S[41]),curAtom    ,4 );
1020     strcpy_n1  ( &(S[45]),curResName ,3 );
1021     if (curChainID[0])   S[49] = curChainID[0];
1022     PutIntIns  ( &(S[50]),curResSeq  ,4,curICode  );
1023 
1024     strcpy_n1  ( &(S[56]),prevAtom   ,4 );
1025     strcpy_n1  ( &(S[60]),prevResName,3 );
1026     if (prevChainID[0])  S[64] = prevChainID[0];
1027     PutIntIns  ( &(S[65]),prevResSeq ,4,prevICode );
1028 
1029   }
1030 
1031 
MakeCIF(mmcif::PData CIF)1032   void  Strand::MakeCIF ( mmcif::PData CIF )  {
1033   mmcif::PLoop Loop;
1034   int         RC;
1035 
1036     RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_RANGE,Loop );
1037     if (RC!=mmcif::CIFRC_Ok)  {
1038       // the category was (re)created, provide tags
1039       Loop->AddLoopTag ( CIFTAG_SHEET_ID                   );
1040       Loop->AddLoopTag ( CIFTAG_ID                         );
1041       Loop->AddLoopTag ( CIFTAG_BEG_LABEL_COMP_ID          );
1042       Loop->AddLoopTag ( CIFTAG_BEG_LABEL_ASYM_ID          );
1043       Loop->AddLoopTag ( CIFTAG_BEG_LABEL_SEQ_ID           );
1044       Loop->AddLoopTag ( CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB );
1045       Loop->AddLoopTag ( CIFTAG_END_LABEL_COMP_ID          );
1046       Loop->AddLoopTag ( CIFTAG_END_LABEL_ASYM_ID          );
1047       Loop->AddLoopTag ( CIFTAG_END_LABEL_SEQ_ID           );
1048       Loop->AddLoopTag ( CIFTAG_NDB_END_LABEL_INS_CODE_PDB );
1049     }
1050     Loop->AddString  ( sheetID     );
1051     Loop->AddInteger ( strandNo    );
1052     Loop->AddString  ( initResName );
1053     Loop->AddString  ( initChainID );
1054     Loop->AddInteger ( initSeqNum  );
1055     Loop->AddString  ( initICode,true );
1056     Loop->AddString  ( endResName  );
1057     Loop->AddString  ( endChainID  );
1058     Loop->AddInteger ( endSeqNum   );
1059     Loop->AddString  ( endICode ,true );
1060 
1061   }
1062 
1063 
ConvertPDBASCII(cpstr S)1064   ERROR_CODE Strand::ConvertPDBASCII ( cpstr S )  {
1065 
1066     GetInteger  ( strandNo   ,&(S[7])  ,3 );
1067     strcpy_ncss ( sheetID    ,&(S[11]) ,3 );
1068 
1069     strcpy_ncss ( initResName,&(S[17]) ,3 );
1070     strcpy_ncss ( initChainID,&(S[21]) ,1 );
1071     GetIntIns   ( initSeqNum ,initICode,&(S[22]),4 );
1072 
1073     strcpy_ncss ( endResName ,&(S[28]) ,3 );
1074     strcpy_ncss ( endChainID ,&(S[32]) ,1 );
1075     GetIntIns   ( endSeqNum  ,endICode ,&(S[33]),4 );
1076 
1077     GetInteger  ( sense      ,&(S[38]) ,2 );
1078 
1079     GetString   ( curAtom    ,&(S[41]) ,4 );
1080     strcpy_ncss ( curResName ,&(S[45]) ,3 );
1081     strcpy_ncss ( curChainID ,&(S[49]) ,1 );
1082     GetIntIns   ( curResSeq  ,curICode ,&(S[50]),4 );
1083 
1084     GetString   ( prevAtom   ,&(S[56]) ,4 );
1085     strcpy_ncss ( prevResName,&(S[60]) ,3 );
1086     strcpy_ncss ( prevChainID,&(S[64]) ,1 );
1087     GetIntIns   ( prevResSeq ,prevICode,&(S[65]),4 );
1088 
1089     return Error_NoError;
1090 
1091   }
1092 
GetCIF(mmcif::PData CIF,cpstr sheet_id)1093   int  Strand::GetCIF ( mmcif::PData CIF, cpstr sheet_id )  {
1094   mmcif::PLoop Loop;
1095   int         RC,l,i,sNo;
1096   pstr        F;
1097 
1098     Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_RANGE );
1099     if (Loop)  {
1100       l = Loop->GetLoopLength();
1101       i = 0;
1102       while (i<l)  {
1103         F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
1104         if (F && (!RC))  {
1105           if (!strcmp(F,sheet_id))  {
1106             strcpy ( sheetID,sheet_id );
1107             if (CIFGetInteger(sNo,Loop,CIFTAG_ID,i))  return i;
1108             if (sNo==strandNo)  {
1109               CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
1110                              i,sizeof(initResName),pstr("   ") );
1111               CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
1112                              i,sizeof(initChainID),pstr("") );
1113               CIFGetString ( initICode,Loop,
1114                              CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
1115                              i,sizeof(initICode),pstr("") );
1116               if (CIFGetInteger(initSeqNum,Loop,
1117                              CIFTAG_BEG_LABEL_SEQ_ID,i))
1118                 return i;
1119               CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
1120                              i,sizeof(endResName),pstr("   ") );
1121               CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
1122                              i,sizeof(endChainID),pstr("") );
1123               CIFGetString ( endICode  ,Loop,
1124                              CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
1125                              i,sizeof(endICode),pstr("") );
1126               if (CIFGetInteger(endSeqNum,Loop,
1127                              CIFTAG_END_LABEL_SEQ_ID,i))
1128                 return i;
1129               Loop->DeleteRow ( i );
1130               i = l+100;  // break the loop
1131             }
1132           }
1133         }
1134         i++;
1135       }
1136     }
1137 
1138     return 0;
1139 
1140   }
1141 
Copy(PStrand Strand)1142   void  Strand::Copy ( PStrand Strand )  {
1143     initSeqNum = Strand->initSeqNum;
1144     endSeqNum  = Strand->endSeqNum;
1145     sense      = Strand->sense;
1146     curResSeq  = Strand->curResSeq;
1147     prevResSeq = Strand->prevResSeq;
1148     strcpy ( initResName,Strand->initResName );
1149     strcpy ( initChainID,Strand->initChainID );
1150     strcpy ( initICode  ,Strand->initICode   );
1151     strcpy ( endResName ,Strand->endResName  );
1152     strcpy ( endChainID ,Strand->endChainID  );
1153     strcpy ( endICode   ,Strand->endICode    );
1154     strcpy ( curAtom    ,Strand->curAtom     );
1155     strcpy ( curResName ,Strand->curResName  );
1156     strcpy ( curChainID ,Strand->curChainID  );
1157     strcpy ( curICode   ,Strand->curICode    );
1158     strcpy ( prevAtom   ,Strand->prevAtom    );
1159     strcpy ( prevResName,Strand->prevResName );
1160     strcpy ( prevChainID,Strand->prevChainID );
1161     strcpy ( prevICode  ,Strand->prevICode   );
1162   }
1163 
write(io::RFile f)1164   void  Strand::write ( io::RFile f )  {
1165   byte Version=1;
1166     f.WriteByte ( &Version    );
1167     f.WriteInt  ( &initSeqNum );
1168     f.WriteInt  ( &endSeqNum  );
1169     f.WriteInt  ( &sense      );
1170     f.WriteInt  ( &curResSeq  );
1171     f.WriteInt  ( &prevResSeq );
1172     f.WriteTerLine ( initResName,false );
1173     f.WriteTerLine ( initChainID,false );
1174     f.WriteTerLine ( initICode  ,false );
1175     f.WriteTerLine ( endResName ,false );
1176     f.WriteTerLine ( endChainID ,false );
1177     f.WriteTerLine ( endICode   ,false );
1178     f.WriteTerLine ( curAtom    ,false );
1179     f.WriteTerLine ( curResName ,false );
1180     f.WriteTerLine ( curChainID ,false );
1181     f.WriteTerLine ( curICode   ,false );
1182     f.WriteTerLine ( prevAtom   ,false );
1183     f.WriteTerLine ( prevResName,false );
1184     f.WriteTerLine ( prevChainID,false );
1185     f.WriteTerLine ( prevICode  ,false );
1186   }
1187 
read(io::RFile f)1188   void  Strand::read  ( io::RFile f ) {
1189   byte Version;
1190     f.ReadByte ( &Version    );
1191     f.ReadInt  ( &initSeqNum );
1192     f.ReadInt  ( &endSeqNum  );
1193     f.ReadInt  ( &sense      );
1194     f.ReadInt  ( &curResSeq  );
1195     f.ReadInt  ( &prevResSeq );
1196     f.ReadTerLine ( initResName,false );
1197     f.ReadTerLine ( initChainID,false );
1198     f.ReadTerLine ( initICode  ,false );
1199     f.ReadTerLine ( endResName ,false );
1200     f.ReadTerLine ( endChainID ,false );
1201     f.ReadTerLine ( endICode   ,false );
1202     f.ReadTerLine ( curAtom    ,false );
1203     f.ReadTerLine ( curResName ,false );
1204     f.ReadTerLine ( curChainID ,false );
1205     f.ReadTerLine ( curICode   ,false );
1206     f.ReadTerLine ( prevAtom   ,false );
1207     f.ReadTerLine ( prevResName,false );
1208     f.ReadTerLine ( prevChainID,false );
1209     f.ReadTerLine ( prevICode  ,false );
1210   }
1211 
MakeStreamFunctions(Strand)1212   MakeStreamFunctions(Strand)
1213 
1214 
1215 
1216 
1217   //  ================  Sheet  ===================
1218 
1219   Sheet::Sheet() : io::Stream()  {
1220     InitSheet();
1221   }
1222 
Sheet(io::RPStream Object)1223   Sheet::Sheet ( io::RPStream Object ) : io::Stream(Object)  {
1224     InitSheet();
1225   }
1226 
~Sheet()1227   Sheet::~Sheet()  {
1228     FreeMemory();
1229   }
1230 
InitSheet()1231   void  Sheet::InitSheet()  {
1232     nStrands   = 0;
1233     sheetID[0] = char(0);
1234     strand     = NULL;
1235   }
1236 
FreeMemory()1237   void  Sheet::FreeMemory()  {
1238   int i;
1239     if (strand)  {
1240       for (i=0;i<nStrands;i++)
1241         if (strand[i])  delete strand[i];
1242       delete[] strand;
1243       strand = NULL;
1244     }
1245     nStrands   = 0;
1246     sheetID[0] = char(0);
1247   }
1248 
PDBASCIIDump(io::RFile f)1249   void  Sheet::PDBASCIIDump ( io::RFile f )  {
1250   char  S[100];
1251   int   i;
1252     if (strand)
1253       for (i=0;i<nStrands;i++)
1254         if (strand[i])  {
1255           strcpy      ( S,"SHEET"           );
1256           PadSpaces   ( S,80                );
1257           PutInteger  ( &(S[7]) ,i+1     ,3 );
1258           strcpy_n1   ( &(S[11]),sheetID ,3 );
1259           PutInteger  ( &(S[14]),nStrands,2 );
1260           strand[i]->PDBASCIIDump ( S       );
1261           f.WriteLine ( S                   );
1262         }
1263   }
1264 
OrderSheet()1265   void  Sheet::OrderSheet()  {
1266   int       i,k;
1267   PPStrand  strand1;
1268     k = 0;
1269     for (i=0;i<nStrands;i++)
1270       if (strand[i])  k++;
1271     if (k<nStrands)  {
1272       strand1 = new PStrand[k];
1273       k = 0;
1274       for (i=0;i<nStrands;i++)
1275         if (strand[i])  strand1[k++] = strand[i];
1276       if (strand)  delete[] strand;
1277       strand   = strand1;
1278       nStrands = k;
1279     }
1280   }
1281 
MakeCIF(mmcif::PData CIF)1282   void  Sheet::MakeCIF ( mmcif::PData CIF )  {
1283   mmcif::PLoop Loop;
1284   int          RC;
1285   int          i;
1286   bool         isSense;
1287 
1288     OrderSheet();
1289 
1290     RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET,Loop );
1291     if (RC!=mmcif::CIFRC_Ok)  {
1292       // the category was (re)created, provide tags
1293       Loop->AddLoopTag ( CIFTAG_SHEET_ID       );
1294       Loop->AddLoopTag ( CIFTAG_NUMBER_STRANDS );
1295     }
1296     Loop->AddString  ( sheetID  );
1297     Loop->AddInteger ( nStrands );
1298 
1299     for (i=0;i<nStrands;i++)  {
1300       strand[i]->MakeCIF ( CIF );
1301       if (strand[i]->sense!=0)  isSense = true;
1302     }
1303 
1304     if (nStrands>1)  {
1305 
1306       if (isSense)  {
1307         RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_ORDER,Loop );
1308         if (RC!=mmcif::CIFRC_Ok)  {
1309           // the category was (re)created, provide tags
1310           Loop->AddLoopTag ( CIFTAG_SHEET_ID   );
1311           Loop->AddLoopTag ( CIFTAG_RANGE_ID_1 );
1312           Loop->AddLoopTag ( CIFTAG_RANGE_ID_2 );
1313           Loop->AddLoopTag ( CIFTAG_SENSE      );
1314         }
1315         for (i=1;i<nStrands;i++)  {
1316           Loop->AddString  ( sheetID               );
1317           Loop->AddInteger ( strand[i-1]->strandNo );
1318           Loop->AddInteger ( strand[i]  ->strandNo );
1319           if (strand[i]->sense>0)
1320                 Loop->AddString ( pstr("parallel")      );
1321           else  Loop->AddString ( pstr("anti-parallel") );
1322         }
1323       }
1324 
1325       RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_HBOND,Loop );
1326       if (RC!=mmcif::CIFRC_Ok)  {
1327         // the category was (re)created, provide tags
1328         Loop->AddLoopTag ( CIFTAG_SHEET_ID                       );
1329         Loop->AddLoopTag ( CIFTAG_RANGE_ID_1                     );
1330         Loop->AddLoopTag ( CIFTAG_RANGE_ID_2                     );
1331         Loop->AddLoopTag ( CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID      );
1332         Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID  );
1333         Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID  );
1334         Loop->AddLoopTag ( CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID       );
1335         Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE );
1336         Loop->AddLoopTag ( CIFTAG_RANGE_1_END_LABEL_ATOM_ID      );
1337         Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID  );
1338         Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID  );
1339         Loop->AddLoopTag ( CIFTAG_RANGE_1_END_LABEL_SEQ_ID       );
1340         Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE );
1341       }
1342       for (i=1;i<nStrands;i++)  {
1343         Loop->AddString  ( sheetID                );
1344         Loop->AddInteger ( strand[i-1]->strandNo  );
1345         Loop->AddInteger ( strand[i]->strandNo    );
1346         Loop->AddString  ( strand[i]->curAtom     );
1347         Loop->AddString  ( strand[i]->curResName  );
1348         Loop->AddString  ( strand[i]->curChainID  );
1349         Loop->AddInteger ( strand[i]->curResSeq   );
1350         Loop->AddString  ( strand[i]->curICode ,true );
1351         Loop->AddString  ( strand[i]->prevAtom    );
1352         Loop->AddString  ( strand[i]->prevResName );
1353         Loop->AddString  ( strand[i]->prevChainID );
1354         Loop->AddInteger ( strand[i]->prevResSeq  );
1355         Loop->AddString  ( strand[i]->prevICode,true );
1356       }
1357     }
1358 
1359   }
1360 
1361 
ConvertPDBASCII(cpstr S)1362   ERROR_CODE Sheet::ConvertPDBASCII ( cpstr S )  {
1363   int       i,k,ns;
1364   SheetID   SID;
1365   PPStrand  strand1;
1366 
1367     GetInteger  ( k  ,&(S[7]) ,3 );
1368     strcpy_ncss ( SID,&(S[11]),3 );
1369     GetInteger  ( ns ,&(S[14]),2 );
1370 
1371   //  if (!SID[0])  return  Error_NoSheetID;
1372     if (!sheetID[0])  strcpy ( sheetID,SID );
1373     else if (strcmp(sheetID,SID))
1374                   return  Error_WrongSheetID;
1375 
1376     if (k<=0)     return  Error_WrongStrandNo;
1377 
1378     ns = IMax(k,ns);
1379     if (!strand)  {
1380       strand = new PStrand[ns];
1381       for (i=0;i<ns;i++)
1382         strand[i] = NULL;
1383     } else if (ns>nStrands)  {
1384       strand1 = new PStrand[ns];
1385       for (i=0;i<nStrands;i++)
1386         strand1[i] = strand[i];
1387       for (i=nStrands;i<ns;i++)
1388         strand1[i] = NULL;
1389       if (strand)  delete[] strand;
1390       strand = strand1;
1391     }
1392     nStrands = ns;
1393 
1394     k--;
1395     if (!strand[k])  strand[k] = new Strand();
1396 
1397     return  strand[k]->ConvertPDBASCII ( S );
1398 
1399   }
1400 
TryStrand(int strand_no)1401   void  Sheet::TryStrand ( int strand_no )  {
1402   int      i,k;
1403   PPStrand strand1;
1404     k = -1;
1405     for (i=0;(i<nStrands) && (k<0);i++)
1406       if (strand[i])
1407         if (strand[i]->strandNo==strand_no)  k = i;
1408     if (k<0)  {
1409       strand1 = new PStrand[nStrands+1];
1410       for (i=0;i<nStrands;i++)
1411         strand1[i] = strand[i];
1412       if (strand) delete[] strand;
1413       strand = strand1;
1414       strand[nStrands] = new Strand();
1415       strand[nStrands]->strandNo = strand_no;
1416       nStrands++;
1417     }
1418   }
1419 
1420 
CIFFindStrands(mmcif::PData CIF,cpstr Category)1421   void  Sheet::CIFFindStrands ( mmcif::PData CIF, cpstr Category ) {
1422   // just look for all strands mentioned for the sheet
1423   mmcif::PLoop Loop;
1424   pstr         F;
1425   int          RC,i,l,sNo;
1426     Loop = CIF->GetLoop ( Category );
1427     if (Loop)  {
1428       l = Loop->GetLoopLength();
1429       for (i=0;i<l;i++)  {
1430         F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
1431         if (F && (!RC))  {
1432           if (!strcmp(F,sheetID))  {
1433             if (!Loop->GetInteger(sNo,CIFTAG_ID,i))
1434               TryStrand ( sNo );
1435             if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))
1436               TryStrand ( sNo );
1437             if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_2,i))
1438               TryStrand ( sNo );
1439           }
1440         }
1441       }
1442     }
1443   }
1444 
GetStrand(int strand_no)1445   int  Sheet::GetStrand ( int strand_no )  {
1446   int i;
1447     for (i=0;i<nStrands;i++)
1448       if (strand[i])  {
1449         if (strand[i]->strandNo==strand_no)
1450           return i;
1451       }
1452     return -1;
1453   }
1454 
GetCIF(mmcif::PData CIF)1455   int Sheet::GetCIF ( mmcif::PData CIF )  {
1456   mmcif::PLoop Loop;
1457   int         i,ns,l,k,k2,RC,sNo;
1458   pstr        F;
1459   ivector     pair;
1460   bool     Ok;
1461 
1462     pair = NULL;
1463 
1464     //    First find all strands and create
1465     // the corresponding classes. The CIF fields
1466     // are not removed at this stage.
1467 
1468     CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_ORDER );
1469     CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_RANGE );
1470     CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_HBOND );
1471 
1472     //  Check number of strands
1473     Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET );
1474     if (Loop)  {
1475       l = Loop->GetLoopLength();
1476       i = 0;
1477       while (i<l)  {
1478         F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
1479         if (F && (!RC))  {
1480           if (!strcmp(F,sheetID))  {
1481             RC = CIFGetInteger1 ( ns,Loop,CIFTAG_NUMBER_STRANDS,i );
1482             if ((!RC) && (ns!=nStrands))
1483               return  Error_WrongNumberOfStrands;
1484             Loop->DeleteRow ( i );
1485             i = l+100;  // break loop
1486           }
1487         }
1488         i++;
1489       }
1490     }
1491 
1492     //  Read each strand
1493     RC = 0;
1494     for (i=0;(i<nStrands) && (!RC);i++)
1495       RC = strand[i]->GetCIF ( CIF,sheetID );
1496 
1497     if (RC)  return RC;
1498 
1499     if (nStrands>1)  {
1500 
1501       GetVectorMemory ( pair,nStrands,0 );
1502       for (i=0;i<nStrands;i++)
1503         pair[i] = -1;
1504 
1505       Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_ORDER );
1506       if (Loop)  {
1507         Ok = true;
1508         l  = Loop->GetLoopLength();
1509         for (i=0;(i<l) && Ok;i++)  {
1510           F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
1511           if (F && (!RC))  {
1512             if (!strcmp(F,sheetID))  {
1513               if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))  {
1514                 k = GetStrand ( sNo );
1515                 if ((k>=0) &&
1516                     (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_2,i)))  {
1517                   pair[k] = GetStrand ( sNo );
1518                   if (pair[k]>=0)  {
1519                     F = Loop->GetString ( CIFTAG_SENSE,i,RC );
1520                     if (F && (!RC))  {
1521                       if (!strcasecmp(F,"anti-parallel"))
1522                         strand[pair[k]]->sense = -1;
1523                       else if (!strcasecmp(F,"parallel"))
1524                         strand[pair[k]]->sense =  1;
1525                     }
1526                     Loop->DeleteRow ( i );
1527                   } else
1528                     Ok = false;
1529                 } else
1530                   Ok = false;
1531               } else
1532                 Ok = false;
1533             }
1534           }
1535         }
1536         if (!Ok)  {
1537           FreeVectorMemory ( pair,0 );
1538           return Error_WrongSheetOrder;
1539         }
1540       }
1541 
1542       Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_HBOND );
1543       if (Loop)  {
1544         Ok = true;
1545         l  = Loop->GetLoopLength();
1546         for (i=0;(i<l) && Ok;i++)  {
1547           F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
1548           if (F && (!RC))  {
1549             if (!strcmp(F,sheetID))  {
1550               if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))  {
1551                 k = GetStrand ( sNo );
1552                 if ((k>=0) &&
1553                     (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i)))  {
1554                   k2 = GetStrand ( sNo );
1555                   if (k2>=0)  {
1556                     if (pair[k]==k2)  {
1557                       CIFGetString ( strand[k2]->curAtom,Loop,
1558                                 CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID,
1559                                 i,sizeof(strand[k2]->curAtom),
1560                                 pstr("    ") );
1561                       CIFGetString ( strand[k2]->curResName,Loop,
1562                                 CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID,
1563                                 i,sizeof(strand[k2]->curResName),
1564                                 pstr("   ") );
1565                       CIFGetString ( strand[k2]->curChainID,Loop,
1566                                 CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID,
1567                                 i,sizeof(strand[k2]->curChainID),
1568                                 pstr(" ") );
1569                       if (CIFGetInteger(strand[k2]->curResSeq,Loop,
1570                                 CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID,i))  {
1571                         FreeVectorMemory ( pair,0 );
1572                         return i;
1573                       }
1574                       CIFGetString ( strand[k2]->curICode,Loop,
1575                                 CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE,
1576                                 i,sizeof(strand[k2]->curICode),
1577                                 pstr(" ") );
1578                       CIFGetString ( strand[k2]->prevAtom,Loop,
1579                                 CIFTAG_RANGE_1_END_LABEL_ATOM_ID,
1580                                 i,sizeof(strand[k2]->prevAtom),
1581                                 pstr("    ") );
1582                       CIFGetString ( strand[k2]->prevResName,Loop,
1583                                 CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID,
1584                                 i,sizeof(strand[k2]->prevResName),
1585                                 pstr("   ") );
1586                       CIFGetString ( strand[k2]->prevChainID,Loop,
1587                                 CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID,
1588                                 i,sizeof(strand[k2]->prevChainID),
1589                                 pstr(" ") );
1590                       if (CIFGetInteger(strand[k2]->prevResSeq,Loop,
1591                                 CIFTAG_RANGE_1_END_LABEL_SEQ_ID,i))  {
1592                         FreeVectorMemory ( pair,0 );
1593                         return i;
1594                       }
1595                       CIFGetString ( strand[k2]->prevICode,Loop,
1596                                 CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE,
1597                                 i,sizeof(strand[k2]->prevICode),
1598                                 pstr(" ") );
1599                       Loop->DeleteRow ( i );
1600                     } else
1601                         Ok = false;
1602                   } else
1603                     Ok = false;
1604                 } else
1605                   Ok = false;
1606               } else
1607                 Ok = false;
1608             }
1609           }
1610         }
1611         if (!Ok)  {
1612           FreeVectorMemory ( pair,0 );
1613           return Error_HBondInconsistency;
1614         }
1615       }
1616     }
1617 
1618     FreeVectorMemory ( pair,0 );
1619 
1620     return 0;
1621 
1622   }
1623 
1624 
Copy(PSheet Sheet)1625   void  Sheet::Copy ( PSheet Sheet )  {
1626   int i;
1627     FreeMemory();
1628     nStrands = Sheet->nStrands;
1629     if (nStrands>0)  {
1630       strand = new PStrand[nStrands];
1631       for (i=0;i<nStrands;i++)
1632         if (Sheet->strand[i])  {
1633           strand[i] = new Strand();
1634           strand[i]->Copy ( Sheet->strand[i] );
1635         } else
1636           strand[i] = NULL;
1637     }
1638     strcpy ( sheetID,Sheet->sheetID );
1639   }
1640 
write(io::RFile f)1641   void  Sheet::write ( io::RFile f )  {
1642   int  i;
1643   byte Version=1;
1644     f.WriteByte ( &Version  );
1645     f.WriteInt  ( &nStrands );
1646     for (i=0;i<nStrands;i++)
1647       StreamWrite ( f,strand[i] );
1648     f.WriteTerLine ( sheetID,false );
1649   }
1650 
read(io::RFile f)1651   void  Sheet::read  ( io::RFile f ) {
1652   int  i;
1653   byte Version;
1654     FreeMemory();
1655     f.ReadByte ( &Version  );
1656     f.ReadInt  ( &nStrands );
1657     if (nStrands>0)  {
1658       strand = new PStrand[nStrands];
1659       for (i=0;i<nStrands;i++)  {
1660         strand[i] = NULL;
1661         StreamRead ( f,strand[i] );
1662       }
1663     }
1664     f.ReadTerLine ( sheetID,false );
1665   }
1666 
MakeStreamFunctions(Sheet)1667   MakeStreamFunctions(Sheet)
1668 
1669 
1670 
1671   //  ====================  Sheets  ============================
1672 
1673 
1674   Sheets::Sheets() : io::Stream()  {
1675     InitSheets();
1676   }
1677 
1678 
Sheets(io::RPStream Object)1679   Sheets::Sheets ( io::RPStream Object ) : io::Stream ( Object )  {
1680     InitSheets();
1681   }
1682 
1683 
~Sheets()1684   Sheets::~Sheets()  {
1685     FreeMemory();
1686   }
1687 
1688 
InitSheets()1689   void  Sheets::InitSheets()  {
1690     nSheets = 0;
1691     sheet   = NULL;
1692   }
1693 
1694 
FreeMemory()1695   void  Sheets::FreeMemory()  {
1696   int i;
1697     if (sheet)  {
1698       for (i=0;i<nSheets;i++)
1699         if (sheet[i])  delete sheet[i];
1700       delete[] sheet;
1701       sheet = NULL;
1702     }
1703     nSheets = 0;
1704   }
1705 
1706 
PDBASCIIDump(io::RFile f)1707   void  Sheets::PDBASCIIDump ( io::RFile f )  {
1708   int i;
1709     if (sheet)
1710       for (i=0;i<nSheets;i++)
1711         if (sheet[i])  sheet[i]->PDBASCIIDump ( f );
1712   }
1713 
1714 
MakeCIF(mmcif::PData CIF)1715   void  Sheets::MakeCIF ( mmcif::PData CIF )  {
1716   int i;
1717     if (sheet)
1718       for (i=0;i<nSheets;i++)
1719         if (sheet[i])  sheet[i]->MakeCIF ( CIF );
1720   }
1721 
1722 
ConvertPDBASCII(cpstr S)1723   ERROR_CODE  Sheets::ConvertPDBASCII ( cpstr S )  {
1724   PPSheet  sheet1;
1725   SheetID  sheetID;
1726   int      i,k;
1727     strcpy_ncss ( sheetID,&(S[11]),3 );
1728     //  if (!sheetID[0]) return  Error_NoSheetID;
1729     k = -1;
1730     for (i=0;i<nSheets;i++)
1731       if (sheet[i])  {
1732         if (!strcmp(sheetID,sheet[i]->sheetID))  {
1733           k = i;
1734           break;
1735         }
1736       }
1737     if (k<0)  {
1738       sheet1 = new PSheet[nSheets+1];
1739       for (i=0;i<nSheets;i++)
1740         sheet1[i] = sheet[i];
1741       if (sheet) delete[] sheet;
1742       sheet = sheet1;
1743       sheet[nSheets] = new Sheet();
1744       k = nSheets;
1745       nSheets++;
1746     }
1747     return  sheet[k]->ConvertPDBASCII ( S );
1748   }
1749 
1750 
CIFFindSheets(mmcif::PData CIF,cpstr Category)1751   void  Sheets::CIFFindSheets ( mmcif::PData CIF, cpstr Category ) {
1752   mmcif::PLoop Loop;
1753   int          RC,i,j,k,l;
1754   pstr         F;
1755   PPSheet      sheet1;
1756     Loop = CIF->GetLoop ( Category );
1757     if (Loop)  {
1758       l = Loop->GetLoopLength();
1759       for (i=0;i<l;i++)  {
1760         F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
1761         if (F && (!RC))  {
1762           k = -1;
1763           j = 0;
1764           while ((j<nSheets) && (k<0))  {
1765             if (sheet[j])  {
1766               if (!strcmp(F,sheet[j]->sheetID))  k = j;
1767             }
1768             j++;
1769           }
1770           if (k<0)  {
1771             sheet1 = new PSheet[nSheets+1];
1772             for (i=0;i<nSheets;i++)
1773               sheet1[i] = sheet[i];
1774             if (sheet) delete[] sheet;
1775             sheet = sheet1;
1776             sheet[nSheets] = new Sheet();
1777             strcpy ( sheet[nSheets]->sheetID,F );
1778             nSheets++;
1779           }
1780         }
1781       }
1782     }
1783   }
1784 
GetCIF(mmcif::PData CIF)1785   int Sheets::GetCIF ( mmcif::PData CIF )  {
1786   int i,RC;
1787 
1788     FreeMemory();
1789 
1790     //  First find all sheet names and create
1791     // the corresponding classes. The CIF fields
1792     // are not removed at this stage.
1793 
1794     CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET       );
1795     CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_ORDER );
1796     CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_RANGE );
1797     CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_HBOND );
1798 
1799     //  Read each sheet
1800     i  = 0;
1801     RC = 0;
1802     while ((i<nSheets) && (!RC))  {
1803       RC = sheet[i]->GetCIF ( CIF );
1804       i++;
1805     }
1806 
1807     return RC;
1808 
1809   }
1810 
1811 
Copy(PSheets Sheets)1812   void  Sheets::Copy ( PSheets Sheets )  {
1813   int i;
1814     FreeMemory();
1815     if (Sheets->nSheets>0)  {
1816       nSheets = Sheets->nSheets;
1817       sheet = new PSheet[nSheets];
1818       for (i=0;i<nSheets;i++)
1819         if (Sheets->sheet[i]) {
1820           sheet[i] = new Sheet();
1821           sheet[i]->Copy ( Sheets->sheet[i] );
1822         } else
1823           sheet[i] = NULL;
1824     }
1825   }
1826 
1827 
write(io::RFile f)1828   void  Sheets::write ( io::RFile f )  {
1829   int  i;
1830   byte Version=1;
1831     f.WriteByte ( &Version );
1832     f.WriteInt  ( &nSheets );
1833     for (i=0;i<nSheets;i++)
1834       StreamWrite ( f,sheet[i] );
1835   }
1836 
1837 
read(io::RFile f)1838   void  Sheets::read ( io::RFile f )  {
1839   int  i;
1840   byte Version;
1841     FreeMemory();
1842     f.ReadByte ( &Version );
1843     f.ReadInt  ( &nSheets );
1844     if (nSheets>0)  {
1845       sheet = new PSheet[nSheets];
1846       for (i=0;i<nSheets;i++)  {
1847         sheet[i] = NULL;
1848         StreamRead ( f,sheet[i] );
1849       }
1850     }
1851   }
1852 
1853 
MakeStreamFunctions(Sheets)1854   MakeStreamFunctions(Sheets)
1855 
1856 
1857 
1858   //  ================  Turn  ===================
1859 
1860   Turn::Turn() : ContainerClass()  {
1861     InitTurn();
1862   }
1863 
Turn(cpstr S)1864   Turn::Turn ( cpstr S ) : ContainerClass()  {
1865     InitTurn();
1866     ConvertPDBASCII ( S );
1867   }
1868 
Turn(io::RPStream Object)1869   Turn::Turn ( io::RPStream Object ) : ContainerClass(Object)  {
1870     InitTurn();
1871   }
1872 
~Turn()1873   Turn::~Turn() {
1874     if (comment)  delete[] comment;
1875   }
1876 
InitTurn()1877   void  Turn::InitTurn()  {
1878     serNum = 0;                   // serial number
1879     strcpy ( turnID     ,"---" ); // turn ID
1880     strcpy ( initResName,"---" ); // name of the turn's initial residue
1881     strcpy ( initChainID," "   ); // chain ID for the chain
1882                                   // containing the turn
1883     initSeqNum = 0;               // sequence number of the initial
1884                                   //    residue
1885     strcpy ( initICode  ," "   ); // insertion code of the initial
1886                                   //    residue
1887     strcpy ( endResName ,"---" ); // name of the turn's terminal residue
1888     strcpy ( endChainID ," "   ); // chain ID for the chain
1889                                   // containing the turn
1890     endSeqNum  = 0;               // sequence number of the terminal
1891                                   //    residue
1892     strcpy ( endICode   ," "   ); // insertion code of the terminal
1893                                   //    residue
1894     comment    = NULL;            // comment about the helix
1895   }
1896 
PDBASCIIDump(pstr S,int N)1897   void  Turn::PDBASCIIDump ( pstr S, int N )  {
1898   UNUSED_ARGUMENT(N);
1899   //  makes the ASCII PDB OBSLTE line number N
1900   //  from the class' data
1901     strcpy     ( S,"TURN" );
1902     PadSpaces  ( S,80 );
1903     PutInteger ( &(S[7]) ,serNum     ,3  );
1904     strcpy_n1  ( &(S[11]),turnID     ,3  );
1905     strcpy_n1  ( &(S[15]),initResName,3  );
1906     strcpy_n1  ( &(S[19]),initChainID,1  );
1907     PutIntIns  ( &(S[20]),initSeqNum ,4,initICode );
1908     strcpy_n1  ( &(S[26]),endResName ,3  );
1909     strcpy_n1  ( &(S[30]),endChainID ,1  );
1910     PutIntIns  ( &(S[31]),endSeqNum  ,4,endICode  );
1911     if (comment)
1912       strcpy_n ( &(S[40]),comment    ,30 );
1913   }
1914 
1915 
1916   #define  TurnTypeID  "TURN_P"
1917 
MakeCIF(mmcif::PData CIF,int N)1918   void  Turn::MakeCIF ( mmcif::PData CIF, int N )  {
1919   UNUSED_ARGUMENT(N);
1920   mmcif::PLoop Loop;
1921   int         RC;
1922     RC = CIF->AddLoop ( CIFCAT_STRUCT_CONF,Loop );
1923     if (RC!=mmcif::CIFRC_Ok)
1924       // the category was (re)created, provide tags
1925       AddStructConfTags ( Loop );
1926     Loop->AddString  ( pstr(TurnTypeID) );
1927     Loop->AddInteger ( serNum      );
1928     Loop->AddString  ( turnID      );
1929     Loop->AddString  ( initResName );
1930     Loop->AddString  ( initChainID );
1931     Loop->AddInteger ( initSeqNum  );
1932     Loop->AddString  ( initICode,true );
1933     Loop->AddString  ( endResName  );
1934     Loop->AddString  ( endChainID  );
1935     Loop->AddInteger ( endSeqNum   );
1936     Loop->AddString  ( endICode ,true );
1937     Loop->AddNoData  ( mmcif::CIF_NODATA_QUESTION );
1938     Loop->AddString  ( comment     );
1939     Loop->AddNoData  ( mmcif::CIF_NODATA_QUESTION );
1940   }
1941 
ConvertPDBASCII(cpstr S)1942   ERROR_CODE Turn::ConvertPDBASCII ( cpstr S )  {
1943   char L[100];
1944     GetInteger   ( serNum     ,&(S[7]) ,3  );
1945     strcpy_ncss  ( turnID     ,&(S[11]),3  );
1946     strcpy_ncss  ( initResName,&(S[15]),3  );
1947     strcpy_ncss  ( initChainID,&(S[19]),1  );
1948     GetIntIns    ( initSeqNum,initICode,&(S[20]),4 );
1949     strcpy_ncss  ( endResName ,&(S[26]),3  );
1950     strcpy_ncss  ( endChainID ,&(S[30]),1  );
1951     GetIntIns    ( endSeqNum ,endICode ,&(S[31]),4 );
1952     strcpy_ncss  ( L          ,&(S[40]),30 );
1953     CreateCopy   ( comment    ,L           );
1954     return Error_NoError;
1955   }
1956 
GetCIF(mmcif::PData CIF,int & n)1957   ERROR_CODE Turn::GetCIF ( mmcif::PData CIF, int & n )  {
1958   mmcif::PLoop Loop;
1959   int          RC,l;
1960   pstr         F;
1961   bool         Done;
1962   ERROR_CODE   rc;
1963 
1964     Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONF );
1965     if (!Loop)  {
1966       n = -1;  // signal to finish processing of this structure
1967       return Error_EmptyCIF;
1968     }
1969 
1970     l    = Loop->GetLoopLength();
1971     Done = n>=l;
1972     while (!Done) {
1973       F = Loop->GetString ( CIFTAG_CONF_TYPE_ID,n,RC );
1974       if ((!RC) && F)  Done = (strcmp(F,TurnTypeID)==0);
1975                  else  Done = false;
1976       if (!Done)  {
1977         n++;
1978         Done = n>=l;
1979       }
1980     }
1981 
1982     if (n>=l)  {
1983       n = -1;  // finish processing of Turn
1984       return Error_EmptyCIF;
1985     }
1986 
1987     Loop->DeleteField ( CIFTAG_CONF_TYPE_ID,n );
1988 
1989     rc = CIFGetInteger ( serNum,Loop,CIFTAG_ID,n );
1990     if (rc==Error_NoData)   return Error_EmptyCIF;
1991     if (rc!=Error_NoError)  return rc;
1992 
1993     CIFGetString ( turnID,Loop,CIFTAG_PDB_ID,n,
1994                    sizeof(turnID),pstr("   ") );
1995 
1996     CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
1997                                n,sizeof(initResName),pstr("   ") );
1998     CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
1999                                n,sizeof(initChainID),pstr(" ") );
2000     CIFGetString ( initICode  ,Loop,CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
2001                                n,sizeof(initICode),pstr(" ") );
2002     rc = CIFGetInteger ( initSeqNum,Loop,CIFTAG_BEG_LABEL_SEQ_ID,n );
2003     if (rc==Error_NoData)   return Error_EmptyCIF;
2004     if (rc!=Error_NoError)  return rc;
2005 
2006     CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
2007                               n,sizeof(endResName),pstr("   ") );
2008     CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
2009                               n,sizeof(endChainID),pstr(" ") );
2010     CIFGetString ( endICode  ,Loop,CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
2011                               n,sizeof(endICode),pstr(" ") );
2012     rc = CIFGetInteger ( endSeqNum,Loop,CIFTAG_END_LABEL_SEQ_ID,n );
2013     if (rc==Error_NoData)   return Error_EmptyCIF;
2014     if (rc!=Error_NoError)  return rc;
2015 
2016     CreateCopy      ( comment,Loop->GetString(CIFTAG_DETAILS,n,RC));
2017     Loop->DeleteField ( CIFTAG_DETAILS,n );
2018 
2019     n++;
2020 
2021     return Error_NoError;
2022 
2023   }
2024 
Copy(PContainerClass Turn)2025   void  Turn::Copy ( PContainerClass Turn )  {
2026     serNum     = PTurn(Turn)->serNum;
2027     initSeqNum = PTurn(Turn)->initSeqNum;
2028     endSeqNum  = PTurn(Turn)->endSeqNum;
2029     strcpy ( turnID     ,PTurn(Turn)->turnID      );
2030     strcpy ( initResName,PTurn(Turn)->initResName );
2031     strcpy ( initChainID,PTurn(Turn)->initChainID );
2032     strcpy ( initICode  ,PTurn(Turn)->initICode   );
2033     strcpy ( endResName ,PTurn(Turn)->endResName  );
2034     strcpy ( endChainID ,PTurn(Turn)->endChainID  );
2035     strcpy ( endICode   ,PTurn(Turn)->endICode    );
2036     CreateCopy ( comment,PTurn(Turn)->comment );
2037   }
2038 
write(io::RFile f)2039   void  Turn::write ( io::RFile f )  {
2040   byte Version=1;
2041     f.WriteByte ( &Version    );
2042     f.WriteInt  ( &serNum     );
2043     f.WriteInt  ( &initSeqNum );
2044     f.WriteInt  ( &endSeqNum  );
2045     f.WriteTerLine ( turnID     ,false );
2046     f.WriteTerLine ( initResName,false );
2047     f.WriteTerLine ( initChainID,false );
2048     f.WriteTerLine ( initICode  ,false );
2049     f.WriteTerLine ( endResName ,false );
2050     f.WriteTerLine ( endChainID ,false );
2051     f.WriteTerLine ( endICode   ,false );
2052     f.CreateWrite ( comment );
2053   }
2054 
read(io::RFile f)2055   void  Turn::read ( io::RFile f )  {
2056   byte Version;
2057     f.ReadByte ( &Version );
2058     f.ReadInt  ( &serNum     );
2059     f.ReadInt  ( &initSeqNum );
2060     f.ReadInt  ( &endSeqNum  );
2061     f.ReadTerLine ( turnID     ,false );
2062     f.ReadTerLine ( initResName,false );
2063     f.ReadTerLine ( initChainID,false );
2064     f.ReadTerLine ( initICode  ,false );
2065     f.ReadTerLine ( endResName ,false );
2066     f.ReadTerLine ( endChainID ,false );
2067     f.ReadTerLine ( endICode   ,false );
2068     f.CreateRead ( comment );
2069   }
2070 
MakeStreamFunctions(Turn)2071   MakeStreamFunctions(Turn)
2072 
2073 
2074   //  ===================  LinkContainer  ========================
2075 
2076   PContainerClass LinkContainer::MakeContainerClass ( int ClassID )  {
2077     switch (ClassID)  {
2078       default :
2079       case ClassID_Template : return
2080                           ClassContainer::MakeContainerClass(ClassID);
2081       case ClassID_Link    : return new Link();
2082     }
2083   }
2084 
MakeStreamFunctions(LinkContainer)2085   MakeStreamFunctions(LinkContainer)
2086 
2087 
2088 
2089   //  ========================  Link  ===========================
2090 
2091   Link::Link() : ContainerClass()  {
2092     InitLink();
2093   }
2094 
Link(cpstr S)2095   Link::Link ( cpstr S ) : ContainerClass()  {
2096     InitLink();
2097     ConvertPDBASCII ( S );
2098   }
2099 
Link(io::RPStream Object)2100   Link::Link ( io::RPStream Object ) : ContainerClass(Object)  {
2101     InitLink();
2102   }
2103 
~Link()2104   Link::~Link() {}
2105 
InitLink()2106   void  Link::InitLink()  {
2107     strcpy ( atName1 ,"----" );  // name of 1st linked atom
2108     strcpy ( aloc1   ," "    );  // alternative location of 1st atom
2109     strcpy ( resName1,"---"  );  // residue name of 1st linked atom
2110     strcpy ( chainID1," "    );  // chain ID of 1st linked atom
2111     seqNum1 = 0;                 // sequence number of 1st linked atom
2112     strcpy ( insCode1," "    );  // insertion code of 1st linked atom
2113     strcpy ( atName2 ,"----" );  // name of 2nd linked atom
2114     strcpy ( aloc2   ," "    );  // alternative location of 2nd atom
2115     strcpy ( resName2,"---"  );  // residue name of 2nd linked atom
2116     strcpy ( chainID2," "    );  // chain ID of 2nd linked atom
2117     seqNum2 = 0;                 // sequence number of 2nd linked atom
2118     strcpy ( insCode2," "    );  // insertion code of 2nd linked atom
2119     s1   = 1;  // sym id of 1st atom
2120     i1   = 5;
2121     j1   = 5;
2122     k1   = 5;
2123     s2   = 1;  // sym id of 2nd atom
2124     i2   = 5;
2125     j2   = 5;
2126     k2   = 5;
2127     dist = -1.0;  // no distance
2128   }
2129 
2130 
PDBASCIIDump(pstr S,int N)2131   void  Link::PDBASCIIDump ( pstr S, int N )  {
2132   UNUSED_ARGUMENT(N);
2133   //  makes the ASCII PDB OBSLTE line number N
2134   //  from the class' data
2135 
2136     strcpy     ( S,"LINK" );
2137     PadSpaces  ( S,80 );
2138 
2139     strcpy_n1  ( &(S[12]),atName1 ,4 );
2140     strcpy_n1  ( &(S[16]),aloc1   ,1 );
2141     strcpy_n1  ( &(S[17]),resName1,3 );
2142     strcpy_n1  ( &(S[21]),chainID1,1 );
2143     PutIntIns  ( &(S[22]),seqNum1 ,4,insCode1 );
2144 
2145     strcpy_n1  ( &(S[42]),atName2 ,4 );
2146     strcpy_n1  ( &(S[46]),aloc2   ,1 );
2147     strcpy_n1  ( &(S[47]),resName2,3 );
2148     strcpy_n1  ( &(S[51]),chainID2,1 );
2149     PutIntIns  ( &(S[52]),seqNum2 ,4,insCode2 );
2150 
2151     PutInteger ( &(S[59]),s1,3 );
2152     PutInteger ( &(S[62]),i1,1 );
2153     PutInteger ( &(S[63]),j1,1 );
2154     PutInteger ( &(S[64]),k1,1 );
2155 
2156     PutInteger ( &(S[66]),s2,3 );
2157     PutInteger ( &(S[69]),i2,1 );
2158     PutInteger ( &(S[70]),j2,1 );
2159     PutInteger ( &(S[71]),k2,1 );
2160 
2161     if (dist>0.0)
2162       PutRealF ( &(S[73]),dist,5,3 );
2163 
2164   }
2165 
2166 
2167   #define  LinkTypeID  "LINK"
2168 
AddStructConnTags(mmcif::PLoop Loop)2169   void AddStructConnTags ( mmcif::PLoop Loop )  {
2170 
2171     Loop->AddLoopTag ( CIFTAG_ID                           );
2172     Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID                 );
2173 
2174     Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ATOM_ID      );
2175     Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID  );
2176     Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_COMP_ID      );
2177     Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ASYM_ID      );
2178     Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_SEQ_ID       );
2179     Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE );
2180 
2181     Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ATOM_ID      );
2182     Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID  );
2183     Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_COMP_ID      );
2184     Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ASYM_ID      );
2185     Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_SEQ_ID       );
2186     Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE );
2187 
2188     Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_SYMMETRY );
2189     Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_SYMMETRY );
2190 
2191     Loop->AddLoopTag ( CIFTAG_CONN_DIST );
2192 
2193   }
2194 
2195 
MakeCIF(mmcif::PData CIF,int N)2196   void  Link::MakeCIF ( mmcif::PData CIF, int N )  {
2197   UNUSED_ARGUMENT(N);
2198   mmcif::PLoop Loop;
2199   char        S[100];
2200   int         RC;
2201 
2202     RC = CIF->AddLoop ( CIFCAT_STRUCT_CONN,Loop );
2203     if (RC!=mmcif::CIFRC_Ok) // the category was (re)created, provide tags
2204       AddStructConnTags ( Loop );
2205 
2206     Loop->AddString  ( "1"      );  // should be a counter
2207     Loop->AddString  ( pstr(LinkTypeID) );
2208 
2209     Loop->AddString  ( atName1  );
2210     Loop->AddString  ( aloc1    );
2211     Loop->AddString  ( resName1 );
2212     Loop->AddString  ( chainID1 );
2213     Loop->AddInteger ( seqNum1  );
2214     Loop->AddString  ( insCode1 );
2215 
2216     Loop->AddString  ( atName2  );
2217     Loop->AddString  ( aloc2    );
2218     Loop->AddString  ( resName2 );
2219     Loop->AddString  ( chainID2 );
2220     Loop->AddInteger ( seqNum2  );
2221     Loop->AddString  ( insCode2 );
2222 
2223     sprintf ( S,"%i%i%i%i",s1,i1,j1,k1 );
2224     Loop->AddString  ( S );
2225     sprintf ( S,"%i%i%i%i",s2,i2,j2,k2 );
2226     Loop->AddString  ( S );
2227 
2228     Loop->AddReal    ( dist     );
2229 
2230   }
2231 
ConvertPDBASCII(cpstr S)2232   ERROR_CODE Link::ConvertPDBASCII ( cpstr S )  {
2233 
2234     GetString    ( atName1 ,&(S[12]),4 );
2235     strcpy_ncss  ( aloc1   ,&(S[16]),1 );
2236     strcpy_ncss  ( resName1,&(S[17]),3 );
2237     strcpy_ncss  ( chainID1,&(S[21]),1 );
2238     GetIntIns    ( seqNum1,insCode1,&(S[22]),4 );
2239 
2240     GetString    ( atName2 ,&(S[42]),4 );
2241     strcpy_ncss  ( aloc2   ,&(S[46]),1 );
2242     strcpy_ncss  ( resName2,&(S[47]),3 );
2243     strcpy_ncss  ( chainID2,&(S[51]),1 );
2244     GetIntIns    ( seqNum2,insCode2,&(S[52]),4 );
2245 
2246     GetInteger   ( s1,&(S[59]),3 );
2247     GetInteger   ( i1,&(S[62]),1 );
2248     GetInteger   ( j1,&(S[63]),1 );
2249     GetInteger   ( k1,&(S[64]),1 );
2250 
2251     GetInteger   ( s2,&(S[66]),3 );
2252     GetInteger   ( i2,&(S[69]),1 );
2253     GetInteger   ( j2,&(S[70]),1 );
2254     GetInteger   ( k2,&(S[71]),1 );
2255 
2256     if (!GetReal(dist,&(S[73]),5))  dist = -1.0;
2257 
2258     return Error_NoError;
2259 
2260   }
2261 
GetCIF(mmcif::PData CIF,int & n)2262   ERROR_CODE Link::GetCIF ( mmcif::PData CIF, int & n )  {
2263   mmcif::PLoop Loop;
2264   pstr         F;
2265   char         S[100];
2266   int          RC,l;
2267   bool         Done;
2268   ERROR_CODE   rc;
2269 
2270     Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
2271     if (!Loop)  {
2272       n = -1;  // signal to finish processing of this structure
2273       return Error_EmptyCIF;
2274     }
2275 
2276     l    = Loop->GetLoopLength();
2277     Done = (n>=l);
2278     while (!Done) {
2279       F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,n,RC );
2280       if ((!RC) && F)  Done = (strcmp(F,LinkTypeID)==0);
2281                  else  Done = false;
2282       if (!Done)  {
2283         n++;
2284         Done = (n>=l);
2285       }
2286     }
2287 
2288     if (n>=l)  {
2289       n = -1;  // finish processing of Turn
2290       return Error_EmptyCIF;
2291     }
2292 
2293     Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,n );
2294 
2295   //  CIFGetInteger ( l,Loop,CIFTAG_ID,n );
2296 
2297     CIFGetString ( atName1,Loop,CIFTAG_CONN_PTNR1_AUTH_ATOM_ID,n,
2298                    sizeof(atName1),pstr("    ") );
2299     CIFGetString ( aloc1,Loop,CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID,n,
2300                    sizeof(aloc1),pstr(" ") );
2301     CIFGetString ( resName1,Loop,CIFTAG_CONN_PTNR1_AUTH_COMP_ID,n,
2302                    sizeof(resName1),pstr("   ") );
2303     CIFGetString ( chainID1,Loop,CIFTAG_CONN_PTNR1_AUTH_ASYM_ID,n,
2304                    sizeof(chainID1),pstr(" ") );
2305     rc = CIFGetInteger ( seqNum1,Loop,CIFTAG_CONN_PTNR1_AUTH_SEQ_ID,n );
2306     if (rc==Error_NoData)   return Error_EmptyCIF;
2307     if (rc!=Error_NoError)  return rc;
2308 
2309     CIFGetString ( insCode1,Loop,CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE,
2310                    n,sizeof(insCode1),pstr(" ") );
2311 
2312     CIFGetString ( atName2,Loop,CIFTAG_CONN_PTNR2_AUTH_ATOM_ID,n,
2313                    sizeof(atName2),pstr("    ") );
2314     CIFGetString ( aloc2,Loop,CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID,n,
2315                    sizeof(aloc2),pstr(" ") );
2316     CIFGetString ( resName2,Loop,CIFTAG_CONN_PTNR2_AUTH_COMP_ID,n,
2317                    sizeof(resName2),pstr("   ") );
2318     CIFGetString ( chainID2,Loop,CIFTAG_CONN_PTNR2_AUTH_ASYM_ID,n,
2319                    sizeof(chainID2),pstr(" ") );
2320     rc = CIFGetInteger ( seqNum2,Loop,CIFTAG_CONN_PTNR2_AUTH_SEQ_ID,n );
2321     if (rc==Error_NoData)   return Error_EmptyCIF;
2322     if (rc!=Error_NoError)  return rc;
2323 
2324     CIFGetString ( insCode2,Loop,CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE,
2325                    n,sizeof(insCode2),pstr(" ") );
2326 
2327     CIFGetString ( S,Loop,CIFTAG_CONN_PTNR1_SYMMETRY,n,
2328                    sizeof(S),pstr("") );
2329     if (S[0])  {
2330       l  = strlen(S)-1;
2331       k1 = int(S[l--]) - int('0');
2332       j1 = int(S[l--]) - int('0');
2333       i1 = int(S[l--]) - int('0');
2334       S[l] = char(0);
2335       s1 = atoi(S);
2336     }
2337 
2338     CIFGetString ( S,Loop,CIFTAG_CONN_PTNR2_SYMMETRY,n,
2339                    sizeof(S),pstr("") );
2340     if (S[0])  {
2341       l  = strlen(S)-1;
2342       k2 = int(S[l--]) - int('0');
2343       j2 = int(S[l--]) - int('0');
2344       i2 = int(S[l--]) - int('0');
2345       S[l] = char(0);
2346       s2 = atoi(S);
2347     }
2348 
2349     rc = CIFGetReal ( dist,Loop,CIFTAG_CONN_DIST,n );
2350     if (rc==Error_NoData)   return Error_EmptyCIF;
2351     if (rc!=Error_NoError)  return rc;
2352 
2353     n++;
2354 
2355     return Error_NoError;
2356 
2357   }
2358 
Copy(PContainerClass Link)2359   void  Link::Copy ( PContainerClass Link )  {
2360 
2361     strcpy ( atName1 ,PLink(Link)->atName1  );
2362     strcpy ( aloc1   ,PLink(Link)->aloc1    );
2363     strcpy ( resName1,PLink(Link)->resName1 );
2364     strcpy ( chainID1,PLink(Link)->chainID1 );
2365     seqNum1 = PLink(Link)->seqNum1;
2366     strcpy ( insCode1,PLink(Link)->insCode1 );
2367 
2368     strcpy ( atName2 ,PLink(Link)->atName2  );
2369     strcpy ( aloc2   ,PLink(Link)->aloc2    );
2370     strcpy ( resName2,PLink(Link)->resName2 );
2371     strcpy ( chainID2,PLink(Link)->chainID2 );
2372     seqNum2 = PLink(Link)->seqNum2;
2373     strcpy ( insCode2,PLink(Link)->insCode2 );
2374 
2375     s1 = PLink(Link)->s1;
2376     i1 = PLink(Link)->i1;
2377     j1 = PLink(Link)->j1;
2378     k1 = PLink(Link)->k1;
2379 
2380     s2 = PLink(Link)->s2;
2381     i2 = PLink(Link)->i2;
2382     j2 = PLink(Link)->j2;
2383     k2 = PLink(Link)->k2;
2384 
2385     dist = PLink(Link)->dist;
2386 
2387   }
2388 
write(io::RFile f)2389   void  Link::write ( io::RFile f )  {
2390   byte Version=2;
2391 
2392     f.WriteByte ( &Version    );
2393 
2394     f.WriteTerLine ( atName1 ,false );
2395     f.WriteTerLine ( aloc1   ,false );
2396     f.WriteTerLine ( resName1,false );
2397     f.WriteTerLine ( chainID1,false );
2398     f.WriteInt     ( &seqNum1 );
2399     f.WriteTerLine ( insCode1,false );
2400 
2401     f.WriteTerLine ( atName2 ,false );
2402     f.WriteTerLine ( aloc2   ,false );
2403     f.WriteTerLine ( resName2,false );
2404     f.WriteTerLine ( chainID2,false );
2405     f.WriteInt     ( &seqNum2 );
2406     f.WriteTerLine ( insCode2,false );
2407 
2408     f.WriteInt ( &s1 );
2409     f.WriteInt ( &i1 );
2410     f.WriteInt ( &j1 );
2411     f.WriteInt ( &k1 );
2412 
2413     f.WriteInt ( &s2 );
2414     f.WriteInt ( &i2 );
2415     f.WriteInt ( &j2 );
2416     f.WriteInt ( &k2 );
2417 
2418     f.WriteReal ( &dist );
2419 
2420   }
2421 
read(io::RFile f)2422   void  Link::read ( io::RFile f )  {
2423   byte Version;
2424 
2425     f.ReadByte ( &Version    );
2426 
2427     f.ReadTerLine ( atName1 ,false );
2428     f.ReadTerLine ( aloc1   ,false );
2429     f.ReadTerLine ( resName1,false );
2430     f.ReadTerLine ( chainID1,false );
2431     f.ReadInt     ( &seqNum1 );
2432     f.ReadTerLine ( insCode1,false );
2433 
2434     f.ReadTerLine ( atName2 ,false );
2435     f.ReadTerLine ( aloc2   ,false );
2436     f.ReadTerLine ( resName2,false );
2437     f.ReadTerLine ( chainID2,false );
2438     f.ReadInt     ( &seqNum2 );
2439     f.ReadTerLine ( insCode2,false );
2440 
2441     f.ReadInt ( &s1 );
2442     f.ReadInt ( &i1 );
2443     f.ReadInt ( &j1 );
2444     f.ReadInt ( &k1 );
2445 
2446     f.ReadInt ( &s2 );
2447     f.ReadInt ( &i2 );
2448     f.ReadInt ( &j2 );
2449     f.ReadInt ( &k2 );
2450 
2451     if (Version>1)
2452       f.ReadReal ( &dist );
2453 
2454   }
2455 
MakeStreamFunctions(Link)2456   MakeStreamFunctions(Link)
2457 
2458 
2459   //  ===================  LinkRContainer  =======================
2460 
2461   PContainerClass LinkRContainer::MakeContainerClass ( int ClassID )  {
2462     switch (ClassID)  {
2463       default :
2464       case ClassID_Template : return
2465                            ClassContainer::MakeContainerClass(ClassID);
2466       case ClassID_LinkR    : return new LinkR();
2467     }
2468   }
2469 
MakeStreamFunctions(LinkRContainer)2470   MakeStreamFunctions(LinkRContainer)
2471 
2472 
2473   //  ========================  LinkR  ===========================
2474 
2475   LinkR::LinkR() : ContainerClass()  {
2476     InitLinkR();
2477   }
2478 
LinkR(cpstr S)2479   LinkR::LinkR ( cpstr S ) : ContainerClass()  {
2480     InitLinkR();
2481     ConvertPDBASCII ( S );
2482   }
2483 
LinkR(io::RPStream Object)2484   LinkR::LinkR ( io::RPStream Object ) : ContainerClass(Object)  {
2485     InitLinkR();
2486   }
2487 
~LinkR()2488   LinkR::~LinkR() {}
2489 
InitLinkR()2490   void  LinkR::InitLinkR()  {
2491     strcpy ( linkRID ,"----" );  // link name
2492     strcpy ( atName1 ,"----" );  // name of 1st linked atom
2493     strcpy ( aloc1   ," "    );  // alternative location of 1st atom
2494     strcpy ( resName1,"---"  );  // residue name of 1st linked atom
2495     strcpy ( chainID1," "    );  // chain ID of 1st linked atom
2496     seqNum1 = 0;                 // sequence number of 1st linked atom
2497     strcpy ( insCode1," "    );  // insertion code of 1st linked atom
2498     strcpy ( atName2 ,"----" );  // name of 2nd linked atom
2499     strcpy ( aloc2   ," "    );  // alternative location of 2nd atom
2500     strcpy ( resName2,"---"  );  // residue name of 2nd linked atom
2501     strcpy ( chainID2," "    );  // chain ID of 2nd linked atom
2502     seqNum2 = 0;                 // sequence number of 2nd linked atom
2503     strcpy ( insCode2," "    );  // insertion code of 2nd linked atom
2504     dist    = 0.0;               // link distance
2505   }
2506 
2507   /*
2508   LINK             LYS A  27                     PLP A 255                PLPLYS
2509   LINK             MAN S   3                     MAN S   4                BETA1-4
2510   LINK        C6  BBEN B   1                O1  BMAF S   2                BEN-MAF
2511   LINK        OE2 AGLU A 320                C1  AMAF S   2                GLU-MAF
2512   LINK        OE2  GLU A  67        1.895   ZN   ZN  R   5                GLU-ZN
2513   LINK        NE2  HIS A  71        2.055   ZN   ZN  R   5                HIS-ZN
2514   LINK        O    ARG A  69        2.240   NA   NA  R   9                ARG-NA
2515   012345678901234567890123456789012345678901234567890123456789012345678901234567890
2516             1         2         3         4         5         6         7
2517   */
2518 
PDBASCIIDump(pstr S,int N)2519   void  LinkR::PDBASCIIDump ( pstr S, int N )  {
2520   UNUSED_ARGUMENT(N);
2521   //  makes the ASCII PDB OBSLTE line number N
2522   //  from the class' data
2523 
2524     strcpy     ( S,"LINKR" );
2525     PadSpaces  ( S,80 );
2526 
2527     strcpy_n1  ( &(S[12]),atName1 ,4 );
2528     strcpy_n1  ( &(S[16]),aloc1   ,1 );
2529     strcpy_n1  ( &(S[17]),resName1,3 );
2530     strcpy_n1  ( &(S[21]),chainID1,1 );
2531     PutIntIns  ( &(S[22]),seqNum1 ,4,insCode1 );
2532 
2533     if (dist>0.0)
2534       PutRealF ( &(S[32]),dist,7,3 );
2535 
2536     strcpy_n1  ( &(S[42]),atName2 ,4 );
2537     strcpy_n1  ( &(S[46]),aloc2   ,1 );
2538     strcpy_n1  ( &(S[47]),resName2,3 );
2539     strcpy_n1  ( &(S[51]),chainID2,1 );
2540     PutIntIns  ( &(S[52]),seqNum2 ,4,insCode2 );
2541 
2542     strcpy_ns  ( &(S[72]),linkRID,8 );
2543 
2544   }
2545 
2546 
2547   #define  LinkRTypeID  "LINKR"
2548 
AddStructConnLinkRTags(mmcif::PLoop Loop)2549   void AddStructConnLinkRTags ( mmcif::PLoop Loop )  {
2550 
2551     Loop->AddLoopTag ( CIFTAG_ID                           );
2552     Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID                 );
2553 
2554     Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ATOM_ID      );
2555     Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID  );
2556     Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_COMP_ID      );
2557     Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ASYM_ID      );
2558     Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_SEQ_ID       );
2559     Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE );
2560 
2561     Loop->AddLoopTag ( CIFTAG_CONN_DIST );
2562 
2563     Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ATOM_ID      );
2564     Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID  );
2565     Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_COMP_ID      );
2566     Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ASYM_ID      );
2567     Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_SEQ_ID       );
2568     Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE );
2569 
2570     Loop->AddLoopTag ( CIFTAG_CONN_NAME );
2571 
2572   }
2573 
MakeCIF(mmcif::PData CIF,int N)2574   void  LinkR::MakeCIF ( mmcif::PData CIF, int N )  {
2575   UNUSED_ARGUMENT(N);
2576   mmcif::PLoop Loop;
2577   int          RC;
2578 
2579     RC = CIF->AddLoop ( CIFCAT_STRUCT_LINKR,Loop );
2580     if (RC!=mmcif::CIFRC_Ok) // the category was (re)created, provide tags
2581       AddStructConnLinkRTags ( Loop );
2582 
2583     Loop->AddString  ( "1"      );  // should be a counter
2584     Loop->AddString  ( pstr(LinkTypeID) );
2585 
2586     Loop->AddString  ( atName1  );
2587     Loop->AddString  ( aloc1    );
2588     Loop->AddString  ( resName1 );
2589     Loop->AddString  ( chainID1 );
2590     Loop->AddInteger ( seqNum1  );
2591     Loop->AddString  ( insCode1 );
2592 
2593     Loop->AddReal    ( dist     );
2594 
2595     Loop->AddString  ( atName2  );
2596     Loop->AddString  ( aloc2    );
2597     Loop->AddString  ( resName2 );
2598     Loop->AddString  ( chainID2 );
2599     Loop->AddInteger ( seqNum2  );
2600     Loop->AddString  ( insCode2 );
2601 
2602     Loop->AddString  ( linkRID  );
2603 
2604   }
2605 
ConvertPDBASCII(cpstr S)2606   ERROR_CODE LinkR::ConvertPDBASCII ( cpstr S )  {
2607 
2608     GetString    ( atName1 ,&(S[12]),4 );
2609     strcpy_ncss  ( aloc1   ,&(S[16]),1 );
2610     strcpy_ncss  ( resName1,&(S[17]),3 );
2611     strcpy_ncss  ( chainID1,&(S[21]),1 );
2612     GetIntIns    ( seqNum1,insCode1,&(S[22]),4 );
2613 
2614     if (!GetReal(dist,&(S[32]),7)) dist = 0.0;
2615 
2616     GetString    ( atName2 ,&(S[42]),4 );
2617     strcpy_ncss  ( aloc2   ,&(S[46]),1 );
2618     strcpy_ncss  ( resName2,&(S[47]),3 );
2619     strcpy_ncss  ( chainID2,&(S[51]),1 );
2620     GetIntIns    ( seqNum2,insCode2,&(S[52]),4 );
2621 
2622     strcpy_ncss  ( linkRID,&(S[72]),8 );
2623 
2624     return Error_NoError ;
2625 
2626   }
2627 
GetCIF(mmcif::PData CIF,int & n)2628   ERROR_CODE LinkR::GetCIF ( mmcif::PData CIF, int & n )  {
2629   mmcif::PLoop Loop;
2630   pstr         F;
2631   int          RC,l;
2632   bool         Done;
2633   ERROR_CODE   rc;
2634 
2635     Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
2636     if (!Loop)  {
2637       n = -1;  // signal to finish processing of this structure
2638       return Error_EmptyCIF;
2639     }
2640 
2641     l    = Loop->GetLoopLength();
2642     Done = (n>=l);
2643     while (!Done) {
2644       F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,n,RC );
2645       if ((!RC) && F)  Done = (strcmp(F,LinkTypeID)==0);
2646                  else  Done = false;
2647       if (!Done)  {
2648         n++;
2649         Done = (n>=l);
2650       }
2651     }
2652 
2653     if (n>=l)  {
2654       n = -1;  // finish processing of Turn
2655       return Error_EmptyCIF;
2656     }
2657 
2658     Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,n );
2659 
2660     //  CIFGetInteger ( l,Loop,CIFTAG_ID,n );
2661 
2662     CIFGetString ( atName1,Loop,CIFTAG_CONN_PTNR1_AUTH_ATOM_ID,n,
2663                    sizeof(atName1),pstr("    ") );
2664     CIFGetString ( aloc1,Loop,CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID,n,
2665                    sizeof(aloc1),pstr(" ") );
2666     CIFGetString ( resName1,Loop,CIFTAG_CONN_PTNR1_AUTH_COMP_ID,n,
2667                    sizeof(resName1),pstr("   ") );
2668     CIFGetString ( chainID1,Loop,CIFTAG_CONN_PTNR1_AUTH_ASYM_ID,n,
2669                    sizeof(chainID1),pstr(" ") );
2670     rc = CIFGetInteger ( seqNum1,Loop,CIFTAG_CONN_PTNR1_AUTH_SEQ_ID,n );
2671     if (rc==Error_NoData)   return Error_EmptyCIF;
2672     if (rc!=Error_NoError)  return rc;
2673 
2674     CIFGetString ( insCode1,Loop,CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE,
2675                    n,sizeof(insCode1),pstr(" ") );
2676 
2677     rc = CIFGetReal ( dist,Loop,CIFTAG_CONN_DIST,n );
2678     if (rc==Error_NoData)   return Error_EmptyCIF;
2679     if (rc!=Error_NoError)  return rc;
2680 
2681     CIFGetString ( atName2,Loop,CIFTAG_CONN_PTNR2_AUTH_ATOM_ID,n,
2682                    sizeof(atName2),pstr("    ") );
2683     CIFGetString ( aloc2,Loop,CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID,n,
2684                    sizeof(aloc2),pstr(" ") );
2685     CIFGetString ( resName2,Loop,CIFTAG_CONN_PTNR2_AUTH_COMP_ID,n,
2686                    sizeof(resName2),pstr("   ") );
2687     CIFGetString ( chainID2,Loop,CIFTAG_CONN_PTNR2_AUTH_ASYM_ID,n,
2688                    sizeof(chainID2),pstr(" ") );
2689     rc = CIFGetInteger ( seqNum2,Loop,CIFTAG_CONN_PTNR2_AUTH_SEQ_ID,n );
2690     if (rc==Error_NoData)   return Error_EmptyCIF;
2691     if (rc!=Error_NoError)  return rc;
2692 
2693     CIFGetString ( insCode2,Loop,CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE,
2694                    n,sizeof(insCode2),pstr(" ") );
2695 
2696     CIFGetString ( linkRID,Loop,CIFTAG_CONN_NAME,n,
2697                    sizeof(linkRID),pstr(" ") );
2698 
2699     n++;
2700 
2701     return Error_NoError;
2702 
2703   }
2704 
Copy(PContainerClass LinkR)2705   void  LinkR::Copy ( PContainerClass LinkR )  {
2706 
2707     strcpy ( atName1 ,PLinkR(LinkR)->atName1  );
2708     strcpy ( aloc1   ,PLinkR(LinkR)->aloc1    );
2709     strcpy ( resName1,PLinkR(LinkR)->resName1 );
2710     strcpy ( chainID1,PLinkR(LinkR)->chainID1 );
2711     seqNum1 = PLinkR(LinkR)->seqNum1;
2712     strcpy ( insCode1,PLinkR(LinkR)->insCode1 );
2713 
2714     dist = PLinkR(LinkR)->dist;
2715 
2716     strcpy ( atName2 ,PLinkR(LinkR)->atName2  );
2717     strcpy ( aloc2   ,PLinkR(LinkR)->aloc2    );
2718     strcpy ( resName2,PLinkR(LinkR)->resName2 );
2719     strcpy ( chainID2,PLinkR(LinkR)->chainID2 );
2720     seqNum2 = PLinkR(LinkR)->seqNum2;
2721     strcpy ( insCode2,PLinkR(LinkR)->insCode2 );
2722 
2723     strcpy ( linkRID,PLinkR(LinkR)->linkRID );
2724 
2725   }
2726 
write(io::RFile f)2727   void  LinkR::write ( io::RFile f )  {
2728   byte Version=1;
2729 
2730     f.WriteByte ( &Version    );
2731 
2732     f.WriteTerLine ( atName1 ,false );
2733     f.WriteTerLine ( aloc1   ,false );
2734     f.WriteTerLine ( resName1,false );
2735     f.WriteTerLine ( chainID1,false );
2736     f.WriteInt     ( &seqNum1 );
2737     f.WriteTerLine ( insCode1,false );
2738 
2739     f.WriteReal    ( &dist );
2740 
2741     f.WriteTerLine ( atName2 ,false );
2742     f.WriteTerLine ( aloc2   ,false );
2743     f.WriteTerLine ( resName2,false );
2744     f.WriteTerLine ( chainID2,false );
2745     f.WriteInt     ( &seqNum2 );
2746     f.WriteTerLine ( insCode2,false );
2747 
2748     f.WriteTerLine ( linkRID,false );
2749 
2750   }
2751 
read(io::RFile f)2752   void  LinkR::read ( io::RFile f )  {
2753   byte Version;
2754 
2755     f.ReadByte ( &Version    );
2756 
2757     f.ReadTerLine ( atName1 ,false );
2758     f.ReadTerLine ( aloc1   ,false );
2759     f.ReadTerLine ( resName1,false );
2760     f.ReadTerLine ( chainID1,false );
2761     f.ReadInt     ( &seqNum1 );
2762     f.ReadTerLine ( insCode1,false );
2763 
2764     f.ReadReal    ( &dist );
2765 
2766     f.ReadTerLine ( atName2 ,false );
2767     f.ReadTerLine ( aloc2   ,false );
2768     f.ReadTerLine ( resName2,false );
2769     f.ReadTerLine ( chainID2,false );
2770     f.ReadInt     ( &seqNum2 );
2771     f.ReadTerLine ( insCode2,false );
2772 
2773     f.ReadTerLine ( linkRID,false );
2774 
2775   }
2776 
MakeStreamFunctions(LinkR)2777   MakeStreamFunctions(LinkR)
2778 
2779 
2780   //  ===================  CisPepContainer  ======================
2781 
2782   PContainerClass CisPepContainer::MakeContainerClass ( int ClassID )  {
2783     switch (ClassID)  {
2784       default :
2785       case ClassID_Template : return
2786                           ClassContainer::MakeContainerClass(ClassID);
2787       case ClassID_CisPep   : return new CisPep();
2788     }
2789   }
2790 
MakeStreamFunctions(CisPepContainer)2791   MakeStreamFunctions(CisPepContainer)
2792 
2793 
2794   //  ========================  CisPep  ==========================
2795 
2796   CisPep::CisPep() : ContainerClass()  {
2797     InitCisPep();
2798   }
2799 
CisPep(cpstr S)2800   CisPep::CisPep ( cpstr S ) : ContainerClass()  {
2801     InitCisPep();
2802     ConvertPDBASCII ( S );
2803   }
2804 
CisPep(io::RPStream Object)2805   CisPep::CisPep ( io::RPStream Object ) : ContainerClass(Object)  {
2806     InitCisPep();
2807   }
2808 
~CisPep()2809   CisPep::~CisPep() {}
2810 
InitCisPep()2811   void CisPep::InitCisPep()  {
2812     serNum  = 1;                //  record serial number
2813     strcpy ( pep1    ,"---" );  //  residue name
2814     strcpy ( chainID1," "   );  //  chain identifier 1
2815     seqNum1 = 0;                //  residue sequence number 1
2816     strcpy ( icode1  ," "   );  //  insertion code 1
2817     strcpy ( pep2    ,"---" );  //  residue name 2
2818     strcpy ( chainID2," "   );  //  chain identifier 2
2819     seqNum2 = 0;                //  residue sequence number 2
2820     strcpy ( icode2  ," "   );  //  insertion code 2
2821     modNum  = 0;                //  model number
2822     measure = 0.0;              //  measure of the angle in degrees.
2823   }
2824 
PDBASCIIDump(pstr S,int N)2825   void  CisPep::PDBASCIIDump ( pstr S, int N )  {
2826   UNUSED_ARGUMENT(N);
2827 
2828     strcpy     ( S,"CISPEP" );
2829     PadSpaces  ( S,80 );
2830 
2831     PutInteger ( &(S[7]),serNum,3 );
2832 
2833     strcpy_n1  ( &(S[11]),pep1    ,3 );
2834     strcpy_n1  ( &(S[15]),chainID1,1 );
2835     PutIntIns  ( &(S[17]),seqNum1 ,4,icode1 );
2836 
2837     strcpy_n1  ( &(S[25]),pep2    ,3 );
2838     strcpy_n1  ( &(S[29]),chainID2,1 );
2839     PutIntIns  ( &(S[31]),seqNum2 ,4,icode1 );
2840 
2841     PutInteger ( &(S[43]),modNum,3 );
2842     PutRealF   ( &(S[53]),measure,6,2 );
2843 
2844   }
2845 
2846 
ConvertPDBASCII(cpstr S)2847   ERROR_CODE CisPep::ConvertPDBASCII ( cpstr S )  {
2848 
2849     GetInteger   ( serNum  ,&(S[7]) ,3 );
2850 
2851     strcpy_ncss  ( pep1    ,&(S[11]),3 );
2852     strcpy_ncss  ( chainID1,&(S[15]),1 );
2853     GetIntIns    ( seqNum1,icode1,&(S[17]),4 );
2854 
2855     strcpy_ncss  ( pep2    ,&(S[25]),3 );
2856     strcpy_ncss  ( chainID2,&(S[29]),1 );
2857     GetIntIns    ( seqNum2,icode2,&(S[31]),4 );
2858 
2859     GetInteger   ( modNum  ,&(S[43]),3 );
2860     GetReal      ( measure ,&(S[53]),6 );
2861 
2862     return Error_NoError;
2863 
2864   }
2865 
2866 
Copy(PContainerClass CisPep)2867   void  CisPep::Copy ( PContainerClass CisPep )  {
2868 
2869     serNum  = PCisPep(CisPep)->serNum;
2870 
2871     strcpy ( pep1    ,PCisPep(CisPep)->pep1     );
2872     strcpy ( chainID1,PCisPep(CisPep)->chainID1 );
2873     seqNum1 = PCisPep(CisPep)->seqNum1;
2874     strcpy ( icode1  ,PCisPep(CisPep)->icode1   );
2875 
2876     strcpy ( pep2    ,PCisPep(CisPep)->pep2     );
2877     strcpy ( chainID2,PCisPep(CisPep)->chainID2 );
2878     seqNum2 = PCisPep(CisPep)->seqNum2;
2879     strcpy ( icode2  ,PCisPep(CisPep)->icode2   );
2880 
2881     modNum  = PCisPep(CisPep)->modNum;
2882     measure = PCisPep(CisPep)->measure;
2883 
2884   }
2885 
write(io::RFile f)2886   void  CisPep::write ( io::RFile f )  {
2887   byte Version=1;
2888 
2889     f.WriteByte    ( &Version   );
2890 
2891     f.WriteInt     ( &serNum );
2892 
2893     f.WriteTerLine ( pep1    ,false );
2894     f.WriteTerLine ( chainID1,false );
2895     f.WriteInt     ( &seqNum1 );
2896     f.WriteTerLine ( icode1  ,false );
2897 
2898     f.WriteTerLine ( pep2    ,false );
2899     f.WriteTerLine ( chainID2,false );
2900     f.WriteInt     ( &seqNum2 );
2901     f.WriteTerLine ( icode2  ,false );
2902 
2903     f.WriteInt     ( &modNum  );
2904     f.WriteReal    ( &measure );
2905 
2906   }
2907 
read(io::RFile f)2908   void  CisPep::read ( io::RFile f )  {
2909   byte Version;
2910 
2911     f.ReadByte    ( &Version   );
2912 
2913     f.ReadInt     ( &serNum );
2914 
2915     f.ReadTerLine ( pep1    ,false );
2916     f.ReadTerLine ( chainID1,false );
2917     f.ReadInt     ( &seqNum1 );
2918     f.ReadTerLine ( icode1  ,false );
2919 
2920     f.ReadTerLine ( pep2    ,false );
2921     f.ReadTerLine ( chainID2,false );
2922     f.ReadInt     ( &seqNum2 );
2923     f.ReadTerLine ( icode2  ,false );
2924 
2925     f.ReadInt     ( &modNum  );
2926     f.ReadReal    ( &measure );
2927 
2928   }
2929 
MakeStreamFunctions(CisPep)2930   MakeStreamFunctions(CisPep)
2931 
2932 
2933 
2934   //  =====================   Model   =======================
2935 
2936   Model::Model() : ProModel() {
2937     InitModel();
2938   }
2939 
Model(PManager MMDBM,int serialNum)2940   Model::Model ( PManager MMDBM, int serialNum ) : ProModel() {
2941     InitModel();
2942     manager = MMDBM;
2943     serNum  = serialNum;
2944   }
2945 
Model(io::RPStream Object)2946   Model::Model ( io::RPStream Object ) : ProModel(Object)  {
2947     InitModel();
2948   }
2949 
InitModel()2950   void  Model::InitModel()  {
2951     serNum       = 0;
2952     nChains      = 0;
2953     nChainsAlloc = 0;
2954     chain        = NULL;
2955     manager      = NULL;
2956     Exclude      = true;
2957   }
2958 
~Model()2959   Model::~Model()  {
2960     FreeMemory();
2961     if (manager)  manager->_ExcludeModel ( serNum );
2962   }
2963 
FreeMemory()2964   void Model::FreeMemory()  {
2965 
2966     DeleteAllChains();
2967     if (chain)  delete[] chain;
2968     chain        = NULL;
2969     nChains      = 0;
2970     nChainsAlloc = 0;
2971 
2972     RemoveSecStructure();
2973     RemoveHetInfo     ();
2974     RemoveLinks       ();
2975     RemoveLinkRs      ();
2976     RemoveCisPeps     ();
2977 
2978   }
2979 
2980 
SetMMDBManager(PManager MMDBM,int serialNum)2981   void  Model::SetMMDBManager ( PManager MMDBM, int serialNum )  {
2982     manager = MMDBM;
2983     serNum  = serialNum;
2984   }
2985 
CheckInAtoms()2986   void  Model::CheckInAtoms()  {
2987   int i;
2988     if (manager)
2989       for (i=0;i<nChains;i++)
2990         if (chain[i])
2991           chain[i]->CheckInAtoms();
2992   }
2993 
2994 
GetNumberOfAtoms(bool countTers)2995   int  Model::GetNumberOfAtoms ( bool countTers )  {
2996   // returns number of atoms in the model
2997   int i,na;
2998     na = 0;
2999     for (i=0;i<nChains;i++)
3000       if (chain[i])  na += chain[i]->GetNumberOfAtoms ( countTers );
3001     return na;
3002   }
3003 
GetNumberOfResidues()3004   int  Model::GetNumberOfResidues()  {
3005   // returns number of residues in the model
3006   PChain   chn;
3007   int      ic,ir,nr;
3008     nr = 0;
3009     for (ic=0;ic<nChains;ic++)  {
3010       chn = chain[ic];
3011       if (chn)
3012         for (ir=0;ir<chn->nResidues;ir++)
3013           if (chn->residue[ir])  nr++;
3014     }
3015     return nr;
3016   }
3017 
3018 
3019   //  ----------------  Extracting chains  --------------------------
3020 
GetNumberOfChains()3021   int  Model::GetNumberOfChains()  {
3022     return nChains;
3023   }
3024 
GetChain(int chainNo)3025   PChain Model::GetChain ( int chainNo )  {
3026     if ((0<=chainNo) && (chainNo<nChains))
3027           return chain[chainNo];
3028     else  return NULL;
3029   }
3030 
3031 
ExpandChainArray(int nOfChains)3032   void Model::ExpandChainArray ( int nOfChains )  {
3033   PPChain chain1;
3034   int     i;
3035     if (nOfChains>=nChainsAlloc)  {
3036       nChainsAlloc = nOfChains+10;
3037       chain1 = new PChain[nChainsAlloc];
3038       for (i=0;i<nChains;i++)
3039         chain1[i] = chain[i];
3040       for (i=nChains;i<nChainsAlloc;i++)
3041         chain1[i] = NULL;
3042       if (chain)  delete[] chain;
3043       chain = chain1;
3044     }
3045   }
3046 
GetChainCreate(const ChainID chID,bool enforceUniqueChainID)3047   PChain Model::GetChainCreate ( const ChainID chID,
3048                                  bool enforceUniqueChainID )  {
3049   //   Returns pointer on chain, whose identifier is
3050   // given in chID. If such a chain is absent in the
3051   // model, it is created.
3052   PChain  chn;
3053   ChainID chainID;
3054   int     i,k;
3055 
3056     // check if such a chain is already in the model
3057     chn = NULL;
3058     if (enforceUniqueChainID)  {
3059       k = 0;
3060       for (i=0;i<nChains;i++)
3061         if (chain[i])  {
3062           // here we check only first letter as it is kept in all
3063           // derived names
3064           if (chID[0]==chain[i]->chainID[0])  {
3065             chn = chain[i];
3066             if (chn->GetNumberOfResidues()>0)  k++;
3067           }
3068         }
3069       if (k)          sprintf ( chainID,"%s%i",chID,k-1 );
3070       else if (!chn)  strcpy  ( chainID,chID ); // chain is absent
3071                 else  return chn;  // the only empty chain
3072     } else  {
3073       if (chID[0])  {
3074         for (i=0;(i<nChains) && (!chn);i++)
3075           if (chain[i])  {
3076             if (!strcmp(chID,chain[i]->chainID))
3077               chn = chain[i]; // it is there; just return the pointer
3078           }
3079       } else  {
3080         for (i=0;(i<nChains) && (!chn);i++)
3081           if (chain[i])  {
3082             if (!chain[i]->chainID[0])
3083               chn = chain[i]; // it is there; just return the pointer
3084           }
3085       }
3086       if (chn)  return chn;
3087       strcpy ( chainID,chID );
3088     }
3089 
3090     ExpandChainArray ( nChains );
3091 
3092     // create new chain
3093     chain[nChains] = newChain();
3094     chain[nChains]->SetChain ( chainID );
3095     chain[nChains]->SetModel ( this );
3096     nChains++;
3097 
3098     return chain[nChains-1];
3099 
3100   }
3101 
CreateChain(const ChainID chID)3102   PChain Model::CreateChain ( const ChainID chID )  {
3103   //   CreateChain() creates a new chain with chain ID regardless
3104   // the presence of same-ID chains in the model. This function
3105   // was introduced only for compatibility with older CCP4
3106   // applications and using it in any new developments should be
3107   // strictly discouraged.
3108 
3109     ExpandChainArray ( nChains );
3110 
3111     // create new chain
3112     chain[nChains] = newChain();
3113     chain[nChains]->SetChain ( chID );
3114     chain[nChains]->SetModel ( this );
3115     nChains++;
3116 
3117     return chain[nChains-1];
3118 
3119   }
3120 
3121 
GetChainTable(PPChain & chainTable,int & NumberOfChains)3122   void  Model::GetChainTable ( PPChain & chainTable,
3123                                int & NumberOfChains )  {
3124     chainTable     = chain;
3125     NumberOfChains = nChains;
3126   }
3127 
GetNewChainID(ChainID chID,int length)3128   bool Model::GetNewChainID ( ChainID chID, int length )  {
3129   int     i,k;
3130   bool found;
3131 
3132     memset ( chID,0,sizeof(ChainID) );
3133     chID[0] = 'A';
3134 
3135     do  {
3136       found = false;
3137       for (i=0;(i<nChains) && (!found);i++)
3138         if (chain[i])
3139           found = (!strcmp(chID,chain[i]->chainID));
3140       if (found)  {
3141         k = 0;
3142         while (k<length)
3143           if (!chID[k])  {
3144             chID[k] = 'A';
3145             break;
3146           } else if (chID[k]<'Z')  {
3147             chID[k]++;
3148             break;
3149           } else  {
3150             chID[k] = 'A';
3151             k++;
3152           }
3153       } else
3154         k = 0;
3155     } while (found && (k<length));
3156 
3157     if (found)  {
3158       k = strlen(chID);
3159       while (k<length)
3160         chID[k++] = 'A';
3161     }
3162 
3163     return (!found);
3164 
3165   }
3166 
3167 
GetChain(const ChainID chID)3168   PChain Model::GetChain ( const ChainID chID )  {
3169   //   Returns pointer on chain, whose identifier is
3170   // given in chID. If such a chain is absent in the
3171   // model, returns NULL.
3172   int     i;
3173   bool isChainID;
3174     if (chID)  isChainID = (chID[0]!=char(0));
3175          else  isChainID = false;
3176     if (isChainID)  {
3177       for (i=0;i<nChains;i++)
3178         if (chain[i])  {
3179           if (!strcmp(chID,chain[i]->chainID))
3180             return chain[i]; // it is there; just return the pointer
3181         }
3182     } else  {
3183       for (i=0;i<nChains;i++)
3184         if (chain[i])  {
3185           if (!chain[i]->chainID[0])
3186             return chain[i]; // it is there; just return the pointer
3187         }
3188     }
3189     return NULL;
3190   }
3191 
3192 
3193   //  ------------------  Deleting chains  --------------------------
3194 
DeleteChain(int chainNo)3195   int Model::DeleteChain ( int chainNo )  {
3196     if ((0<=chainNo) && (chainNo<nChains))  {
3197       if (chain[chainNo])  {
3198         Exclude = false;
3199         delete chain[chainNo];
3200         chain[chainNo] = NULL;
3201         Exclude = true;
3202         return 1;
3203       }
3204     }
3205     return 0;
3206   }
3207 
DeleteChain(const ChainID chID)3208   int Model::DeleteChain ( const ChainID chID )  {
3209   int i;
3210     if (chID[0])  {
3211       for (i=0;i<nChains;i++)
3212         if (chain[i])  {
3213           if (!strcmp(chID,chain[i]->chainID))  {
3214             Exclude  = false;
3215             delete chain[i];
3216             chain[i] = NULL;
3217             Exclude  = true;
3218             return 1;
3219           }
3220         }
3221     } else  {
3222       for (i=0;i<nChains;i++)
3223         if (chain[i])  {
3224           if (!chain[i]->chainID[0])  {
3225             Exclude  = false;
3226             delete chain[i];
3227             chain[i] = NULL;
3228             Exclude  = true;
3229             return 1;
3230           }
3231         }
3232     }
3233     return 0;
3234   }
3235 
3236 
DeleteAllChains()3237   int Model::DeleteAllChains()  {
3238   int i,k;
3239     Exclude = false;
3240     k = 0;
3241     for (i=0;i<nChains;i++)
3242       if (chain[i])  {
3243         delete chain[i];
3244         chain[i] = NULL;
3245         k++;
3246       }
3247     nChains = 0;
3248     Exclude = true;
3249     return k;
3250   }
3251 
DeleteSolventChains()3252   int Model::DeleteSolventChains()  {
3253   int i,k;
3254     Exclude = false;
3255     k = 0;
3256     for (i=0;i<nChains;i++)
3257       if (chain[i])  {
3258         if (chain[i]->isSolventChain())  {
3259           delete chain[i];
3260           chain[i] = NULL;
3261           k++;
3262         }
3263       }
3264     Exclude = true;
3265     return k;
3266   }
3267 
TrimChainTable()3268   void Model::TrimChainTable()  {
3269   int i,j;
3270     Exclude = false;
3271     j = 0;
3272     for (i=0;i<nChains;i++)
3273       if (chain[i])  {
3274         if (chain[i]->nResidues>0)  {
3275           if (j<i)  {
3276             chain[j] = chain[i];
3277             chain[i] = NULL;
3278           }
3279           j++;
3280         } else  {
3281           delete chain[i];
3282           chain[i] = NULL;
3283         }
3284       }
3285     nChains = j;
3286     Exclude = true;
3287   }
3288 
3289 
GetNumberOfResidues(const ChainID chainID)3290   int  Model::GetNumberOfResidues ( const ChainID chainID )  {
3291   PChain chn;
3292     chn = GetChain ( chainID );
3293     if (chn)  return chn->nResidues;
3294     return 0;
3295   }
3296 
GetNumberOfResidues(int chainNo)3297   int  Model::GetNumberOfResidues ( int chainNo )  {
3298     if ((0<=chainNo) && (chainNo<nChains))  {
3299       if (chain[chainNo])
3300         return chain[chainNo]->nResidues;
3301     }
3302     return 0;
3303   }
3304 
GetResidue(const ChainID chainID,int seqNo,const InsCode insCode)3305   PResidue Model::GetResidue ( const ChainID chainID, int seqNo,
3306                                  const InsCode insCode )  {
3307   PChain chn;
3308     chn = GetChain ( chainID );
3309     if (chn)
3310       return chn->GetResidue ( seqNo,insCode );
3311     return NULL;
3312   }
3313 
GetResidue(const ChainID chainID,int resNo)3314   PResidue Model::GetResidue ( const ChainID chainID, int resNo )  {
3315   PChain chn;
3316     chn = GetChain ( chainID );
3317     if (chn)  {
3318       if ((0<=resNo) && (resNo<chn->nResidues))
3319         return chn->residue[resNo];
3320     }
3321     return NULL;
3322   }
3323 
GetResidue(int chainNo,int seqNo,const InsCode insCode)3324   PResidue Model::GetResidue ( int chainNo, int seqNo,
3325                                  const InsCode insCode )  {
3326     if ((0<=chainNo) && (chainNo<nChains))  {
3327       if (chain[chainNo])
3328         return chain[chainNo]->GetResidue ( seqNo,insCode );
3329     }
3330     return NULL;
3331   }
3332 
GetResidue(int chainNo,int resNo)3333   PResidue Model::GetResidue ( int chainNo, int resNo )  {
3334     if ((0<=chainNo) && (chainNo<nChains))  {
3335       if (chain[chainNo]) {
3336         if ((0<=resNo) && (resNo<chain[chainNo]->nResidues))
3337           return chain[chainNo]->residue[resNo];
3338       }
3339     }
3340     return NULL;
3341   }
3342 
GetResidueNo(const ChainID chainID,int seqNo,const InsCode insCode)3343   int Model::GetResidueNo ( const ChainID chainID, int seqNo,
3344                             const InsCode insCode )  {
3345   PChain chn;
3346     chn = GetChain ( chainID );
3347     if (chn)
3348       return chn->GetResidueNo ( seqNo,insCode );
3349     return -2;
3350   }
3351 
GetResidueNo(int chainNo,int seqNo,const InsCode insCode)3352   int Model::GetResidueNo ( int  chainNo, int seqNo,
3353                              const InsCode insCode )  {
3354     if ((0<=chainNo) && (chainNo<nChains))  {
3355       if (chain[chainNo])
3356         return chain[chainNo]->GetResidueNo ( seqNo,insCode );
3357     }
3358     return -2;
3359   }
3360 
3361 
GetResidueTable(PPResidue & resTable,int & NumberOfResidues)3362   void Model::GetResidueTable ( PPResidue & resTable,
3363                                  int & NumberOfResidues )  {
3364   // resTable has to be NULL or it will be reallocated. The application
3365   // is responsible for deallocating the resTable (but not of its
3366   // residues!). This does not apply to other GetResidueTable
3367   // functions.
3368   PPChain   chn;
3369   PPResidue res;
3370   int       i,j,k,nChns,nResidues;
3371 
3372     if (resTable)  {
3373       delete[] resTable;
3374       resTable = NULL;
3375     }
3376 
3377     NumberOfResidues = 0;
3378     GetChainTable ( chn,nChns );
3379     for (i=0;i<nChns;i++)
3380       if (chn[i])  {
3381         chn[i]->GetResidueTable ( res,nResidues );
3382         NumberOfResidues += nResidues;
3383       }
3384 
3385     if (NumberOfResidues>0)  {
3386       resTable = new PResidue[NumberOfResidues];
3387       k = 0;
3388       GetChainTable ( chn,nChns );
3389       for (i=0;i<nChns;i++)
3390         if (chn[i])  {
3391           chn[i]->GetResidueTable ( res,nResidues );
3392           for (j=0;j<nResidues;j++)
3393             if (res[j])  resTable[k++] = res[j];
3394         }
3395       NumberOfResidues = k;
3396     }
3397 
3398   }
3399 
GetResidueTable(const ChainID chainID,PPResidue & resTable,int & NumberOfResidues)3400   void Model::GetResidueTable ( const ChainID chainID,
3401                                  PPResidue & resTable,
3402                                  int & NumberOfResidues )  {
3403   PChain chn;
3404     resTable         = NULL;
3405     NumberOfResidues = 0;
3406     chn = GetChain ( chainID );
3407     if (chn)  {
3408       resTable         = chn->residue;
3409       NumberOfResidues = chn->nResidues;
3410     }
3411   }
3412 
GetResidueTable(int chainNo,PPResidue & resTable,int & NumberOfResidues)3413   void Model::GetResidueTable ( int chainNo, PPResidue & resTable,
3414                                  int & NumberOfResidues )  {
3415     resTable         = NULL;
3416     NumberOfResidues = 0;
3417     if ((0<=chainNo) && (chainNo<nChains))  {
3418       if (chain[chainNo])  {
3419         resTable         = chain[chainNo]->residue;
3420         NumberOfResidues = chain[chainNo]->nResidues;
3421       }
3422     }
3423   }
3424 
3425 
DeleteResidue(const ChainID chainID,int seqNo,const InsCode insCode)3426   int Model::DeleteResidue ( const ChainID chainID, int seqNo,
3427                               const InsCode insCode )  {
3428   PChain chn;
3429     chn = GetChain ( chainID );
3430     if (chn)  return chn->DeleteResidue ( seqNo,insCode );
3431     return 0;
3432   }
3433 
DeleteResidue(const ChainID chainID,int resNo)3434   int Model::DeleteResidue ( const ChainID chainID, int resNo )  {
3435   PChain chn;
3436     chn = GetChain ( chainID );
3437     if (chn)  return chn->DeleteResidue ( resNo );
3438     return 0;
3439   }
3440 
DeleteResidue(int chainNo,int seqNo,const InsCode insCode)3441   int Model::DeleteResidue ( int  chainNo, int seqNo,
3442                               const InsCode insCode )  {
3443     if ((0<=chainNo) && (chainNo<nChains))  {
3444       if (chain[chainNo])
3445         return chain[chainNo]->DeleteResidue ( seqNo,insCode );
3446     }
3447     return 0;
3448   }
3449 
DeleteResidue(int chainNo,int resNo)3450   int Model::DeleteResidue ( int chainNo, int resNo )  {
3451     if ((0<=chainNo) && (chainNo<nChains))  {
3452       if (chain[chainNo])
3453         return chain[chainNo]->DeleteResidue ( resNo );
3454     }
3455     return 0;
3456   }
3457 
DeleteAllResidues(const ChainID chainID)3458   int Model::DeleteAllResidues ( const ChainID chainID )  {
3459   PChain chn;
3460     chn = GetChain ( chainID );
3461     if (chn)  return chn->DeleteAllResidues();
3462     return 0;
3463   }
3464 
DeleteAllResidues(int chainNo)3465   int Model::DeleteAllResidues ( int chainNo )  {
3466     if ((0<=chainNo) && (chainNo<nChains))  {
3467       if (chain[chainNo])
3468         return chain[chainNo]->DeleteAllResidues();
3469     }
3470     return 0;
3471   }
3472 
DeleteAllResidues()3473   int Model::DeleteAllResidues()  {
3474   int i,k;
3475     k = 0;
3476     for (i=0;i<nChains;i++)
3477       if (chain[i])
3478         k += chain[i]->DeleteAllResidues();
3479     return k;
3480   }
3481 
3482 
DeleteSolvent()3483   int Model::DeleteSolvent()  {
3484   int i,k;
3485     Exclude = false;
3486     k = 0;
3487     for (i=0;i<nChains;i++)
3488       if (chain[i])  {
3489         k += chain[i]->DeleteSolvent();
3490         chain[i]->TrimResidueTable();
3491         if (chain[i]->nResidues<=0)  {
3492           delete chain[i];
3493           chain[i] = NULL;
3494         }
3495       }
3496     Exclude = true;
3497     return k;
3498   }
3499 
3500 
AddResidue(const ChainID chainID,PResidue res)3501   int Model::AddResidue ( const ChainID chainID, PResidue res )  {
3502   PChain chn;
3503     chn = GetChain ( chainID );
3504     if (chn)  return chn->AddResidue ( res );
3505     return 0;
3506   }
3507 
AddResidue(int chainNo,PResidue res)3508   int Model::AddResidue ( int chainNo, PResidue res )  {
3509     if ((0<=chainNo) && (chainNo<nChains))  {
3510       if (chain[chainNo])
3511         return chain[chainNo]->AddResidue ( res );
3512     }
3513     return 0;
3514   }
3515 
3516 
_ExcludeChain(const ChainID chainID)3517   int  Model::_ExcludeChain ( const ChainID chainID )  {
3518   //   _ExcludeChain(..) excludes (but does not dispose!) a chain
3519   // from the model. Returns 1 if the model gets empty and 0 otherwise.
3520   int  i,k;
3521 
3522     if (!Exclude)  return 0;
3523 
3524     // find the chain
3525     k = -1;
3526     for (i=0;(i<nChains) && (k<0);i++)
3527       if (!strcmp(chainID,chain[i]->chainID))
3528         k = i;
3529 
3530     if (k>=0)  {
3531       for (i=k+1;i<nChains;i++)
3532         chain[i-1] = chain[i];
3533       nChains--;
3534       chain[nChains] = NULL;
3535     }
3536 
3537     if (nChains<=0)  return 1;
3538                else  return 0;
3539 
3540   }
3541 
3542 
3543   //  --------------------  Sort chains  ----------------------------
3544 
3545   DefineClass(QSortChains)
3546 
3547   class QSortChains : public QuickSort  {
3548     public :
QSortChains()3549       QSortChains() : QuickSort() { sKey = 0; }
3550       int  Compare ( int i, int j );
3551       void Swap    ( int i, int j );
3552       void Sort    ( PPChain chain, int nChains, int sortKey );
3553     private :
3554       int sKey;
3555   };
3556 
Compare(int i,int j)3557   int QSortChains::Compare ( int i, int j )  {
3558   int diff;
3559 
3560     diff = strcmp ( (PPChain(data))[i]->GetChainID(),
3561                     (PPChain(data))[j]->GetChainID() );
3562     if (diff>0)  diff =  1;
3563     if (diff<0)  diff = -1;
3564 
3565     if (sKey==SORT_CHAIN_ChainID_Desc) return -diff;
3566 
3567     return diff;
3568 
3569   }
3570 
Swap(int i,int j)3571   void QSortChains::Swap ( int i, int j )  {
3572   PChain chn;
3573     chn = ((PPChain)data)[i];
3574     ((PPChain)data)[i] = ((PPChain)data)[j];
3575     ((PPChain)data)[j] = chn;
3576   }
3577 
Sort(PPChain chain,int nChains,int sortKey)3578   void QSortChains::Sort ( PPChain chain, int nChains, int sortKey )  {
3579     sKey = sortKey;
3580     QuickSort::Sort ( &(chain[0]),nChains );
3581   }
3582 
SortChains(int sortKey)3583   void Model::SortChains ( int sortKey )  {
3584   QSortChains SC;
3585     TrimChainTable();
3586     SC.Sort ( chain,nChains,sortKey );
3587   }
3588 
3589 
3590   // --------------------  Extracting atoms  -----------------------
3591 
3592 
GetNumberOfAtoms(const ChainID chainID,int seqNo,const InsCode insCode)3593   int  Model::GetNumberOfAtoms ( const ChainID chainID, int seqNo,
3594                                   const InsCode insCode )  {
3595   PChain   chn;
3596   PResidue res;
3597     chn = GetChain ( chainID );
3598     if (chn)  {
3599       res = chn->GetResidue ( seqNo,insCode );
3600       if (res)  return res->nAtoms;
3601     }
3602     return 0;
3603   }
3604 
GetNumberOfAtoms(int chainNo,int seqNo,const InsCode insCode)3605   int  Model::GetNumberOfAtoms ( int chainNo, int seqNo,
3606                                   const InsCode insCode )  {
3607   PChain   chn;
3608   PResidue res;
3609     chn = GetChain ( chainNo );
3610     if (chn)  {
3611       res = chn->GetResidue ( seqNo,insCode );
3612       if (res)  return res->nAtoms;
3613     }
3614     return 0;
3615   }
3616 
GetNumberOfAtoms(const ChainID chainID,int resNo)3617   int  Model::GetNumberOfAtoms ( const ChainID chainID, int resNo )  {
3618   PChain   chn;
3619   PResidue res;
3620     chn = GetChain ( chainID );
3621     if (chn)  {
3622       if ((0<=resNo) && (resNo<chn->nResidues))  {
3623         res = chn->residue[resNo];
3624         if (res)  return res->nAtoms;
3625       }
3626     }
3627     return 0;
3628   }
3629 
GetNumberOfAtoms(int chainNo,int resNo)3630   int  Model::GetNumberOfAtoms ( int chainNo, int resNo )  {
3631   PChain   chn;
3632   PResidue res;
3633     if ((0<=chainNo) && (chainNo<nChains))  {
3634       chn = chain[chainNo];
3635       if (chn)  {
3636         if ((0<=resNo) && (resNo<chn->nResidues))  {
3637           res = chn->residue[resNo];
3638           if (res)  return res->nAtoms;
3639         }
3640       }
3641     }
3642     return 0;
3643   }
3644 
GetAtom(const ChainID chID,int seqNo,const InsCode insCode,const AtomName aname,const Element elmnt,const AltLoc aloc)3645   PAtom  Model::GetAtom ( const ChainID  chID,
3646                             int            seqNo,
3647                             const InsCode  insCode,
3648                             const AtomName aname,
3649                             const Element  elmnt,
3650                             const AltLoc   aloc
3651                           )  {
3652   PChain   chn;
3653   PResidue res;
3654     chn = GetChain ( chID );
3655     if (chn)  {
3656       res = chn->GetResidue ( seqNo,insCode );
3657       if (res)
3658         return res->GetAtom ( aname,elmnt,aloc );
3659     }
3660     return NULL;
3661   }
3662 
GetAtom(const ChainID chID,int seqNo,const InsCode insCode,int atomNo)3663   PAtom Model::GetAtom ( const ChainID chID,    int seqNo,
3664                            const InsCode insCode, int   atomNo )  {
3665   PChain   chn;
3666   PResidue res;
3667     chn = GetChain ( chID );
3668     if (chn)  {
3669       res = chn->GetResidue ( seqNo,insCode );
3670       if (res)  {
3671         if ((0<=atomNo) && (atomNo<res->nAtoms))
3672           return res->atom[atomNo];
3673       }
3674     }
3675     return NULL;
3676   }
3677 
GetAtom(const ChainID chID,int resNo,const AtomName aname,const Element elmnt,const AltLoc aloc)3678   PAtom Model::GetAtom ( const ChainID  chID,
3679                            int            resNo,
3680                            const AtomName aname,
3681                            const Element  elmnt,
3682                            const AltLoc   aloc )  {
3683   PChain   chn;
3684   PResidue res;
3685     chn = GetChain ( chID );
3686     if (chn)  {
3687       if ((0<=resNo) && (resNo<chn->nResidues))  {
3688         res = chn->residue[resNo];
3689         if (res)
3690           return res->GetAtom ( aname,elmnt,aloc );
3691       }
3692     }
3693     return NULL;
3694   }
3695 
GetAtom(const ChainID chID,int resNo,int atomNo)3696   PAtom Model::GetAtom ( const ChainID chID, int resNo, int atomNo )  {
3697   PChain   chn;
3698   PResidue res;
3699     chn = GetChain ( chID );
3700     if (chn)  {
3701       if ((0<=resNo) && (resNo<chn->nResidues))  {
3702         res = chn->residue[resNo];
3703         if (res)  {
3704           if ((0<=atomNo) && (atomNo<res->nAtoms))
3705             return res->atom[atomNo];
3706         }
3707       }
3708     }
3709     return NULL;
3710   }
3711 
GetAtom(int chNo,int seqNo,const InsCode insCode,const AtomName aname,const Element elmnt,const AltLoc aloc)3712   PAtom Model::GetAtom ( int chNo, int seqNo,
3713                            const InsCode  insCode,
3714                            const AtomName aname,
3715                            const Element  elmnt,
3716                            const AltLoc   aloc )  {
3717   PResidue res;
3718     if ((0<=chNo) && (chNo<nChains))  {
3719       if (chain[chNo])  {
3720         res = chain[chNo]->GetResidue ( seqNo,insCode );
3721         if (res)
3722           return res->GetAtom ( aname,elmnt,aloc );
3723       }
3724     }
3725     return NULL;
3726   }
3727 
GetAtom(int chNo,int seqNo,const InsCode insCode,int atomNo)3728   PAtom Model::GetAtom ( int chNo, int seqNo, const InsCode insCode,
3729                            int atomNo )  {
3730   PResidue res;
3731     if ((0<=chNo) && (chNo<nChains))  {
3732       if (chain[chNo])  {
3733         res = chain[chNo]->GetResidue ( seqNo,insCode );
3734         if (res)  {
3735           if ((0<=atomNo) && (atomNo<res->nAtoms))
3736             return res->atom[atomNo];
3737         }
3738       }
3739     }
3740     return NULL;
3741   }
3742 
GetAtom(int chNo,int resNo,const AtomName aname,const Element elmnt,const AltLoc aloc)3743   PAtom Model::GetAtom ( int chNo, int resNo,
3744                            const AtomName aname,
3745                            const Element  elmnt,
3746                            const AltLoc   aloc )  {
3747   PResidue res;
3748     if ((0<=chNo) && (chNo<nChains))  {
3749       if (chain[chNo])  {
3750         if ((0<=resNo) && (resNo<chain[chNo]->nResidues))  {
3751           res = chain[chNo]->residue[resNo];
3752           if (res)
3753             return res->GetAtom ( aname,elmnt,aloc );
3754         }
3755       }
3756     }
3757     return NULL;
3758   }
3759 
GetAtom(int chNo,int resNo,int atomNo)3760   PAtom Model::GetAtom ( int chNo, int resNo, int atomNo )  {
3761   PResidue res;
3762     if ((0<=chNo) && (chNo<nChains))  {
3763       if (chain[chNo])  {
3764         if ((0<=resNo) && (resNo<chain[chNo]->nResidues))  {
3765           res = chain[chNo]->residue[resNo];
3766           if (res)  {
3767             if ((0<=atomNo) && (atomNo<res->nAtoms))
3768               return res->atom[atomNo];
3769           }
3770         }
3771       }
3772     }
3773     return NULL;
3774   }
3775 
3776 
GetAtomTable(const ChainID chainID,int seqNo,const InsCode insCode,PPAtom & atomTable,int & NumberOfAtoms)3777   void Model::GetAtomTable ( const ChainID chainID, int seqNo,
3778                               const InsCode insCode,
3779                               PPAtom & atomTable,
3780                               int & NumberOfAtoms )  {
3781   PResidue res;
3782     atomTable     = NULL;
3783     NumberOfAtoms = 0;
3784     res = GetResidue ( chainID,seqNo,insCode );
3785     if (res)  {
3786       atomTable     = res->atom;
3787       NumberOfAtoms = res->nAtoms;
3788     }
3789   }
3790 
GetAtomTable(int chainNo,int seqNo,const InsCode insCode,PPAtom & atomTable,int & NumberOfAtoms)3791   void Model::GetAtomTable ( int chainNo, int seqNo,
3792                               const InsCode insCode,
3793                               PPAtom & atomTable,
3794                               int & NumberOfAtoms )  {
3795   PResidue res;
3796     atomTable     = NULL;
3797     NumberOfAtoms = 0;
3798     res = GetResidue ( chainNo,seqNo,insCode );
3799     if (res)  {
3800       atomTable     = res->atom;
3801       NumberOfAtoms = res->nAtoms;
3802     }
3803   }
3804 
GetAtomTable(const ChainID chainID,int resNo,PPAtom & atomTable,int & NumberOfAtoms)3805   void Model::GetAtomTable ( const ChainID chainID, int resNo,
3806                               PPAtom & atomTable,
3807                               int & NumberOfAtoms )  {
3808   PResidue res;
3809     atomTable     = NULL;
3810     NumberOfAtoms = 0;
3811     res = GetResidue ( chainID,resNo );
3812     if (res)  {
3813       atomTable     = res->atom;
3814       NumberOfAtoms = res->nAtoms;
3815     }
3816   }
3817 
GetAtomTable(int chainNo,int resNo,PPAtom & atomTable,int & NumberOfAtoms)3818   void Model::GetAtomTable ( int chainNo, int resNo,
3819                               PPAtom & atomTable,
3820                               int & NumberOfAtoms )  {
3821   PResidue res;
3822     atomTable     = NULL;
3823     NumberOfAtoms = 0;
3824     res = GetResidue ( chainNo,resNo );
3825     if (res)  {
3826       atomTable     = res->atom;
3827       NumberOfAtoms = res->nAtoms;
3828     }
3829   }
3830 
3831 
GetAtomTable1(const ChainID chainID,int seqNo,const InsCode insCode,PPAtom & atomTable,int & NumberOfAtoms)3832   void Model::GetAtomTable1 ( const ChainID chainID, int seqNo,
3833                                const InsCode insCode,
3834                                PPAtom & atomTable,
3835                                int & NumberOfAtoms )  {
3836   PResidue res;
3837     res = GetResidue ( chainID,seqNo,insCode );
3838     if (res)
3839       res->GetAtomTable1 ( atomTable,NumberOfAtoms );
3840     else  {
3841       if (atomTable)  delete[] atomTable;
3842       atomTable     = NULL;
3843       NumberOfAtoms = 0;
3844     }
3845   }
3846 
GetAtomTable1(int chainNo,int seqNo,const InsCode insCode,PPAtom & atomTable,int & NumberOfAtoms)3847   void Model::GetAtomTable1 ( int chainNo, int seqNo,
3848                                const InsCode insCode,
3849                                PPAtom & atomTable,
3850                                int & NumberOfAtoms )  {
3851   PResidue res;
3852     res = GetResidue ( chainNo,seqNo,insCode );
3853     if (res)
3854       res->GetAtomTable1 ( atomTable,NumberOfAtoms );
3855     else  {
3856       if (atomTable)  delete[] atomTable;
3857       atomTable     = NULL;
3858       NumberOfAtoms = 0;
3859     }
3860   }
3861 
GetAtomTable1(const ChainID chainID,int resNo,PPAtom & atomTable,int & NumberOfAtoms)3862   void Model::GetAtomTable1 ( const ChainID chainID, int resNo,
3863                                PPAtom & atomTable,
3864                                int & NumberOfAtoms )  {
3865   PResidue res;
3866     res = GetResidue ( chainID,resNo );
3867     if (res)
3868       res->GetAtomTable1 ( atomTable,NumberOfAtoms );
3869     else  {
3870       if (atomTable)  delete[] atomTable;
3871       atomTable     = NULL;
3872       NumberOfAtoms = 0;
3873     }
3874   }
3875 
GetAtomTable1(int chainNo,int resNo,PPAtom & atomTable,int & NumberOfAtoms)3876   void Model::GetAtomTable1 ( int chainNo, int resNo,
3877                                PPAtom & atomTable,
3878                                int & NumberOfAtoms )  {
3879   PResidue res;
3880     res = GetResidue ( chainNo,resNo );
3881     if (res)
3882       res->GetAtomTable1 ( atomTable,NumberOfAtoms );
3883     else  {
3884       if (atomTable)  delete[] atomTable;
3885       atomTable     = NULL;
3886       NumberOfAtoms = 0;
3887     }
3888   }
3889 
3890 
3891 
DeleteAtom(const ChainID chID,int seqNo,const InsCode insCode,const AtomName aname,const Element elmnt,const AltLoc aloc)3892   int  Model::DeleteAtom ( const ChainID  chID,
3893                             int            seqNo,
3894                             const InsCode  insCode,
3895                             const AtomName aname,
3896                             const Element  elmnt,
3897                             const AltLoc   aloc
3898                           )  {
3899   PChain chn;
3900     chn = GetChain ( chID );
3901     if (chn)
3902       return  chn->DeleteAtom ( seqNo,insCode,aname,elmnt,aloc );
3903     return 0;
3904   }
3905 
DeleteAtom(const ChainID chID,int seqNo,const InsCode insCode,int atomNo)3906   int  Model::DeleteAtom ( const ChainID chID,    int seqNo,
3907                             const InsCode insCode, int   atomNo )  {
3908   PChain chn;
3909     chn = GetChain ( chID );
3910     if (chn)  return chn->DeleteAtom ( seqNo,insCode,atomNo );
3911     return 0;
3912   }
3913 
DeleteAtom(const ChainID chID,int resNo,const AtomName aname,const Element elmnt,const AltLoc aloc)3914   int  Model::DeleteAtom ( const ChainID  chID,
3915                             int            resNo,
3916                             const AtomName aname,
3917                             const Element  elmnt,
3918                             const AltLoc   aloc )  {
3919   PChain chn;
3920     chn = GetChain ( chID );
3921     if (chn)  return chn->DeleteAtom ( resNo,aname,elmnt,aloc );
3922     return 0;
3923   }
3924 
DeleteAtom(const ChainID chID,int resNo,int atomNo)3925   int  Model::DeleteAtom ( const ChainID chID, int resNo, int atomNo ) {
3926   PChain chn;
3927     chn = GetChain ( chID );
3928     if (chn)  return chn->DeleteAtom ( resNo,atomNo );
3929     return 0;
3930   }
3931 
DeleteAtom(int chNo,int seqNo,const InsCode insCode,const AtomName aname,const Element elmnt,const AltLoc aloc)3932   int  Model::DeleteAtom ( int chNo, int seqNo,
3933                             const InsCode  insCode,
3934                             const AtomName aname,
3935                             const Element  elmnt,
3936                             const AltLoc   aloc )  {
3937     if ((0<=chNo) && (chNo<nChains))  {
3938       if (chain[chNo])
3939         return chain[chNo]->DeleteAtom ( seqNo,insCode,aname,
3940                                          elmnt,aloc );
3941     }
3942     return 0;
3943   }
3944 
DeleteAtom(int chNo,int seqNo,const InsCode insCode,int atomNo)3945   int Model::DeleteAtom ( int chNo, int seqNo, const InsCode insCode,
3946                            int atomNo )  {
3947     if ((0<=chNo) && (chNo<nChains))  {
3948       if (chain[chNo])
3949         return  chain[chNo]->DeleteAtom ( seqNo,insCode,atomNo );
3950     }
3951     return 0;
3952   }
3953 
DeleteAtom(int chNo,int resNo,const AtomName aname,const Element elmnt,const AltLoc aloc)3954   int Model::DeleteAtom ( int chNo, int resNo,
3955                            const AtomName aname,
3956                            const Element  elmnt,
3957                            const AltLoc   aloc )  {
3958     if ((0<=chNo) && (chNo<nChains))  {
3959       if (chain[chNo])
3960         return chain[chNo]->DeleteAtom ( resNo,aname,elmnt,aloc );
3961     }
3962     return 0;
3963   }
3964 
DeleteAtom(int chNo,int resNo,int atomNo)3965   int Model::DeleteAtom ( int chNo, int resNo, int atomNo )  {
3966     if ((0<=chNo) && (chNo<nChains))  {
3967       if (chain[chNo])
3968         return chain[chNo]->DeleteAtom ( resNo,atomNo );
3969     }
3970     return 0;
3971   }
3972 
DeleteAllAtoms(const ChainID chID,int seqNo,const InsCode insCode)3973   int Model::DeleteAllAtoms ( const ChainID chID, int seqNo,
3974                                const InsCode insCode )  {
3975   PChain chn;
3976     chn = GetChain ( chID );
3977     if (chn)  return chn->DeleteAllAtoms ( seqNo,insCode );
3978     return 0;
3979   }
3980 
DeleteAllAtoms(const ChainID chID,int resNo)3981   int Model::DeleteAllAtoms ( const ChainID chID, int resNo )  {
3982   PChain chn;
3983     chn = GetChain ( chID );
3984     if (chn)  return chn->DeleteAllAtoms ( resNo );
3985     return 0;
3986   }
3987 
DeleteAllAtoms(const ChainID chID)3988   int Model::DeleteAllAtoms ( const ChainID chID )  {
3989   PChain chn;
3990     chn = GetChain ( chID );
3991     if (chn)  return chn->DeleteAllAtoms();
3992     return 0;
3993   }
3994 
DeleteAllAtoms(int chNo,int seqNo,const InsCode insCode)3995   int Model::DeleteAllAtoms ( int chNo, int seqNo,
3996                                const InsCode insCode )  {
3997     if ((0<=chNo) && (chNo<nChains))  {
3998       if (chain[chNo])
3999         return chain[chNo]->DeleteAllAtoms ( seqNo,insCode );
4000     }
4001     return 0;
4002   }
4003 
DeleteAllAtoms(int chNo,int resNo)4004   int Model::DeleteAllAtoms ( int chNo, int resNo )  {
4005     if ((0<=chNo) && (chNo<nChains))  {
4006       if (chain[chNo])
4007         return chain[chNo]->DeleteAllAtoms ( resNo );
4008     }
4009     return 0;
4010   }
4011 
DeleteAllAtoms(int chNo)4012   int Model::DeleteAllAtoms ( int chNo )  {
4013     if ((0<=chNo) && (chNo<nChains))  {
4014       if (chain[chNo])
4015         return chain[chNo]->DeleteAllAtoms();
4016     }
4017     return 0;
4018   }
4019 
DeleteAllAtoms()4020   int Model::DeleteAllAtoms()  {
4021   int i,k;
4022     k = 0;
4023     for (i=0;i<nChains;i++)
4024       if (chain[i])  k += chain[i]->DeleteAllAtoms();
4025     return k;
4026   }
4027 
DeleteAltLocs()4028   int Model::DeleteAltLocs()  {
4029   //  This function leaves only alternative location with maximal
4030   // occupancy, if those are equal or unspecified, the one with
4031   // "least" alternative location indicator.
4032   //  The function returns the number of deleted. All tables remain
4033   // untrimmed, so that explicit trimming or calling FinishStructEdit()
4034   // is required.
4035   int i,n;
4036 
4037     n = 0;
4038     for (i=0;i<nChains;i++)
4039       if (chain[i])  n += chain[i]->DeleteAltLocs();
4040 
4041     return n;
4042 
4043   }
4044 
4045 
AddAtom(const ChainID chID,int seqNo,const InsCode insCode,PAtom atom)4046   int Model::AddAtom ( const ChainID chID, int seqNo,
4047                         const InsCode insCode,
4048                         PAtom atom )  {
4049   PChain chn;
4050     chn = GetChain ( chID );
4051     if (chn)  return chn->AddAtom ( seqNo,insCode,atom );
4052     return 0;
4053   }
4054 
AddAtom(const ChainID chID,int resNo,PAtom atom)4055   int Model::AddAtom ( const ChainID chID, int resNo, PAtom  atom )  {
4056   PChain chn;
4057     chn = GetChain ( chID );
4058     if (chn)  return chn->AddAtom ( resNo,atom );
4059     return 0;
4060   }
4061 
AddAtom(int chNo,int seqNo,const InsCode insCode,PAtom atom)4062   int Model::AddAtom ( int chNo, int seqNo, const InsCode insCode,
4063                         PAtom atom )  {
4064     if ((0<=chNo) && (chNo<nChains))  {
4065       if (chain[chNo])
4066         return chain[chNo]->AddAtom ( seqNo,insCode,atom );
4067     }
4068     return 0;
4069   }
4070 
AddAtom(int chNo,int resNo,PAtom atom)4071   int Model::AddAtom ( int chNo, int resNo, PAtom atom )  {
4072     if ((0<=chNo) && (chNo<nChains))  {
4073       if (chain[chNo])
4074         return chain[chNo]->AddAtom ( resNo,atom );
4075     }
4076     return 0;
4077   }
4078 
4079 
4080 
GetAtomStatistics(RAtomStat AS)4081   void  Model::GetAtomStatistics ( RAtomStat AS )  {
4082     AS.Init();
4083     CalAtomStatistics ( AS );
4084     AS.Finish();
4085   }
4086 
CalAtomStatistics(RAtomStat AS)4087   void  Model::CalAtomStatistics ( RAtomStat AS )  {
4088   int i;
4089     for (i=0;i<nChains;i++)
4090       if (chain[i])  chain[i]->CalAtomStatistics ( AS );
4091   }
4092 
4093 
4094 
ConvertPDBString(pstr PDBString)4095   ERROR_CODE Model::ConvertPDBString ( pstr PDBString ) {
4096   //   Interprets PDB records DBREF, SEQADV, SEQRES, MODRES.
4097   //   Returns zero if the line was converted, otherwise returns a
4098   // non-negative value of Error_XXXX.
4099   //   PDBString must be not shorter than 81 characters.
4100   ChainID    chainID;
4101   PChain     chn;
4102   PHelix     helix;
4103   PTurn      turn;
4104   PLink      link;
4105   PLinkR     linkR;
4106   PCisPep    cispep;
4107   ERROR_CODE RC;
4108 
4109     //  pad input line with spaces, if necessary
4110     PadSpaces ( PDBString,80 );
4111 
4112     chainID[0] = char(0);
4113     chainID[1] = char(0);
4114 
4115     if (!strncmp(PDBString,"DBREF ",6))  {
4116 
4117       if (PDBString[12]!=' ')  chainID[0] = PDBString[12];
4118       chn = GetChainCreate ( chainID,false );
4119       return chn->ConvertDBREF ( PDBString );
4120 
4121     } else if (!strncmp(PDBString,"SEQADV",6))  {
4122 
4123       if (PDBString[16]!=' ')  chainID[0] = PDBString[16];
4124       chn = GetChainCreate ( chainID,false );
4125       return chn->ConvertSEQADV ( PDBString );
4126 
4127     } else if (!strncmp(PDBString,"SEQRES",6))  {
4128 
4129       if (PDBString[11]!=' ')  chainID[0] = PDBString[11];
4130       chn = GetChainCreate ( chainID,false );
4131       return chn->ConvertSEQRES ( PDBString );
4132 
4133     } else if (!strncmp(PDBString,"MODRES",6))  {
4134 
4135       if (PDBString[16]!=' ')  chainID[0] = PDBString[16];
4136       chn = GetChainCreate ( chainID,false );
4137       return chn->ConvertMODRES ( PDBString );
4138 
4139     } else if (!strncmp(PDBString,"HET   ",6))  {
4140 
4141       if (PDBString[12]!=' ')  chainID[0] = PDBString[12];
4142       chn = GetChainCreate ( chainID,false );
4143       return chn->ConvertHET ( PDBString );
4144 
4145     } else if (!strncmp(PDBString,"HETNAM",6))  {
4146 
4147       hetCompounds.ConvertHETNAM ( PDBString );
4148       return Error_NoError;
4149 
4150     } else if (!strncmp(PDBString,"HETSYN",6))  {
4151 
4152       hetCompounds.ConvertHETSYN ( PDBString );
4153       return Error_NoError;
4154 
4155     } else if (!strncmp(PDBString,"FORMUL",6))  {
4156 
4157       hetCompounds.ConvertFORMUL ( PDBString );
4158       return Error_NoError;
4159 
4160     } else if (!strncmp(PDBString,"HELIX ",6))  {
4161 
4162       helix = new Helix();
4163       RC    = helix->ConvertPDBASCII(PDBString);
4164       if (RC==0)  helices.AddData ( helix );
4165             else  delete helix;
4166       return RC;
4167 
4168     } else if (!strncmp(PDBString,"SHEET ",6))  {
4169 
4170       return sheets.ConvertPDBASCII ( PDBString );
4171 
4172     } else if (!strncmp(PDBString,"TURN  ",6))  {
4173 
4174       turn = new Turn();
4175       RC   = turn->ConvertPDBASCII(PDBString);
4176       if (RC==0)  turns.AddData ( turn );
4177             else  delete turn;
4178       return RC;
4179 
4180     } else if (!strncmp(PDBString,"LINK  ",6))  {
4181 
4182       link = new Link();
4183       RC   = link->ConvertPDBASCII(PDBString);
4184       if (RC==0)  links.AddData ( link );
4185             else  delete link;
4186       return RC;
4187 
4188 
4189     } else if (!strncmp(PDBString,"LINKR ",6))  {
4190 
4191       linkR = new LinkR();
4192       RC   = linkR->ConvertPDBASCII(PDBString);
4193       if (RC==0)  linkRs.AddData ( linkR );
4194             else  delete linkR;
4195       return RC;
4196 
4197     } else if (!strncmp(PDBString,"CISPEP",6))  {
4198 
4199       cispep = new CisPep();
4200       RC   = cispep->ConvertPDBASCII(PDBString);
4201       if (RC==0)  cisPeps.AddData ( cispep );
4202             else  delete cispep;
4203       return RC;
4204 
4205     } else
4206       return Error_WrongSection;
4207 
4208   }
4209 
4210 
PDBASCIIDumpPS(io::RFile f)4211   void  Model::PDBASCIIDumpPS ( io::RFile f )  {
4212   int i;
4213 
4214     for (i=0;i<nChains;i++)
4215       if (chain[i])
4216         chain[i]->DBRef.PDBASCIIDump ( f );
4217 
4218     for (i=0;i<nChains;i++)
4219       if (chain[i])
4220         chain[i]->seqAdv.PDBASCIIDump ( f );
4221 
4222     for (i=0;i<nChains;i++)
4223       if (chain[i])
4224         chain[i]->seqRes.PDBASCIIDump ( f );
4225 
4226     for (i=0;i<nChains;i++)
4227       if (chain[i])
4228         chain[i]->modRes.PDBASCIIDump ( f );
4229 
4230     for (i=0;i<nChains;i++)
4231       if (chain[i])
4232         chain[i]->Het.PDBASCIIDump ( f );
4233 
4234     hetCompounds.PDBASCIIDump ( f );
4235     helices     .PDBASCIIDump ( f );
4236     sheets      .PDBASCIIDump ( f );
4237     turns       .PDBASCIIDump ( f );
4238     links       .PDBASCIIDump ( f );
4239     linkRs      .PDBASCIIDump ( f );
4240 
4241   }
4242 
PDBASCIIDumpCP(io::RFile f)4243   void  Model::PDBASCIIDumpCP ( io::RFile f )  {
4244     cisPeps.PDBASCIIDump ( f );
4245   }
4246 
PDBASCIIDump(io::RFile f)4247   void  Model::PDBASCIIDump ( io::RFile f )  {
4248   char  S[100];
4249   int   i;
4250   bool  singleModel = true;
4251 
4252     if (manager)
4253       singleModel = (manager->nModels<=1);
4254 
4255     if (!singleModel)  {
4256       strcpy      ( S,"MODEL " );
4257       PadSpaces   ( S,80 );
4258       PutInteger  ( &(S[10]),serNum,4 );
4259       f.WriteLine ( S );
4260     }
4261 
4262     for (i=0;i<nChains;i++)
4263       if (chain[i])
4264         chain[i]->PDBASCIIAtomDump ( f );
4265 
4266     if (!singleModel)  {
4267       strcpy      ( S,"ENDMDL" );
4268       PadSpaces   ( S,80 );
4269       f.WriteLine ( S );
4270     }
4271 
4272   }
4273 
4274 
MakeAtomCIF(mmcif::PData CIF)4275   void  Model::MakeAtomCIF ( mmcif::PData CIF )  {
4276   int  i;
4277     for (i=0;i<nChains;i++)
4278       if (chain[i])
4279         chain[i]->MakeAtomCIF ( CIF );
4280   }
4281 
4282 
MakePSCIF(mmcif::PData CIF)4283   void  Model::MakePSCIF ( mmcif::PData CIF )  {
4284   int  i;
4285 
4286     for (i=0;i<nChains;i++)
4287       if (chain[i])
4288         chain[i]->DBRef.MakeCIF ( CIF );
4289 
4290     for (i=0;i<nChains;i++)
4291       if (chain[i])
4292         chain[i]->seqAdv.MakeCIF ( CIF );
4293 
4294     for (i=0;i<nChains;i++)
4295       if (chain[i])
4296         chain[i]->seqRes.MakeCIF ( CIF );
4297 
4298     for (i=0;i<nChains;i++)
4299       if (chain[i])
4300         chain[i]->modRes.MakeCIF ( CIF );
4301 
4302     for (i=0;i<nChains;i++)
4303       if (chain[i])
4304         chain[i]->Het.MakeCIF ( CIF );
4305 
4306     hetCompounds.MakeCIF ( CIF );
4307     helices     .MakeCIF ( CIF );
4308     sheets      .MakeCIF ( CIF );
4309     turns       .MakeCIF ( CIF );
4310     links       .MakeCIF ( CIF );
4311     linkRs      .MakeCIF ( CIF );
4312 
4313   }
4314 
GetCIFPSClass(mmcif::PData CIF,int ClassID)4315   ERROR_CODE Model::GetCIFPSClass ( mmcif::PData CIF, int ClassID )  {
4316   ChainContainer  PSClass;
4317   PChainContainer Dest;
4318   ERROR_CODE      RC;
4319   cpstr           chainID;
4320   PChain          chn;
4321     PSClass.SetChain ( NULL );
4322     RC = PSClass.GetCIF ( CIF,ClassID );
4323     if (RC!=Error_NoError)  return RC;
4324     chainID = PSClass.Get1stChainID();
4325     while (chainID)  {
4326       chn = GetChainCreate ( chainID,false );
4327       switch (ClassID)  {
4328         case ClassID_DBReference : Dest = &(chn->DBRef);   break;
4329         case ClassID_SeqAdv      : Dest = &(chn->seqAdv);  break;
4330         case ClassID_ModRes      : Dest = &(chn->modRes);  break;
4331         case ClassID_Het         : Dest = &(chn->Het);     break;
4332         default                  : Dest = NULL;
4333       }
4334       if (Dest)  {
4335         PSClass.MoveByChainID ( chainID,Dest );
4336         Dest->SetChain ( chn );
4337       } else
4338         printf ( " **** PROGRAM ERROR: wrong call to"
4339                  " Model::GetCIFPSClass(..)\n" );
4340       chainID = PSClass.Get1stChainID();
4341     }
4342     return Error_NoError;
4343   }
4344 
GetCIF(mmcif::PData CIF)4345   ERROR_CODE Model::GetCIF ( mmcif::PData CIF ) {
4346   SeqRes     seqRes;
4347   ERROR_CODE RC;
4348   PChain     chn;
4349 
4350     RC = GetCIFPSClass ( CIF,ClassID_DBReference );
4351     if (RC!=Error_NoError)  return RC;
4352 
4353     RC = GetCIFPSClass ( CIF,ClassID_SeqAdv );
4354     if (RC!=Error_NoError)  return RC;
4355 
4356     RC = seqRes.GetCIF ( CIF );
4357     while (RC==Error_NoError)  {
4358       chn = GetChainCreate ( seqRes.chainID,false );
4359       chn->seqRes.Copy ( &seqRes );
4360       RC  = seqRes.GetCIF ( CIF );
4361     }
4362 
4363     RC = GetCIFPSClass ( CIF,ClassID_ModRes );
4364     if (RC!=Error_NoError)  return RC;
4365 
4366     RC = GetCIFPSClass ( CIF,ClassID_Het );
4367     if (RC!=Error_NoError)  return RC;
4368 
4369     hetCompounds.GetCIF ( CIF );
4370     helices     .GetCIF ( CIF,ClassID_Helix );
4371     sheets      .GetCIF ( CIF );
4372     turns       .GetCIF ( CIF,ClassID_Turn  );
4373     links       .GetCIF ( CIF,ClassID_Link  );
4374     linkRs      .GetCIF ( CIF,ClassID_LinkR );
4375 
4376     return RC;
4377 
4378   }
4379 
GetEntryID()4380   cpstr  Model::GetEntryID()  {
4381     if (manager)  return manager->title.idCode;
4382             else  return pstr("");
4383   }
4384 
SetEntryID(const IDCode idCode)4385   void  Model::SetEntryID ( const IDCode idCode )  {
4386     if (manager)
4387       manager->SetEntryID ( idCode );
4388   }
4389 
GetNumberOfAllAtoms()4390   int   Model::GetNumberOfAllAtoms()  {
4391     if (manager)  return manager->nAtoms;
4392             else  return 0;
4393   }
4394 
GetSerNum()4395   int   Model::GetSerNum()  {
4396     return serNum;
4397   }
4398 
GetAllAtoms()4399   PAtom * Model::GetAllAtoms()  {
4400     if (manager)  return manager->atom;
4401             else  return NULL;
4402   }
4403 
4404 
GetModelID(pstr modelID)4405   cpstr  Model::GetModelID ( pstr modelID )  {
4406     modelID[0] = char(0);
4407     sprintf ( modelID,"/%i",serNum );
4408     return modelID;
4409   }
4410 
GetNumberOfModels()4411   int   Model::GetNumberOfModels()  {
4412     if (manager)  return manager->nModels;
4413             else  return 0;
4414   }
4415 
4416 
Copy(PModel model)4417   void  Model::Copy ( PModel model )  {
4418   //  modify both Model::_copy and Model::Copy methods simultaneously!
4419   int i;
4420 
4421     FreeMemory();
4422 
4423     if (model)  {
4424 
4425       serNum       = model->serNum;
4426       nChains      = model->nChains;
4427       nChainsAlloc = nChains;
4428       if (nChains>0)  {
4429         chain = new PChain[nChainsAlloc];
4430         for (i=0;i<nChains;i++)  {
4431           if (model->chain[i])  {
4432             chain[i] = newChain();
4433             chain[i]->SetModel ( this );
4434             chain[i]->Copy ( model->chain[i] );
4435           } else
4436             chain[i] = NULL;
4437         }
4438       }
4439 
4440       hetCompounds.Copy ( &(model->hetCompounds) );
4441       helices     .Copy ( &(model->helices)      );
4442       sheets      .Copy ( &(model->sheets)       );
4443       turns       .Copy ( &(model->turns)        );
4444       links       .Copy ( &(model->links)        );
4445       linkRs      .Copy ( &(model->linkRs)       );
4446       cisPeps     .Copy ( &(model->cisPeps)      );
4447 
4448     }
4449 
4450   }
4451 
CopyHets(PModel model)4452   void  Model::CopyHets ( PModel model )  {
4453     if (model)  hetCompounds.Copy ( &(model->hetCompounds) );
4454   }
4455 
CopySecStructure(PModel model)4456   void  Model::CopySecStructure ( PModel model )  {
4457     if (model)  {
4458       helices.Copy ( &(model->helices) );
4459       sheets .Copy ( &(model->sheets)  );
4460       turns  .Copy ( &(model->turns)   );
4461     }
4462   }
4463 
CopyLinks(PModel model)4464   void  Model::CopyLinks ( PModel model )  {
4465     if (model)links.Copy ( &(model->links) );
4466   }
4467 
CopyLinkRs(PModel model)4468   void  Model::CopyLinkRs ( PModel model )  {
4469     if (model)  linkRs.Copy ( &(model->linkRs) );
4470   }
4471 
CopyCisPeps(PModel model)4472   void  Model::CopyCisPeps ( PModel model )  {
4473     if (model)  cisPeps.Copy ( &(model->cisPeps) );
4474   }
4475 
_copy(PModel model)4476   void  Model::_copy ( PModel model )  {
4477   //  modify both Model::_copy and Model::Copy methods simultaneously!
4478   int i;
4479 
4480     FreeMemory();
4481 
4482     if (model)  {
4483 
4484       serNum       = model->serNum;
4485       nChains      = model->nChains;
4486       nChainsAlloc = nChains;
4487       if (nChains>0)  {
4488         chain = new PChain[nChainsAlloc];
4489         for (i=0;i<nChains;i++)  {
4490           if (model->chain[i])  {
4491             chain[i] = newChain();
4492             chain[i]->SetModel ( this );
4493             chain[i]->_copy ( model->chain[i] );
4494           } else
4495             chain[i] = NULL;
4496         }
4497       }
4498 
4499       hetCompounds.Copy ( &(model->hetCompounds) );
4500       helices     .Copy ( &(model->helices)      );
4501       sheets      .Copy ( &(model->sheets)       );
4502       turns       .Copy ( &(model->turns)        );
4503       links       .Copy ( &(model->links)        );
4504       linkRs      .Copy ( &(model->linkRs)       );
4505       cisPeps     .Copy ( &(model->cisPeps)      );
4506 
4507     }
4508 
4509   }
4510 
4511 
_copy(PModel model,PPAtom atom,int & atom_index)4512   void  Model::_copy ( PModel model, PPAtom atom, int & atom_index ) {
4513   //  modify both Model::_copy and Model::Copy methods simultaneously!
4514   //
4515   //  _copy(PModel,PPAtom,int&) does copy atoms into array 'atom'
4516   // starting from position atom_index. 'atom' should be able to
4517   // accept all new atoms - no checks on the length of 'atom'
4518   // is being made. This function should not be used in applications.
4519   int i;
4520 
4521     FreeMemory();
4522 
4523     if (model)  {
4524 
4525       serNum       = model->serNum;
4526       nChains      = model->nChains;
4527       nChainsAlloc = nChains;
4528       if (nChains>0)  {
4529         chain = new PChain[nChainsAlloc];
4530         for (i=0;i<nChains;i++)  {
4531           if (model->chain[i])  {
4532             chain[i] = newChain();
4533             chain[i]->SetModel ( this );
4534             chain[i]->_copy ( model->chain[i],atom,atom_index );
4535           } else
4536             chain[i] = NULL;
4537         }
4538       }
4539 
4540       hetCompounds.Copy ( &(model->hetCompounds) );
4541       helices     .Copy ( &(model->helices)      );
4542       sheets      .Copy ( &(model->sheets)       );
4543       turns       .Copy ( &(model->turns)        );
4544       links       .Copy ( &(model->links)        );
4545       linkRs      .Copy ( &(model->linkRs)       );
4546 
4547     }
4548 
4549   }
4550 
4551 
AddChain(PChain chn)4552   int  Model::AddChain ( PChain chn )  {
4553   //  modify both Model::Copy methods simultaneously!
4554   //
4555   //  Copy(PModel,PPAtom,int&) copies atoms into array 'atom'
4556   // starting from position atom_index. 'atom' should be able to
4557   // accept all new atoms - no checks on the length of 'atom'
4558   // is being made. This function should not be used in applications.
4559   PModel  model1;
4560   int     i;
4561 
4562     for (i=0;i<nChains;i++)
4563       if (chain[i]==chn)  return -i;  // this chain is already there
4564 
4565     if (chn)  {
4566 
4567       // get space for new chain
4568       ExpandChainArray ( nChains );
4569 
4570       if (chn->GetCoordHierarchy())  {
4571         // The chain is associated with a coordinate hierarchy. It should
4572         // remain there, therefore we physically copy all its residues
4573         // and atoms.
4574         chain[nChains] = newChain();
4575         chain[nChains]->SetModel ( this );
4576         if (manager)  {
4577           // get space for new atoms
4578           manager->AddAtomArray ( chn->GetNumberOfAtoms(true) );
4579           chain[nChains]->_copy ( chn,manager->atom,manager->nAtoms );
4580         } else  {
4581           for (i=0;i<chn->nResidues;i++)
4582             chain[nChains]->AddResidue ( chn->residue[i] );
4583         }
4584       } else  {
4585         // The chain is not associated with a coordinate hierarchy. Such
4586         // unregistered objects are simply taken over, i.e. moved into
4587         // the new destination (model).
4588         chain[nChains] = chn;
4589         // remove chain from its model:
4590         model1 = chn->GetModel();
4591         if (model1)
4592           for (i=0;i<model1->nChains;i++)
4593             if (model1->chain[i]==chn)  {
4594               model1->chain[i] = NULL;
4595               break;
4596             }
4597         chain[nChains]->SetModel ( this );
4598         if (manager)
4599           chain[nChains]->CheckInAtoms();
4600       }
4601 
4602       nChains++;
4603 
4604     }
4605 
4606     return nChains;
4607 
4608   }
4609 
4610 
MoveChain(PChain & m_chain,PPAtom m_atom,PPAtom atom,int & atom_index,int chain_ext)4611   void  Model::MoveChain ( PChain & m_chain, PPAtom m_atom,
4612                             PPAtom  atom, int & atom_index,
4613                             int  chain_ext )  {
4614   //   MoveChain(..) adds chain m_chain on the top Chain array.
4615   // The pointer on chain is then set to NULL (m_chain=NULL).
4616   // If chain_ext is greater than 0, the moved chain will be
4617   // forcefully renamed; the new name is composed as the previous
4618   // one + underscore + chain_ext (e.g. A_1). If thus generated
4619   // name duplicates any of existing chain IDs, or if chain_ext
4620   // was set to 0 and there is a duplication of chain IDs, the
4621   // name is again modified as above, with the extension number
4622   // generated automatically (this may result in IDs like
4623   // A_1_10).
4624   //   m_atom must give pointer to the Atom array, from which
4625   // the atoms belonging to m_chain, are moved to Atom array
4626   // given by 'atom', starting from poisition 'atom_index'.
4627   // 'atom_index' is then automatically updated to the next
4628   // free position in 'atom'.
4629   //   Note1: the moved atoms will occupy a continuous range
4630   // in 'atom' array; no checks on whether the corresponding
4631   // cells are occupied or not, are performed.
4632   //   Note2: the 'atom_index' is numbered from 0 on, i.e.
4633   // it is equal to atom[atom_index]->index-1; atom[]->index
4634   // is assigned automatically.
4635   ChainID   chainID;
4636   int       i,j,k,Ok;
4637   PPChain   chain1;
4638   PResidue  crRes;
4639 
4640     if (!m_chain)  return;
4641 
4642     // modify chain ID with the extension given
4643     if (chain_ext>0)
4644           sprintf ( chainID,"%s_%i",m_chain->chainID,chain_ext );
4645     else  strcpy  ( chainID,m_chain->chainID );
4646 
4647     // Choose the chain ID. If a chain with such ID is
4648     // already present in the model, it will be assigned
4649     // a new ID 'ID_n', where 'ID' stands for the original
4650     // chain ID and 'n' is the minimum (integer) number
4651     // chosen such that 'name_n' represents a new chain ID
4652     // (in the model).
4653     k = 0;
4654     do {
4655       Ok = true;
4656       for (i=0;(i<nChains) && (Ok);i++)
4657         if (chain[i])
4658           if (!strcmp(chainID,chain[i]->chainID))  Ok = false;
4659       if (!Ok)  {
4660         k++;
4661         if (chain_ext>0)
4662               sprintf ( chainID,"%s_%i_%i",m_chain->chainID,
4663                                            chain_ext,k );
4664         else  sprintf ( chainID,"%s_%i",m_chain->chainID,k );
4665       }
4666     } while (!Ok);
4667 
4668     // add chain on the top of Chain array.
4669     strcpy ( m_chain->chainID,chainID );
4670     if (nChains>=nChainsAlloc)  {
4671       nChainsAlloc = nChains+10;
4672       chain1 = new PChain[nChainsAlloc];
4673       k = 0;
4674       for (i=0;i<nChains;i++)
4675         if (chain[i])  chain1[k++] = chain[i];
4676       for (i=k;i<nChainsAlloc;i++)
4677         chain1[i] = NULL;
4678       if (chain)  delete[] chain;
4679       chain = chain1;
4680     }
4681     chain[nChains] = m_chain;
4682     chain[nChains]->SetModel ( this );
4683     nChains++;
4684 
4685     // Move all atoms of the chain. While residues belong
4686     // atoms belong to the chain's manager class. Therefore
4687     // they should be moved from one manager to another.
4688     for (i=0;i<m_chain->nResidues;i++)  {
4689       crRes = m_chain->residue[i];
4690       if (crRes)
4691         for (j=0;j<crRes->nAtoms;j++)
4692           if (crRes->atom[j])  {
4693             k = crRes->atom[j]->index-1;
4694             atom[atom_index] = m_atom[k];
4695             atom[atom_index]->index = atom_index+1;
4696             atom_index++;
4697             m_atom[k] = NULL;  // moved!
4698           }
4699     }
4700 
4701     m_chain = NULL;  // moved!
4702 
4703   }
4704 
GetAIndexRange(int & i1,int & i2)4705   void Model::GetAIndexRange ( int & i1, int & i2 )  {
4706   PChain    chn;
4707   PResidue  res;
4708   int       ic,ir,ia;
4709     i1 = MaxInt4;
4710     i2 = MinInt4;
4711     for (ic=0;ic<nChains;ic++)  {
4712       chn = chain[ic];
4713       if (chn)  {
4714         for (ir=0;ir<chn->nResidues;ir++)  {
4715           res = chn->residue[ir];
4716           if (res)  {
4717             for (ia=0;ia<res->nAtoms;ia++)
4718               if (res->atom[ia])  {
4719                 if (res->atom[ia]->index<i1)  i1 = res->atom[ia]->index;
4720                 if (res->atom[ia]->index>i2)  i2 = res->atom[ia]->index;
4721               }
4722           }
4723         }
4724       }
4725     }
4726 
4727   }
4728 
4729 
MaskAtoms(PMask Mask)4730   void  Model::MaskAtoms ( PMask Mask )  {
4731   int i;
4732     for (i=0;i<nChains;i++)
4733       if (chain[i])  chain[i]->MaskAtoms ( Mask );
4734   }
4735 
MaskResidues(PMask Mask)4736   void  Model::MaskResidues ( PMask Mask )  {
4737   int i;
4738     for (i=0;i<nChains;i++)
4739       if (chain[i])  chain[i]->MaskResidues ( Mask );
4740   }
4741 
MaskChains(PMask Mask)4742   void  Model::MaskChains ( PMask Mask )  {
4743   int i;
4744     for (i=0;i<nChains;i++)
4745       if (chain[i])  chain[i]->SetMask ( Mask );
4746   }
4747 
UnmaskAtoms(PMask Mask)4748   void  Model::UnmaskAtoms ( PMask Mask )  {
4749   int i;
4750     for (i=0;i<nChains;i++)
4751       if (chain[i])  chain[i]->UnmaskAtoms ( Mask );
4752   }
4753 
UnmaskResidues(PMask Mask)4754   void  Model::UnmaskResidues ( PMask Mask )  {
4755   int i;
4756     for (i=0;i<nChains;i++)
4757       if (chain[i])  chain[i]->UnmaskResidues ( Mask );
4758   }
4759 
UnmaskChains(PMask Mask)4760   void  Model::UnmaskChains ( PMask Mask )  {
4761   int i;
4762     for (i=0;i<nChains;i++)
4763       if (chain[i])  chain[i]->RemoveMask ( Mask );
4764   }
4765 
4766 
4767   // ------ Getting Secondary Structure Elements
4768 
GetNumberOfHelices()4769   int  Model::GetNumberOfHelices()  {
4770     return  helices.Length();
4771   }
4772 
GetNumberOfSheets()4773   int  Model::GetNumberOfSheets()  {
4774     return  sheets.nSheets;
4775   }
4776 
GetHelix(int serialNum)4777   PHelix  Model::GetHelix ( int serialNum )  {
4778     return (PHelix)helices.GetContainerClass ( serialNum-1 );
4779   }
4780 
GetSheetID(int serialNum,SheetID sheetID)4781   void  Model::GetSheetID ( int serialNum, SheetID sheetID )  {
4782     if ((1<=serialNum) && (serialNum<=sheets.nSheets))  {
4783       if (sheets.sheet[serialNum-1])  {
4784         strcpy ( sheetID,sheets.sheet[serialNum-1]->sheetID );
4785         return;
4786       }
4787     }
4788     sheetID[0] = char(0);
4789   }
4790 
GetSheet(int serialNum)4791   PSheet Model::GetSheet ( int serialNum )  {
4792     if ((1<=serialNum) && (serialNum<=sheets.nSheets))
4793           return  sheets.sheet[serialNum-1];
4794     else  return  NULL;
4795   }
4796 
GetSheet(const SheetID sheetID)4797   PSheet Model::GetSheet ( const SheetID sheetID )  {
4798   int i;
4799     for (i=0;i<sheets.nSheets;i++)
4800       if (sheets.sheet[i])  {
4801         if (!strcmp(sheets.sheet[i]->sheetID,sheetID))
4802           return sheets.sheet[i];
4803       }
4804     return NULL;
4805   }
4806 
GetNumberOfStrands(int sheetSerNum)4807   int  Model::GetNumberOfStrands ( int sheetSerNum )  {
4808     if ((1<=sheetSerNum) && (sheetSerNum<=sheets.nSheets))  {
4809       if (sheets.sheet[sheetSerNum-1])
4810         return  sheets.sheet[sheetSerNum-1]->nStrands;
4811     }
4812     return 0;
4813   }
4814 
GetNumberOfStrands(const SheetID sheetID)4815   int  Model::GetNumberOfStrands ( const SheetID sheetID )  {
4816   int i;
4817     for (i=0;i<sheets.nSheets;i++)
4818       if (sheets.sheet[i])  {
4819         if (!strcmp(sheets.sheet[i]->sheetID,sheetID))
4820           return sheets.sheet[i]->nStrands;
4821       }
4822     return 0;
4823   }
4824 
GetStrand(int sheetSerNum,int strandSerNum)4825   PStrand Model::GetStrand ( int sheetSerNum, int strandSerNum )  {
4826   PSheet sheet;
4827     if ((1<=sheetSerNum) && (sheetSerNum<=sheets.nSheets))  {
4828       sheet = sheets.sheet[sheetSerNum-1];
4829       if (sheet)  {
4830         if ((1<=strandSerNum) && (strandSerNum<=sheet->nStrands))
4831         return  sheet->strand[strandSerNum-1];
4832       }
4833     }
4834     return NULL;
4835   }
4836 
GetStrand(const SheetID sheetID,int strandSerNum)4837   PStrand Model::GetStrand ( const SheetID sheetID,
4838                              int strandSerNum )  {
4839   int    i;
4840   PSheet sheet;
4841     for (i=0;i<sheets.nSheets;i++)
4842       if (sheets.sheet[i])  {
4843         if (!strcmp(sheets.sheet[i]->sheetID,sheetID))  {
4844           sheet = sheets.sheet[i];
4845           if (sheet)  {
4846             if ((1<=strandSerNum) && (strandSerNum<=sheet->nStrands))
4847               return  sheet->strand[strandSerNum-1];
4848           }
4849         }
4850       }
4851     return NULL;
4852   }
4853 
RemoveSecStructure()4854   void  Model::RemoveSecStructure()  {
4855     helices.FreeContainer();
4856     sheets .FreeMemory   ();
4857     turns  .FreeContainer();
4858   }
4859 
RemoveHetInfo()4860   void  Model::RemoveHetInfo()  {
4861     hetCompounds.FreeMemory();
4862   }
4863 
4864 
GetNumberOfLinks()4865   int  Model::GetNumberOfLinks()  {
4866     return  links.Length();
4867   }
4868 
GetLink(int serialNum)4869   PLink  Model::GetLink ( int serialNum )  {
4870     return (PLink)links.GetContainerClass ( serialNum-1 );
4871   }
4872 
RemoveLinks()4873   void  Model::RemoveLinks()  {
4874     links.FreeContainer();
4875   }
4876 
AddLink(PLink link)4877   void  Model::AddLink ( PLink link )  {
4878     links.AddData ( link );
4879   }
4880 
4881 
GetNumberOfLinkRs()4882   int  Model::GetNumberOfLinkRs()  {
4883     return  linkRs.Length();
4884   }
4885 
GetLinkR(int serialNum)4886   PLinkR  Model::GetLinkR ( int serialNum )  {
4887     return (PLinkR)linkRs.GetContainerClass ( serialNum-1 );
4888   }
4889 
RemoveLinkRs()4890   void  Model::RemoveLinkRs()  {
4891     linkRs.FreeContainer();
4892   }
4893 
AddLinkR(PLinkR linkR)4894   void  Model::AddLinkR ( PLinkR linkR )  {
4895     linkRs.AddData ( linkR );
4896   }
4897 
4898 
4899 
GetNumberOfCisPeps()4900   int  Model::GetNumberOfCisPeps()  {
4901     return  cisPeps.Length();
4902   }
4903 
GetCisPep(int CisPepNum)4904   PCisPep Model::GetCisPep ( int CisPepNum )  {
4905     return (PCisPep)cisPeps.GetContainerClass ( CisPepNum-1 );
4906   }
4907 
RemoveCisPeps()4908   void  Model::RemoveCisPeps()  {
4909     cisPeps.FreeContainer();
4910   }
4911 
AddCisPep(PCisPep cisPep)4912   void  Model::AddCisPep ( PCisPep cisPep )  {
4913     cisPeps.AddData ( cisPep );
4914   }
4915 
4916 
ApplyTransform(mat44 & TMatrix)4917   void  Model::ApplyTransform ( mat44 & TMatrix )  {
4918   // transforms all coordinates by multiplying with matrix TMatrix
4919   int i;
4920     for (i=0;i<nChains;i++)
4921       if (chain[i])  chain[i]->ApplyTransform ( TMatrix );
4922   }
4923 
isInSelection(int selHnd)4924   bool Model::isInSelection ( int selHnd )  {
4925   PMask  mask;
4926     if (manager)  {
4927       mask = PRoot(manager)->GetSelMask ( selHnd );
4928       if (mask)  return CheckMask ( mask );
4929     }
4930     return false;
4931   }
4932 
4933 
4934 
4935   // -------  user-defined data handlers
4936 
PutUDData(int UDDhandle,int iudd)4937   int  Model::PutUDData ( int UDDhandle, int iudd )  {
4938     if (UDDhandle & UDRF_MODEL)
4939           return  UDData::putUDData ( UDDhandle,iudd );
4940     else  return  UDDATA_WrongUDRType;
4941   }
4942 
PutUDData(int UDDhandle,realtype rudd)4943   int  Model::PutUDData ( int UDDhandle, realtype rudd )  {
4944     if (UDDhandle & UDRF_MODEL)
4945           return  UDData::putUDData ( UDDhandle,rudd );
4946     else  return  UDDATA_WrongUDRType;
4947   }
4948 
PutUDData(int UDDhandle,cpstr sudd)4949   int  Model::PutUDData ( int UDDhandle, cpstr sudd )  {
4950     if (UDDhandle & UDRF_MODEL)
4951           return  UDData::putUDData ( UDDhandle,sudd );
4952     else  return  UDDATA_WrongUDRType;
4953   }
4954 
GetUDData(int UDDhandle,int & iudd)4955   int  Model::GetUDData ( int UDDhandle, int & iudd )  {
4956     if (UDDhandle & UDRF_MODEL)
4957           return  UDData::getUDData ( UDDhandle,iudd );
4958     else  return  UDDATA_WrongUDRType;
4959   }
4960 
GetUDData(int UDDhandle,realtype & rudd)4961   int  Model::GetUDData ( int UDDhandle, realtype & rudd )  {
4962     if (UDDhandle & UDRF_MODEL)
4963           return  UDData::getUDData ( UDDhandle,rudd );
4964     else  return  UDDATA_WrongUDRType;
4965   }
4966 
GetUDData(int UDDhandle,pstr sudd,int maxLen)4967   int  Model::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
4968     if (UDDhandle & UDRF_MODEL)
4969           return  UDData::getUDData ( UDDhandle,sudd,maxLen );
4970     else  return  UDDATA_WrongUDRType;
4971   }
4972 
GetUDData(int UDDhandle,pstr & sudd)4973   int  Model::GetUDData ( int UDDhandle, pstr & sudd )  {
4974     if (UDDhandle & UDRF_MODEL)
4975           return  UDData::getUDData ( UDDhandle,sudd );
4976     else  return  UDDATA_WrongUDRType;
4977   }
4978 
4979 
4980   // -------  calculation of Secondary Structure
4981 
4982 
CalcSecStructure(bool flagBulge,int aminoSelHnd)4983   int Model::CalcSecStructure ( bool flagBulge, int aminoSelHnd )  {
4984   // This function is contributed by Liz Potterton, University of York
4985   //------------------------------------------------------------------
4986   // Define a secondary structure type of each amino acid residue in the
4987   // structure.
4988   // Procedure:
4989   // Find all amino acids
4990   // Find all pairs of amino acids which have inter-Ca distance  < 10.0A
4991   // Test for hydrogen bonds between the main chain N and O of the close
4992   // residues and store the information in the hbonds matrix
4993   // Analyse the info in hbonds matrix to assign secondary structure to
4994   // secstr vector
4995   PPResidue Res;
4996   PPAtom    Ca;
4997   PChain    chn;
4998   PContact  contact;
4999   imatrix   hbonds;
5000   PPAtom *  hbond_atoms;
5001   int       nres, ncontacts;
5002   int       ir1,ir2, irdif;
5003   int       i,j,k,l;
5004 
5005     // 1a. Get protein residues from selection handle
5006 
5007     if (aminoSelHnd>=0) {
5008 
5009       manager->GetSelIndex(aminoSelHnd,Res,nres);
5010       if (nres<=0)  return  SSERC_noResidues;
5011 
5012     } else {
5013 
5014       //  1b. Get all protein residues
5015 
5016       nres = 0;
5017       for (i=0;i<nChains;i++)
5018         if (chain[i])
5019           nres += chain[i]->nResidues;
5020 
5021       if (nres<=0)  return  SSERC_noResidues;
5022 
5023       Res  = new PResidue[nres];
5024       nres = 0;
5025       for (i=0;i<nChains;i++)  {
5026         chn = chain[i];
5027         if (chn)  {
5028           k = chn->nResidues;
5029           for (j=0;j<k;j++)
5030             Res[nres++] = chn->residue[j];
5031         }
5032       }
5033 
5034 
5035       if (nres<=0)  {
5036         delete[] Res;
5037         return   SSERC_noResidues;
5038       }
5039 
5040    }
5041 
5042     //  2. Get C-alphas of all aminoacids
5043 
5044     Ca = new PAtom[nres];
5045     k  = 0;
5046     for (i=0;i<nres;i++)
5047       if (Res[i])  {
5048         if (aminoSelHnd>=0 || Res[i]->isAminoacid())  {
5049           Ca[i] = Res[i]->GetAtom("CA", " C", "*");
5050           k++;
5051         } else
5052           Ca[i] = NULL;
5053         Res[i]->SSE = SSE_None;
5054       } else
5055         Ca[i] = NULL;
5056 
5057     if (k<=0)  {
5058       delete[] Res;
5059       delete[] Ca;
5060       return   SSERC_noAminoacids;
5061     }
5062 
5063 
5064     //  3. Find all close Calphas - i.e. find the contacts between
5065     //     the two equivalent sets of Ca atoms
5066 
5067     contact   = NULL;
5068     ncontacts = 0;
5069     manager->SeekContacts ( Ca,nres, Ca,nres, 2.0,10.0, 2,
5070                             contact,ncontacts,0 );
5071     manager->RemoveBricks();
5072     if (ncontacts<=0)  {
5073       delete[] Res;
5074       delete[] Ca;
5075       if (contact)  delete[] contact;
5076       return  SSERC_noSSE;
5077     }
5078 
5079 
5080     //  4. Get and initialize memory for analysing the SSE
5081 
5082     GetMatrixMemory ( hbonds,nres,3,0,0 );
5083     hbond_atoms = new PPAtom[nres];
5084     for (i=0;i<nres;i++)  {
5085       hbond_atoms[i] = new PAtom[6];
5086       for (j=0;j<6;j++) hbond_atoms[i][j] = NULL;
5087       for (j=0;j<3;j++) hbonds     [i][j] = 0;
5088     }
5089 
5090 
5091     //  5.  Loop over all close (in space) residues - excluding those
5092     //      that are close in sequence
5093 
5094     for (i=0;i<ncontacts;i++)  {
5095       ir1   = contact[i].id2;
5096       ir2   = contact[i].id1;
5097       irdif = ir1 - ir2;
5098       if (irdif>2)  {
5099         //  test if there is donor Hbond from residue ir1
5100         if (Res[ir1]->isMainchainHBond(Res[ir2]))  {
5101           k = 0;
5102           while ((hbonds[ir1][k]!=0) && (k<2))  k++;
5103           hbonds     [ir1][k]   = -irdif;
5104           hbond_atoms[ir1][k]   = Res[ir1]->GetAtom ( "N" );
5105           hbond_atoms[ir1][k+3] = Res[ir2]->GetAtom ( "O" );
5106         }
5107         //  test if there is donor Hbond from residue ir2
5108         if (Res[ir2]->isMainchainHBond(Res[ir1]))  {
5109           k = 0;
5110           while ((hbonds[ir2][k]!=0) && (k<2))  k++;
5111           hbonds     [ir2][k]   = irdif;
5112           hbond_atoms[ir2][k]   = Res[ir2]->GetAtom ( "N" );
5113           hbond_atoms[ir2][k+3] = Res[ir1]->GetAtom ( "O" );
5114         }
5115       }
5116     }
5117 
5118     //  6. Assign the turns - if there is bifurcated bond then the 4-turn
5119     //     takes precedence - read the paper to make sense of this
5120 
5121     for (i=0;i<nres;i++)  {
5122       k = 0;
5123       while ((k<=2) && (hbonds[i][k]!=0))  {
5124         if (hbonds[i][k]==-5)  {
5125           Res[i-1]->SSE = SSE_5Turn;
5126           Res[i-2]->SSE = SSE_5Turn;
5127           Res[i-3]->SSE = SSE_5Turn;
5128           Res[i-4]->SSE = SSE_5Turn;
5129         }
5130         if (hbonds[i][k]==-3)  {
5131           Res[i-1]->SSE = SSE_3Turn;
5132           Res[i-2]->SSE = SSE_3Turn;
5133         }
5134         k++;
5135       }
5136     }
5137     for (i=0;i<nres;i++)  {
5138       k = 0;
5139       while ((k<=2) && (hbonds[i][k]!=0))  {
5140         if (hbonds[i][k]==-4)  {
5141           Res[i-1]->SSE = SSE_4Turn;
5142           Res[i-2]->SSE = SSE_4Turn;
5143           Res[i-3]->SSE = SSE_4Turn;
5144         }
5145         k++;
5146       }
5147     }
5148 
5149 
5150     //  7. Look for consecutive 4-turns which make alpha helix
5151 
5152     for (i=1;i<nres-3;i++) {
5153       if (((Res[i  ]->SSE==SSE_Helix) || (Res[i  ]->SSE==SSE_4Turn)) &&
5154           ((Res[i+1]->SSE==SSE_Helix) || (Res[i+1]->SSE==SSE_4Turn)) &&
5155           ((Res[i+2]->SSE==SSE_Helix) || (Res[i+2]->SSE==SSE_4Turn)) &&
5156           ((Res[i+3]->SSE==SSE_Helix) || (Res[i+3]->SSE==SSE_4Turn)))
5157         for (j=i;j<=i+3;j++)  Res[j]->SSE = SSE_Helix;
5158     }
5159 
5160     for (i=0;i<nres;i++)  {
5161 
5162       k = 0;
5163       while ((k<=2) && (hbonds[i][k]!=0))  {
5164 
5165         irdif = hbonds[i][k];
5166         // Test for 'close' hbond
5167         j = i + irdif;
5168         l = 0;
5169         while ((l<=2) && (hbonds[j][l]!=0))  {
5170           // Antiparallel strands
5171           if (hbonds[j][l]==-irdif)  {
5172             Res[i]->SSE = SSE_Strand;
5173             Res[j]->SSE = SSE_Strand;
5174           }
5175           // Parallel strand
5176           if (hbonds[j][l]==-irdif-2)  {
5177             Res[i-1]->SSE = SSE_Strand;
5178             Res[j  ]->SSE = SSE_Strand;
5179           }
5180           // Parallel beta bulge
5181           if (hbonds[j][l]==-irdif-3)  {
5182             if (flagBulge) {
5183               if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Bulge;
5184               if (Res[i-2]->SSE==SSE_None)  Res[i-2]->SSE = SSE_Bulge;
5185               if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Bulge;
5186             } else  {
5187               if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Strand;
5188               if (Res[i-2]->SSE==SSE_None)  Res[i-2]->SSE = SSE_Strand;
5189               if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Strand;
5190             }
5191           }
5192           l++;
5193         }
5194         // Test for 'wide' hbond
5195         j = i + hbonds[i][k] + 2;
5196         if (j<nres)  {
5197           l = 0;
5198           while ((l<=2) && (hbonds[j][l]!=0))  {
5199             // Antiaprallel strands
5200             if (hbonds[j][l]==-irdif-4)  {
5201               Res[i-1]->SSE = SSE_Strand;
5202               Res[j-1]->SSE = SSE_Strand;
5203             }
5204             // Parallel strands
5205             if (hbonds[j][l]==-irdif-2)  {
5206               Res[i  ]->SSE = SSE_Strand;
5207           Res[j-1]->SSE = SSE_Strand;
5208             }
5209             l++;
5210           }
5211         }
5212 
5213         // test for anti-parallel B-bulge between 'close' hbonds
5214         j = i + hbonds[i][k] - 1;
5215         if (j>=0)  {
5216           l = 0;
5217           while ((l<=2) && (hbonds[j][l]!=0))  {
5218             if (hbonds[j][l]==-irdif+1)  {
5219               if (flagBulge)  {
5220             if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Bulge;
5221             if (Res[j+1]->SSE==SSE_None)  Res[j+1]->SSE = SSE_Bulge;
5222             if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Bulge;
5223               } else  {
5224                 if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Strand;
5225                 if (Res[j+1]->SSE==SSE_None)  Res[j+1]->SSE = SSE_Strand;
5226                 if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Strand;
5227               }
5228             }
5229             l++;
5230           }
5231         }
5232 
5233         // test for anti-parallel B-bulge between 'wide' hbonds
5234         j = i + hbonds[i][k] + 3;
5235         if (j<nres)  {
5236           l = 0;
5237           while ((l<=2) && (hbonds[j][l]!=0))  {
5238             if ((hbonds[j][l]==-irdif+5) && (i>0))  {
5239               if (flagBulge)  {
5240                 if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Bulge;
5241                 if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Bulge;
5242                 if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Bulge;
5243               } else  {
5244                 if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Strand;
5245                 if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Strand;
5246                 if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Strand;
5247               }
5248             } else if (hbonds[j][l]==-irdif-3)  {
5249               // and bulge in parallel strand
5250           if (flagBulge)  {
5251                 if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Bulge;
5252                 if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Bulge;
5253                 if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Bulge;
5254               }
5255               else {
5256                 if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Strand;
5257                 if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Strand;
5258                 if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Strand;
5259               }
5260             }
5261             l++;
5262           }
5263         }
5264         k++;
5265 
5266       } // Finish looping over Hbonds for residue (k loop)
5267 
5268     }  // Finish looping over residues ( i loop)
5269 
5270 
5271     //  8. Free memory
5272 
5273     if (hbond_atoms)  {
5274       for (i=0;i<nres;i++)
5275         if (hbond_atoms[i])  delete[] hbond_atoms[i];
5276       delete[] hbond_atoms;
5277     }
5278     FreeMatrixMemory ( hbonds,nres,0,0 );
5279     if (contact) delete[] contact;
5280     if (Res && aminoSelHnd<0) delete[] Res;
5281     if (Ca)      delete[] Ca;
5282 
5283     return  SSERC_Ok;
5284 
5285   }
5286 
5287 
5288   // -------  streaming
5289 
write(io::RFile f)5290   void  Model::write ( io::RFile f )  {
5291   int  i,k;
5292   byte Version=4;
5293   bool compactBinary = false;
5294 
5295     PManager M = GetCoordHierarchy();
5296     if (M)
5297       compactBinary = M->isCompactBinary();
5298 
5299     f.WriteByte ( &Version       );
5300     f.WriteBool ( &compactBinary );
5301 
5302     f.WriteInt ( &serNum  );
5303     f.WriteInt ( &nChains );
5304 
5305     for (i=0;i<nChains;i++)  {
5306       if (chain[i])  k = 1;
5307                else  k = 0;
5308       f.WriteInt ( &k );
5309       if (chain[i]) chain[i]->write ( f );
5310     }
5311 
5312     if (!compactBinary)  {
5313 
5314       ProModel::write ( f );
5315 
5316       hetCompounds.write ( f );
5317       helices     .write ( f );
5318       sheets      .write ( f );
5319       turns       .write ( f );
5320       links       .write ( f );
5321       linkRs      .write ( f );
5322 
5323     }
5324 
5325   }
5326 
read(io::RFile f)5327   void  Model::read ( io::RFile f )  {
5328   int  i,k;
5329   byte Version;
5330   bool compactBinary;
5331 
5332     FreeMemory();
5333 
5334     f.ReadByte ( &Version       );
5335     f.ReadBool ( &compactBinary );
5336 
5337     f.ReadInt ( &serNum  );
5338     f.ReadInt ( &nChains );
5339     nChainsAlloc = nChains;
5340     if (nChains>0)  {
5341       chain = new PChain[nChainsAlloc];
5342       for (i=0;i<nChains;i++)  {
5343         f.ReadInt ( &k );
5344         if (k)  {
5345           chain[i] = newChain();
5346           chain[i]->SetModel ( this );
5347           chain[i]->read ( f );
5348         }
5349       }
5350     }
5351 
5352     if (!compactBinary)  {
5353 
5354       ProModel::read ( f );
5355 
5356       hetCompounds.read ( f );
5357       helices     .read ( f );
5358       sheets      .read ( f );
5359       turns       .read ( f );
5360       links       .read ( f );
5361       linkRs      .read ( f );
5362 
5363     }
5364 
5365   }
5366 
5367   MakeFactoryFunctions(Model)
5368 
5369 }  // namespace mmdb
5370