forked from Amber-MD/cpptraj
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathExec_Build.cpp
More file actions
1769 lines (1689 loc) · 73.6 KB
/
Copy pathExec_Build.cpp
File metadata and controls
1769 lines (1689 loc) · 73.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "Exec_Build.h"
#include "Action_FixAtomOrder.h"
#include "AssociatedData_Connect.h"
#include "CpptrajStdio.h"
#include "DataIO_Coords.h"
#include "DataSet_LeapOpts.h"
#include "DataSet_Parameters.h" // For casting DataSet_Parameters to ParameterSet
#include "ParmFile.h"
#include "StringRoutines.h" // integerToString
#include "Trajout_Single.h"
#include "Parm/AssignParams.h"
#include "Parm/LJ1264_Params.h"
#include "Structure/AddIons.h"
#include "Structure/Builder.h"
#include "Structure/Creator.h"
#include "Structure/Disulfide.h"
#include "Structure/HisProt.h"
#include "Structure/PdbCleaner.h"
#include "Structure/ResStatArray.h"
#include "Structure/Solvate.h"
#include "Structure/SugarBuilder.h"
#include "Structure/Sugar.h"
#include "StructureCheck.h"
#include <set> // For warning about missing residue templates
#include <cmath> // fabs
/** CONSTRUCTOR */
Exec_Build::Exec_Build() :
Exec(GENERAL),
debug_(0),
check_box_natom_(5000), // TODO make user specifiable
check_structure_(true),
keepMissingSourceAtoms_(false),
requireAllInputAtoms_(false),
doHisDetect_(true),
doDisulfide_(true),
doSugar_(true),
fixAtomOrder_(true),
outCrdPtr_(0)
{}
void Exec_Build::printErrMsgWebsites() {
mprinterr("Error: See https://ambermd.org/AmberModels.php for more information\n"
"Error: or email the Amber mailing list http://lists.ambermd.org/mailman/listinfo/amber\n");
}
/** Search in array of atom bonding pairs for given bonding pair. */
bool Exec_Build::hasBondingPair(IParray const& bpairs, Ipair const& bpair) {
for (IParray::const_iterator it = bpairs.begin(); it != bpairs.end(); ++it)
if (*it == bpair) return true;
return false;
}
/** \return True if target residue is in array of residue connections. */
bool Exec_Build::resIsConnected(Iarray const& resConnections, int tgtRes) {
for (Iarray::const_iterator it = resConnections.begin(); it != resConnections.end(); ++it)
if (*it == tgtRes) return true;
return false;
}
/** Use given templates to construct a final molecule. */
int Exec_Build::FillAtomsWithTemplates(Topology& topOut, Frame& frameOut,
Topology const& topIn, Frame const& frameIn,
Cpptraj::Structure::Creator const& creator,
std::vector<BondType> const& topInBonds)
{
// Array of head/tail connect atoms for each residue
Iarray resHeadAtoms;
Iarray resTailAtoms;
std::vector<Cpptraj::Structure::TerminalType> ResTermTypes;
resHeadAtoms.reserve( topIn.Nres() );
resTailAtoms.reserve( topIn.Nres() );
ResTermTypes.reserve( topIn.Nres() );
// Array of templates for each residue
std::vector<DataSet_Coords*> ResTemplates;
ResTemplates.reserve( topIn.Nres() );
t_fill_template_.Start();
// Initial loop to try to match residues to templates
int newNatom = 0;
unsigned int n_no_template_found = 0;
std::set<NameType> missing_templates;
for (int ires = 0; ires != topIn.Nres(); ires++)
{
Residue const& currentRes = topIn.Res(ires);
if (debug_ > 0)
mprintf("DEBUG: ---------- Processing Residue %s ---------- \n", topIn.TruncResNameNum(ires).c_str());
int pres = ires - 1;
int nres = ires + 1;
// Determine if this is a terminal residue
Cpptraj::Structure::TerminalType resTermType;
if (currentRes.IsTerminal()) {
resTermType = Cpptraj::Structure::END_TERMINAL;
if (debug_ > 0)
mprintf("DEBUG: %s End terminal due to TERMINAL status.\n", topIn.TruncResNameNum(ires).c_str());
} else if (ires == 0 && topIn.Nres() > 1) {
resTermType = Cpptraj::Structure::BEG_TERMINAL;
if (debug_ > 0)
mprintf("DEBUG: %s Begin terminal due to first residue.\n", topIn.TruncResNameNum(ires).c_str());
} else if (pres > -1 && topIn.Res(pres).IsTerminal()) {
resTermType = Cpptraj::Structure::BEG_TERMINAL;
if (debug_ > 0)
mprintf("DEBUG: %s Begin terminal due to previous residue TERMINAL status.\n", topIn.TruncResNameNum(ires).c_str());
} else if (ires > 0 && ResTermTypes.back() == Cpptraj::Structure::END_TERMINAL) {
resTermType = Cpptraj::Structure::BEG_TERMINAL;
if (debug_ > 0)
mprintf("DEBUG: %s Begin terminal due to previous residue BEGIN status.\n", topIn.TruncResNameNum(ires).c_str());
} else if (nres < topIn.Nres() && (topIn.Res(nres).ChainID() != currentRes.ChainID())// ||
// (topIn.Res(nres).OriginalResNum() == currentRes.OriginalResNum() &&
// topIn.Res(nres).Icode() != currentRes.Icode()
// )
// )
)
{
resTermType = Cpptraj::Structure::END_TERMINAL;
if (debug_ > 0)
mprintf("DEBUG: %s End terminal due to chain ID.\n", topIn.TruncResNameNum(ires).c_str());
} else if (nres == topIn.Nres()) {
resTermType = Cpptraj::Structure::END_TERMINAL;
if (debug_ > 0)
mprintf("DEBUG: %s End terminal due to last residue.\n", topIn.TruncResNameNum(ires).c_str());
} else {
resTermType = Cpptraj::Structure::NON_TERMINAL;
}
if (debug_ > 0)
mprintf("DEBUG: Residue type: %s terminal (IsTerminal=%i)\n", Cpptraj::Structure::terminalStr(resTermType), (int)currentRes.IsTerminal());
ResTermTypes.push_back( resTermType );
// Identify a template based on the residue name.
DataSet_Coords* resTemplate = creator.IdTemplateFromResname(currentRes.Name(), resTermType);
if (resTemplate == 0) {
// Residue has no template.
n_no_template_found++;
mprintf("Warning: No template found for residue %s\n", topIn.TruncResNameOnumId(ires).c_str());
missing_templates.insert( currentRes.Name() );
newNatom += currentRes.NumAtoms();
// Head and tail atoms are blank
resHeadAtoms.push_back( -1 );
resTailAtoms.push_back( -1 );
} else {
// Residue has a template.
if (debug_ > 0)
mprintf("\tTemplate %s being used for residue %s\n",
resTemplate->legend(), topIn.TruncResNameOnumId(ires).c_str());
int nTgtAtomsMissing = 0;
if (keepMissingSourceAtoms_)
nTgtAtomsMissing = creator.CountAtomsMissingFromTemplate( topIn, ires, resTemplate );
// Save the head and tail atoms
AssociatedData* ad = resTemplate->GetAssociatedData(AssociatedData::CONNECT);
if (ad == 0) {
if (debug_ > 0)
mprintf("DEBUG: Unit '%s' does not have CONNECT data.\n", resTemplate->legend());
resHeadAtoms.push_back( -1 );
resTailAtoms.push_back( -1 );
} else {
AssociatedData_Connect const& CONN = static_cast<AssociatedData_Connect const&>( *ad );
if (CONN.NconnectAtoms() < 2) {
mprinterr("Error: Not enough connect atoms in unit '%s'\n", resTemplate->legend());
return 1;
}
if (CONN.Connect()[0] > -1)
resHeadAtoms.push_back( CONN.Connect()[0] + newNatom );
else
resHeadAtoms.push_back( -1 );
if (CONN.Connect()[1] > -1)
resTailAtoms.push_back( CONN.Connect()[1] + newNatom );
else
resTailAtoms.push_back( -1 );
}
// Update # of atoms
newNatom += resTemplate->Top().Natom() + nTgtAtomsMissing;
}
ResTemplates.push_back( resTemplate );
}
mprintf("\tFinal structure should have %i atoms.\n", newNatom);
if (n_no_template_found > 0) {
mprintf("Warning: No template was found for %u residues.\n", n_no_template_found);
mprintf("Warning: Residue names:");
for (std::set<NameType>::const_iterator rit = missing_templates.begin();
rit != missing_templates.end(); ++rit)
mprintf(" %s", *(*rit));
mprintf("\n");
mprintf("Warning: This may indicate that you have not loaded a library file\n"
"Warning: or have not loaded the correct force field.\n");
}
frameOut.SetupFrame( newNatom );
// Clear frame so that AddXYZ can be used
frameOut.ClearAtoms();
// -----------------------------------
// hasPosition - for each atom in topOut, status on whether atom in frameOut needs building
Cpptraj::Structure::Builder::Barray hasPosition;
hasPosition.reserve( newNatom );
// Hold atom offsets needed when building residues
Iarray AtomOffsets;
AtomOffsets.reserve( topIn.Nres() );
// For existing inter-residue bonding, use residue # and atom name since
// atom numbering may change if atoms are added from templates.
// TODO make this a class var so disulfide/sugar prep can use it.
typedef std::pair<int,NameType> ResAtPair;
typedef std::vector<ResAtPair> ResAtArray;
ResAtArray detectedInterResBonds;
// Hold template atom names corressponding to source atom names.
typedef std::vector<NameType> NameArray;
NameArray SourceAtomNames;
SourceAtomNames.resize( topIn.Natom() );
// Loop for setting up atoms in the topology from residues or residue templates.
int nAtomsNotInTemplates = 0;
int nRefAtomsMissing = 0;
int nAtomsMissingTypes = 0;
bool has_bfac = !topIn.Bfactor().empty();
bool has_occ = !topIn.Occupancy().empty();
bool has_pdbn = !topIn.PdbSerialNum().empty();
if (debug_ > 0)
mprintf("DEBUG: Input top has_bfac=%i has_occ=%i has_pdbn=%i\n",
(int)has_bfac, (int)has_occ, (int)has_pdbn);
for (int ires = 0; ires != topIn.Nres(); ires++)
{
if (debug_ > 0)
mprintf("\tAdding atoms for residue %s\n", topIn.TruncResNameOnumId(ires).c_str());
int atomOffset = topOut.Natom();
//mprintf("DEBUG: atom offset is %i\n", atomOffset);
DataSet_Coords* resTemplate = ResTemplates[ires];
IParray intraResBonds;
if (resTemplate == 0) {
// ----- No template. Just add the atoms. ------------
Residue const& currentRes = topIn.Res(ires);
AtomOffsets.push_back( -1 );
for (int itgt = currentRes.FirstAtom(); itgt != currentRes.LastAtom(); ++itgt)
{
// Track intra-residue bonds
Atom sourceAtom = topIn[itgt];
if (!sourceAtom.HasType())
nAtomsMissingTypes++;
SourceAtomNames[itgt] = sourceAtom.Name();
int at0 = itgt - currentRes.FirstAtom() + atomOffset;
for (Atom::bond_iterator bat = sourceAtom.bondbegin(); bat != sourceAtom.bondend(); ++bat) {
if ( topIn[*bat].ResNum() == ires ) {
// Intra-residue
int at1 = *bat - currentRes.FirstAtom() + atomOffset;
if (at1 > at0) {
//mprintf("Will add bond between %i and %i (original %i and %i)\n", at0+1, at1+1, itgt+1, *bat + 1);
intraResBonds.push_back( Ipair(at0, at1) );
}
} else {
// Inter-residue. Only record if bonding to a previous residue.
if (topIn[*bat].ResNum() < ires) {
detectedInterResBonds.push_back( ResAtPair(ires, sourceAtom.Name()) );
detectedInterResBonds.push_back( ResAtPair(topIn[*bat].ResNum(), topIn[*bat].Name()) );
}
}
}
sourceAtom.ClearBonds(); // FIXME AddTopAtom should clear bonds
topOut.AddTopAtom( sourceAtom, currentRes );
frameOut.AddVec3( Vec3(frameIn.XYZ(itgt)) );
hasPosition.push_back( true );
if (has_bfac)
topOut.AddBfactor( topIn.Bfactor()[itgt] );
if (has_occ)
topOut.AddOccupancy( topIn.Occupancy()[itgt] );
if (has_pdbn)
topOut.AddPdbSerialNum( topIn.PdbSerialNum()[itgt] );
}
} else {
// ----- A template exists for this residue. ---------
Residue currentRes = topIn.Res(ires);
// Use template residue name.
// To match LEaP behavior, if the template name is > 3 characters,
// truncate to the last 3 characters.
NameType const& templateResName = resTemplate->Top().Res(0).Name();
if (templateResName.len() < 4)
currentRes.SetName( templateResName );
else
currentRes.SetName( NameType( (*templateResName) + ( templateResName.len() - 3) ) );
// Map source atoms to template atoms.
int nTgtAtomsMissing = 0;
std::vector<int> map = creator.MapAtomsToTemplate( topIn, ires, resTemplate, SourceAtomNames, nTgtAtomsMissing );
if (debug_ > 1) {
mprintf("\t Atom map:\n");
// DEBUG - print map
for (int iref = 0; iref != resTemplate->Top().Natom(); iref++) {
mprintf("\t\t%6i %6s =>", iref+1, *(resTemplate->Top()[iref].Name()));
if (map[iref] == -1)
mprintf(" No match\n");
else
mprintf(" %6i %6s\n", map[iref]+1, *(topIn[map[iref]].Name()));
}
}
// Map template atoms back to source atoms.
std::vector<int> pdb(currentRes.NumAtoms(), -1);
for (int iref = 0; iref != resTemplate->Top().Natom(); iref++) {
if (map[iref] != -1)
pdb[map[iref]-currentRes.FirstAtom()] = iref;
}
if (debug_ > 1) {
mprintf("\t PDB atom map:\n");
for (int itgt = 0; itgt != currentRes.NumAtoms(); itgt++) {
mprintf("\t\t%6i %6s =>", itgt+1, *(topIn[itgt+currentRes.FirstAtom()].Name()));
if (pdb[itgt] == -1)
mprintf(" Not in template\n");
else
mprintf(" %6i %6s\n", pdb[itgt]+1, *(resTemplate->Top()[pdb[itgt]].Name()));
}
}
bool atomsNeedBuilding = false;
// Loop over template atoms
for (int iref = 0; iref != resTemplate->Top().Natom(); iref++) {
// Track intra-residue bonds from the template.
Atom templateAtom = resTemplate->Top()[iref];
int at0 = iref + atomOffset;
for (Atom::bond_iterator bat = templateAtom.bondbegin(); bat != templateAtom.bondend(); ++bat) {
int at1 = *bat + atomOffset;
if (at1 > at0) {
//mprintf("Will add bond between %i and %i (original %i and %i)\n", at0+1, at1+1, iref+1, *bat + 1);
intraResBonds.push_back( Ipair(at0, at1) );
}
}
templateAtom.ClearBonds(); // FIXME AddTopAtom should clear bonds
//mprintf("DEBUG: Adding template %i atom %6s (elt %2s) Res %4s\n", topOut.Natom()+1, templateAtom.c_str(), templateAtom.ElementName(), currentRes.c_str());
topOut.AddTopAtom( templateAtom, currentRes );
if (map[iref] == -1) {
// Template atom not in input structure.
frameOut.AddVec3( Vec3(0.0) );
hasPosition.push_back( false );
nRefAtomsMissing++;
atomsNeedBuilding = true;
if (has_bfac) topOut.AddBfactor(0.0);
if (has_occ) topOut.AddOccupancy(0.0);
if (has_pdbn) topOut.AddPdbSerialNum(0);
} else {
// Template atom was in input structure.
int itgt = map[iref];
frameOut.AddVec3( Vec3(frameIn.XYZ(itgt)) );
hasPosition.push_back( true );
if (has_bfac) topOut.AddBfactor( topIn.Bfactor()[itgt] );
if (has_occ) topOut.AddOccupancy( topIn.Occupancy()[itgt] );
if (has_pdbn) topOut.AddPdbSerialNum( topIn.PdbSerialNum()[itgt] );
//pdb[itgt-currentRes.FirstAtom()] = iref;
// Check source atoms for inter-residue connections.
/* Atom const& sourceAtom = topIn[itgt];
for (Atom::bond_iterator bat = sourceAtom.bondbegin(); bat != sourceAtom.bondend(); ++bat) {
if ( topIn[*bat].ResNum() < ires ) {
// Use template atom names. Use saved names in case source name had an alias.
detectedInterResBonds.push_back( ResAtPair(ires, templateAtom.Name()) );
detectedInterResBonds.push_back( ResAtPair(topIn[*bat].ResNum(), SourceAtomNames[*bat]) );
if ( debug_ > 1 ) {
mprintf("DEBUG: Adding detected interres bond: itgt=%i name=%s res=%i tempName=%s -- bat=%i name=%s res=%i srcName=%s\n",
itgt+1, *(sourceAtom.Name()), ires+1, *(templateAtom.Name()),
*bat+1, *(topIn[*bat].Name()), topIn[*bat].ResNum()+1, *(SourceAtomNames[*bat]));
}
}
}*/
}
} // END loop over template atoms
if (nTgtAtomsMissing > 0) {
nAtomsNotInTemplates += nTgtAtomsMissing;
mprintf("\t%i source atoms not mapped to template.\n", nTgtAtomsMissing);
if (keepMissingSourceAtoms_) {
ResAtArray tmpBonds;
int firstNonTemplateAtom = topOut.Natom();
for (int itgt = 0; itgt != currentRes.NumAtoms(); itgt++) {
if (pdb[itgt] == -1) {
// This PDB atom had no equivalent in the residue template
int pdbat = itgt + currentRes.FirstAtom();
Atom pdbAtom = topIn[pdbat];
if (debug_ > 0)
mprintf("DEBUG:\t\tInput atom %s missing from template.\n",*(pdbAtom.Name()));
// Bonds
for (Atom::bond_iterator bit = pdbAtom.bondbegin(); bit != pdbAtom.bondend(); ++bit)
{
Atom bndAt = topIn[*bit];
NameType bndAtmName;
if (SourceAtomNames[*bit].len() > 0)
bndAtmName = SourceAtomNames[*bit];
else
bndAtmName = bndAt.Name();
if (debug_ > 0)
mprintf("DEBUG:\t\t\tBonded to %s\n", *(bndAtmName));
tmpBonds.push_back( ResAtPair(ires, pdbAtom.Name()) );
tmpBonds.push_back( ResAtPair(bndAt.ResNum(), bndAt.Name()) );
}
// Add missing atom
pdbAtom.ClearBonds();
topOut.AddTopAtom( pdbAtom, currentRes );
frameOut.AddVec3( Vec3(frameIn.XYZ(pdbat)) );
hasPosition.push_back( true );
if (has_bfac)
topOut.AddBfactor( topIn.Bfactor()[pdbat] );
if (has_occ)
topOut.AddOccupancy( topIn.Occupancy()[pdbat] );
if (has_pdbn)
topOut.AddPdbSerialNum( topIn.PdbSerialNum()[pdbat] );
}
} // END loop over input residue atoms
// Add Bonds
for (ResAtArray::const_iterator bit = tmpBonds.begin(); bit != tmpBonds.end(); ++bit)
{
int ba0 = topOut.FindAtomInResidue( bit->first, bit->second );
++bit;
int ba1 = topOut.FindAtomInResidue( bit->first, bit->second );
if (ba0 < firstNonTemplateAtom ||
ba1 < firstNonTemplateAtom ||
ba0 < ba1)
{
if (debug_ > 0)
mprintf("DEBUG:\t\tAdd bond %i %s -- %i %s\n", ba0+1, *(topOut[ba0].Name()), ba1+1, *(topOut[ba1].Name()));
topOut.AddBond( ba0, ba1 );
}
} // END loop over bonds
}
}
// Save atom offset if atoms need to be built
if (atomsNeedBuilding)
AtomOffsets.push_back( atomOffset );
else
AtomOffsets.push_back( -1 );
} // END template exists
// Add intra-residue bonds
for (IParray::const_iterator it = intraResBonds.begin(); it != intraResBonds.end(); ++it)
{
//mprintf("DEBUG: Intra-res bond: Res %s atom %s (%s) to res %s atom %s (%s)\n",
// topOut.TruncResNameOnumId(topOut[it->first].ResNum()).c_str(), *(topOut[it->first].Name()),
// topOut.AtomMaskName(it->first).c_str(),
// topOut.TruncResNameOnumId(topOut[it->second].ResNum()).c_str(), *(topOut[it->second].Name()),
// topOut.AtomMaskName(it->second).c_str());
topOut.AddBond(it->first, it->second);
}
} // END loop over source residues
t_fill_template_.Stop();
if (nRefAtomsMissing > 0)
mprintf("\t%i template atoms missing in source.\n", nRefAtomsMissing);
if (nAtomsNotInTemplates > 0) {
if (requireAllInputAtoms_)
mprinterr("Error: %i input atoms not in templates.\n", nAtomsNotInTemplates);
else
mprintf("\t%i input atoms were not in templates and were ignored.\n", nAtomsNotInTemplates);
}
if (nAtomsMissingTypes > 0) {
mprinterr("Error: %i atoms are missing types, either because they did not have\n"
"Error: one initially or they could not be matched to a template.\n"
"Error: This can happen if a parameter file is missing or a force field\n"
"Error: file has not been loaded.\n"
"Error: Build cannot proceed unless all atoms have a type:\n",
nAtomsMissingTypes);
std::set<NameType> atoms_missing_types;
for (int ires = 0; ires != topOut.Nres(); ires++) {
for (int at = topOut.Res(ires).FirstAtom(); at != topOut.Res(ires).LastAtom(); ++at) {
if ( !topOut[at].HasType() )
atoms_missing_types.insert( topOut[at].Name() );
}
}
mprinterr("Error: Atoms missing types:");
for (std::set<NameType>::const_iterator ait = atoms_missing_types.begin();
ait != atoms_missing_types.end(); ++ait)
mprinterr(" %s", *(*ait));
mprinterr("\n");
if (debug_ > 0) {
for (int ires = 0; ires != topOut.Nres(); ires++) {
std::string missingTypes;
for (int at = topOut.Res(ires).FirstAtom(); at != topOut.Res(ires).LastAtom(); ++at)
if ( !topOut[at].HasType() )
missingTypes.append(" " + topOut[at].Name().Truncated() );
if (!missingTypes.empty())
mprinterr("Error:\t%s missing types for%s\n", topOut.TruncResNameNum(ires).c_str(), missingTypes.c_str());
}
}
if (!missing_templates.empty()) {
mprinterr("Error: %u residues were missing a template.\n", n_no_template_found);
mprinterr("Error: %zu missing residue templates:", missing_templates.size());
for (std::set<NameType>::const_iterator rit = missing_templates.begin();
rit != missing_templates.end(); ++rit)
mprinterr(" %s", *(*rit));
mprinterr("\n");
}
mprinterr("Error: Suggestions:\n"
"Error: 1) Load an Amber force field using 'source <leaprc file>', e.g. 'source leaprc.protein.ff19SB'\n"
"Error: 2) Load residue templates with atom types from library/coords files with 'readdata <file> as <type>', e.g. 'readdata amino19.lib as off'\n"
"Error: 3) If the residues missing templates can be removed (e.g. extra waters), remove them with 'nowat' or 'stripmask'.\n");
printErrMsgWebsites();
return 1;
}
// -----------------------------------
// DEBUG - Print primary connection atoms
if (debug_ > 0) {
for (unsigned int idx = 0; idx != ResTemplates.size(); idx++) {
if (ResTemplates[idx] != 0) {
mprintf("DEBUG: Template %s (%s)", ResTemplates[idx]->legend(), Cpptraj::Structure::terminalStr(ResTermTypes[idx]));
if (resHeadAtoms[idx] > -1) mprintf(" head %s", topOut.AtomMaskName(resHeadAtoms[idx]).c_str());
if (resTailAtoms[idx] > -1) mprintf(" tail %s", topOut.AtomMaskName(resTailAtoms[idx]).c_str());
mprintf("\n");
}
}
}
// Keep track of which residues are connected.
ResConnectArray ResidueConnections( topOut.Nres() );
// Try to connect HEAD atoms to previous residue TAIL atoms.
std::vector<IParray> resBondingAtoms(topOut.Nres());
for (int ires = 1; ires < topOut.Nres(); ires++) {
int pres = ires - 1;
if (resHeadAtoms[ires] != -1) {
if (ResTermTypes[ires] == Cpptraj::Structure::BEG_TERMINAL) {
if (debug_ > 0)
mprintf("DEBUG: Res %s is begin terminal, ignoring head atom.\n",
topOut.TruncResNameOnumId(ires).c_str());
} else {
if (resTailAtoms[pres] != -1) {
if (ResTermTypes[pres] == Cpptraj::Structure::END_TERMINAL) {
if (debug_ > 0)
mprintf("DEBUG: Res %s is end terminal, ignoring tail atom.\n",
topOut.TruncResNameOnumId(pres).c_str());
} else {
if (debug_ > 0)
mprintf("DEBUG: Connecting HEAD atom %s to tail atom %s\n",
topOut.AtomMaskName(resHeadAtoms[ires]).c_str(),
topOut.AtomMaskName(resTailAtoms[pres]).c_str());
resBondingAtoms[ires].push_back( Ipair(resHeadAtoms[ires], resTailAtoms[pres]) );
resBondingAtoms[pres].push_back( Ipair(resTailAtoms[pres], resHeadAtoms[ires]) );
resHeadAtoms[ires] = -1;
resTailAtoms[pres] = -1;
ResidueConnections[ires].push_back( pres );
ResidueConnections[pres].push_back( ires );
}
}
}
}
}
// Report unused HEAD/TAIL atoms
for (int ires = 0; ires != topOut.Nres(); ires++) { // TODO should be topIn?
if (resHeadAtoms[ires] != -1)
mprintf("Warning: Unused head atom %s\n", topOut.AtomMaskName(resHeadAtoms[ires]).c_str());
if (resTailAtoms[ires] != -1)
mprintf("Warning: Unused tail atom %s\n", topOut.AtomMaskName(resTailAtoms[ires]).c_str());
}
// Add external bonds
if (!topInBonds.empty()) {
for (std::vector<BondType>::const_iterator bnd = topInBonds.begin();
bnd != topInBonds.end(); ++bnd)
{
Atom const& At0 = topIn[bnd->A1()];
Atom const& At1 = topIn[bnd->A2()];
// Ignore bonds in the same residue
if ( At0.ResNum() == At1.ResNum()) {
mprintf("Build Warning: Atoms %s and %s are in the same residue %i. Not adding extra bond.\n",
*(At0.Name()), *(At1.Name()), At0.ResNum()+1);
continue;
}
int a0 = topOut.FindAtomInResidue( At0.ResNum(), At0.Name() );
int a1 = topOut.FindAtomInResidue( At1.ResNum(), At1.Name() );
if (a0 < 0) {
mprinterr("Error: Atom %s not found in residue %i\n", *(At0.Name()), At0.ResNum()+1);
return 1;
}
if (a1 < 0) {
mprinterr("Error: Atom %s not found in residue %i\n", *(At1.Name()), At1.ResNum()+1);
return 1;
}
if (resIsConnected(ResidueConnections[At0.ResNum()], At1.ResNum())) {
mprintf("Warning: Residue %s already connected to residue %s; ignoring\n"
"Warning: extra bond %s - %s\n",
topOut.TruncResNameNum(At0.ResNum()).c_str(),
topOut.TruncResNameNum(At1.ResNum()).c_str(),
topOut.AtomMaskName(a0).c_str(),
topOut.AtomMaskName(a1).c_str());
} else {
if (debug_ > 0)
mprintf("DEBUG: Adding extra bond %s - %s\n",
topOut.AtomMaskName(a0).c_str(),
topOut.AtomMaskName(a1).c_str());
resBondingAtoms[At0.ResNum()].push_back( Ipair(a0, a1) );
resBondingAtoms[At1.ResNum()].push_back( Ipair(a1, a0) );
ResidueConnections[At0.ResNum()].push_back( At1.ResNum() );
ResidueConnections[At1.ResNum()].push_back( At0.ResNum() );
}
} // END loop over externally passed in bonds
}
// Check detected inter-residue bonds
for (ResAtArray::const_iterator it = detectedInterResBonds.begin();
it != detectedInterResBonds.end(); ++it)
{
ResAtPair const& ra0 = *it;
++it;
ResAtPair const& ra1 = *it;
bool bondInvolvesResWithNoTemplate = ( (ResTemplates[ra0.first] == 0) ||
(ResTemplates[ra1.first] == 0) );
if (debug_ > 1)
mprintf("DEBUG: Inter-res bond: Res %i atom %s to res %i atom %s : bondInvolvesResWithNoTemplate=%i\n",
ra0.first+1, *(ra0.second),
ra1.first+1, *(ra1.second),
(int)bondInvolvesResWithNoTemplate);
int at0 = topOut.FindAtomInResidue(ra0.first, ra0.second);
if (at0 < 0) {
mprinterr("Error: Atom %s not found in residue %i\n", *(ra0.second), ra0.first+1);
return 1;
}
int at1 = topOut.FindAtomInResidue(ra1.first, ra1.second);
if (at1 < 0) {
mprinterr("Error: Atom %s not found in residue %i\n", *(ra1.second), ra1.first+1);
return 1;
}
// Save detected inter-residue bonding atoms if not already added via
// template connect atoms. Convention is atom belonging to the current
// residue is first.
// NOTE: Only checking at0/at1 here, which should be fine.
if (!hasBondingPair(resBondingAtoms[ra0.first], Ipair(at0, at1))) {
// Check if we already have a connection from ra0 to ra1.
if (resIsConnected(ResidueConnections[ra0.first], ra1.first)) {
mprintf("Warning: Residue %s already connected to residue %s; ignoring\n"
"Warning: potential detected bond %s - %s\n",
topOut.TruncResNameNum(ra0.first).c_str(),
topOut.TruncResNameNum(ra1.first).c_str(),
topOut.AtomMaskName(at0).c_str(),
topOut.AtomMaskName(at1).c_str());
} else {
if (bondInvolvesResWithNoTemplate) {
mprintf("\tAdding non-template bond %s - %s\n",
topOut.AtomMaskName(at0).c_str(),
topOut.AtomMaskName(at1).c_str());
resBondingAtoms[ra0.first].push_back( Ipair(at0, at1) );
resBondingAtoms[ra1.first].push_back( Ipair(at1, at0) );
ResidueConnections[ra0.first].push_back( ra1.first );
ResidueConnections[ra1.first].push_back( ra0.first );
} else {
if (debug_ > 0)
mprintf("DEBUG: Detected non-template bond %s - %s; not adding it.\n",
topOut.AtomMaskName(at0).c_str(),
topOut.AtomMaskName(at1).c_str());
}
}
}
}
// DEBUG print inter-residue bonding atoms
if (debug_ > 0) {
for (std::vector<IParray>::const_iterator rit = resBondingAtoms.begin();
rit != resBondingAtoms.end(); ++rit)
{
mprintf("\tResidue %s bonding atoms.\n", topOut.TruncResNameNum(rit-resBondingAtoms.begin()).c_str());
for (IParray::const_iterator it = rit->begin(); it != rit->end(); ++it)
mprintf("\t\t%s - %s\n", topOut.AtomMaskName(it->first).c_str(), topOut.AtomMaskName(it->second).c_str());
}
}
// -----------------------------------
// Do some error checking
if (hasPosition.size() != (unsigned int)newNatom) {
mprinterr("Internal Error: hasPosition size %zu != newNatom size %i\n", hasPosition.size(), newNatom);
return 1;
}
if (AtomOffsets.size() != (unsigned int)topOut.Nres()) {
mprinterr("Internal Error: AtomOffsets size %zu != newNres size %i\n", AtomOffsets.size(), topOut.Nres());
return 1;
}
if (SourceAtomNames.size() != (unsigned int)topIn.Natom()) {
mprinterr("Internal Error: Source atom names length %zu != # input atoms %i\n", SourceAtomNames.size(), topIn.Natom());
return 1;
}
if (has_bfac) {
if (topOut.Bfactor().size() != (unsigned int)topOut.Natom()) {
mprinterr("Internal Error: Size of final Bfactor array %zu != # atoms %i\n", topOut.Bfactor().size(), topOut.Natom());
return 1;
}
}
if (has_occ) {
if (topOut.Occupancy().size() != (unsigned int)topOut.Natom()) {
mprinterr("Internal Error: Size of final Occupancy array %zu != # atoms %i\n", topOut.Occupancy().size(), topOut.Natom());
return 1;
}
}
if (has_pdbn) {
if (topOut.PdbSerialNum().size() != (unsigned int)topOut.Natom()) {
mprinterr("Internal Error: Size of final PdbSerialNum array %zu != # atoms %i\n", topOut.PdbSerialNum().size(), topOut.Natom());
return 1;
}
}
if (debug_ > 0) {
mprintf("DEBUG: hasPosition:\n");
for (unsigned int idx = 0; idx != (unsigned int)topOut.Natom(); idx++)
mprintf("\t%10u %20s : %i\n", idx+1, topOut.AtomMaskName(idx).c_str(), (int)hasPosition[idx]);
}
// -----------------------------------
// Build using internal coords if needed.
t_fill_build_.Start();
bool buildFailed = false;
Cpptraj::Structure::Builder::Barray tmpHasPosition(topOut.Natom(), false);
int nextTempHasPositionStart = 0;
for (Iarray::const_iterator it = AtomOffsets.begin(); it != AtomOffsets.end(); ++it)
{
long int ires = it-AtomOffsets.begin();
if (*it > -1) {
if (debug_ > 0)
mprintf("DEBUG: ***** BUILD residue %li %s *****\n", ires + 1,
topOut.TruncResNameOnumId(ires).c_str());
// Residue has atom offset which indicates it needs something built.
Cpptraj::Structure::Builder structureBuilder;// = new Cpptraj::Structure::Builder();
structureBuilder.SetDebug( debug_ );
if (creator.HasMainParmSet())
structureBuilder.SetParameters( creator.MainParmSetPtr() );
// Generate internals from the template, update indices to this topology.
DataSet_Coords* resTemplate = ResTemplates[ires];
# ifdef TIMER
t_fill_build_internals_.Start();
# endif
Frame templateFrame = resTemplate->AllocateFrame();
resTemplate->GetFrame( 0, templateFrame );
if (structureBuilder.GenerateInternals(templateFrame, resTemplate->Top(),
std::vector<bool>(resTemplate->Top().Natom(), true)))
{
mprinterr("Error: Generate internals for residue template failed.\n");
return 1;
}
# ifdef TIMER
t_fill_build_internals_.Stop();
# endif
structureBuilder.UpdateIndicesWithOffset( *it );
//mprintf("DEBUG: Residue type: %s terminal\n", Cpptraj::Structure::terminalStr(*termType));
// Is this residue connected to an earlier residue?
# ifdef TIMER
t_fill_build_link_.Start();
# endif
for (IParray::const_iterator resBonds = resBondingAtoms[ires].begin();
resBonds != resBondingAtoms[ires].end(); ++resBonds)
{
if (resBonds->second < resBonds->first) {
if (debug_ > 0)
mprintf("\t\tResidue connection: %s - %s\n",
topOut.AtomMaskName(resBonds->first).c_str(),
topOut.AtomMaskName(resBonds->second).c_str());
# ifdef TIMER
t_fill_build_link_bond_.Start();
# endif
topOut.AddBond(resBonds->first, resBonds->second);
# ifdef TIMER
t_fill_build_link_bond_.Stop();
# endif
// Generate internals around the link
Residue const& R0 = topIn.Res(topOut[resBonds->first].ResNum());
for (int at = nextTempHasPositionStart; at < R0.FirstAtom(); at++)
tmpHasPosition[at] = true;
nextTempHasPositionStart = R0.FirstAtom();
if (structureBuilder.GenerateInternalsAroundLink(resBonds->first, resBonds->second,
frameOut, topOut, hasPosition, Cpptraj::Structure::Builder::BUILD,
tmpHasPosition))
{
mprinterr("Error: Assign torsions around inter-residue link %s - %s failed.\n",
topOut.AtomMaskName(resBonds->first).c_str(),
topOut.AtomMaskName(resBonds->second).c_str());
return 1;
}
}
}
# ifdef TIMER
t_fill_build_link_.Stop();
# endif
// Update internal coords from known positions
if (structureBuilder.UpdateICsFromFrame( frameOut, topOut, hasPosition )) {
mprinterr("Error: Failed to update internals with values from existing positions.\n");
return 1;
}
# ifdef TIMER
t_fill_build_build_.Start();
# endif
if (structureBuilder.BuildFromInternals(frameOut, topOut, hasPosition)) {
mprinterr("Error: Building residue %s failed.\n",
topOut.TruncResNameOnumId(ires).c_str());
buildFailed = true;
}
# ifdef TIMER
t_fill_build_build_.Stop();
# endif
} else {
// All atoms present. Just connect
// Is this residue connected to an earlier residue?
for (IParray::const_iterator resBonds = resBondingAtoms[ires].begin();
resBonds != resBondingAtoms[ires].end(); ++resBonds)
{
if (resBonds->second < resBonds->first) {
if (debug_ > 0)
mprintf("\t\tResidue connection only: %s - %s\n",
topOut.AtomMaskName(resBonds->first).c_str(),
topOut.AtomMaskName(resBonds->second).c_str());
topOut.AddBond(resBonds->first, resBonds->second);
}
}
}
} // END loop over atom offsets
t_fill_build_.Stop();
// DEBUG - Print new top/coords
if (debug_ > 1) {
for (int iat = 0; iat != topOut.Natom(); iat++)
{
Residue const& res = topOut.Res( topOut[iat].ResNum() );
const double* XYZ = frameOut.XYZ(iat);
mprintf("%6i %6s %6i %6s (%i) %g %g %g\n",
iat+1, *(topOut[iat].Name()), res.OriginalResNum(), *(res.Name()),
(int)hasPosition[iat], XYZ[0], XYZ[1], XYZ[2]);
}
}
if (buildFailed) return 1;
return 0;
}
/** Given an original topology and bonded atom indices, find those atoms
* in another topology and ensure they are bonded.
*/
int Exec_Build::transfer_bonds(Topology& topOut, Topology const& topIn,
std::vector<BondType> const& bondsIn)
const
{
for (std::vector<BondType>::const_iterator bnd = bondsIn.begin();
bnd != bondsIn.end(); ++bnd)
{
// Get the original atom name and residue number
Atom const& original_A1 = topIn[bnd->A1()];
Atom const& original_A2 = topIn[bnd->A2()];
if (debug_ > 0)
mprintf("DEBUG: Original bond atoms %i (%s) %i (%s)\n",
bnd->A1()+1, topIn.AtomMaskName(bnd->A1()).c_str(),
bnd->A2()+1, topIn.AtomMaskName(bnd->A2()).c_str());
// Find the atoms in the new topology
int a1 = topOut.FindAtomInResidue( original_A1.ResNum(), original_A1.Name() );
if (a1 < 0) {
mprinterr("Error: Could not find atom %i (%s) in new topology.\n",
bnd->A1()+1, topIn.AtomMaskName(bnd->A1()).c_str());
return 1;
}
int a2 = topOut.FindAtomInResidue( original_A2.ResNum(), original_A2.Name() );
if (a2 < 0) {
mprinterr("Error: Could not find atom %i (%s) in new topology.\n",
bnd->A2()+1, topIn.AtomMaskName(bnd->A2()).c_str());
return 1;
}
// Add the bond to the new topology
topOut.AddBond( a1, a2 );
}
return 0;
}
// -----------------------------------------------------------------------------
// Exec_Build::Help()
void Exec_Build::Help() const
{
mprintf("\t[name <output COORDS>] {crdset <COORDS set>|<file>} [{frame <#>|doassembly}]\n");
Cpptraj::Structure::PdbCleaner::Help();
mprintf("\t[title <title>] [verbose <#>] [keepmissingatoms] [nofixorder]\n"
"\t[parmout <topology file>] [crdout <coord file>] [simplecheck]\n"
"\t[reportfile <check file>] [flexiblewater]\n");
mprintf("\t[%s]\n", Cpptraj::Parm::GB_Params::HelpText().c_str());
mprintf(" LJ 12-6-4 options:\n");
mprintf("\t[lj1264 %s]\n", Cpptraj::Parm::LJ1264_Params::HelpText().c_str());
mprintf(" Atom Scan direction:\n");
mprintf("\t[%s]\n"
" Residue Templates and Parameters to use:\n"
"\t[{%s} ...]\n"
"\t[{%s} ...]\n"
" Solvation/box:\n"
"\t[{{solvatebox|solvateoct} %s\n"
"\t %s |\n"
"\t setbox %s}]\n"
" Adding ions:\n"
"\t[addionsrand ion1 <name1> nion1 <num1> [ion2 <name2> nion2 <num2>]\n"
"\t [minsep <dist>] [ionseed <seed>] [ionchain <id>]]\n"
" 'prepareforleap' options:\n"
"%s"
"%s"
"%s",
Cpptraj::Structure::Creator::other_keywords_,
Cpptraj::Structure::Creator::template_keywords_,
Cpptraj::Structure::Creator::parm_keywords_,
Cpptraj::Structure::Solvate::SolvateKeywords1(),
Cpptraj::Structure::Solvate::SolvateKeywords2(),
Cpptraj::Structure::Solvate::SetboxKeywords(),
Cpptraj::Structure::HisProt::keywords_,
Cpptraj::Structure::Disulfide::keywords_,
Cpptraj::Structure::SugarBuilder::keywords_
);
mprintf(" Build complete topology and parameters from given crdset.\n");
}
/** Check if any unhandled options have been set. */
int Exec_Build::checkUnhandledOptions(DataSet_LeapOpts const& OPTS) const {
if (OPTS.IPOL() > 0) {
mprinterr("Error: IPOL has been set to something other than zero by a previous leaprc file.\n"
"Error: Creating topologies for polarizable FF is not yet supported.\n");
return 1;
}
return 0;
}
// Exec_Build::Execute()
Exec::RetType Exec_Build::Execute(CpptrajState& State, ArgList& argIn)
{
#ifndef CPPTRAJ_USE_LEAP_PI
mprintf("Warning: CPPTRAJ was not compiled with LEaP's value of PI.\n"
"Warning: Output Topology and Coordinates are expected to differ slightly from LEaP.\n"
"Warning: To obtain an exact match to LEaP CPPTRAJ must be compiled with\n"
"Warning: -DCPPTRAJ_USE_LEAP_PI (configure flag '-leappi').\n");
# endif
std::string outset = argIn.GetStringKey("name");
// Get input coords
DataSet* inCrdPtr = 0;
std::string crdset = argIn.GetStringKey("crdset");
if (crdset.empty()) {
// Try to load a file
FileName fname(argIn.GetStringNext());
if (File::Exists( fname )) {
DataIO_Coords crdin;
if (crdin.ReadData(fname, State.DSL(), fname.Base())) {
mprinterr("Error: Could not read top/coords from '%s'\n", fname.full());
return CpptrajState::ERR;
}
inCrdPtr = crdin.added_back();
}
} else {
inCrdPtr = State.DSL().FindSetOfGroup( crdset, DataSet::COORDINATES );
if (inCrdPtr == 0) {
mprinterr("Error: No COORDS set found matching %s\n", crdset.c_str());
return CpptrajState::ERR;
}
}
if (inCrdPtr == 0) {
mprinterr("Error: Must specify file to build or COORDS set with 'crdset'\n");
return CpptrajState::ERR;
}
DataSet_LeapOpts* leapopts = (DataSet_LeapOpts*)State.DSL().FindSetOfType( "*", DataSet::LEAPOPTS );
if (leapopts != 0) {
// Check for unhandled leap options
DataSet_LeapOpts const& OPTS = static_cast<DataSet_LeapOpts const&>( *leapopts );
if (checkUnhandledOptions( OPTS )) return CpptrajState::ERR;
}
return BuildAndParmStructure(inCrdPtr, outset, State.DSL(), State.Debug(), argIn, Cpptraj::Parm::UNKNOWN_GB, leapopts);
}
/** Create an assembly from all the frames in the input coordinates. */
int Exec_Build::createAssembly(Topology& topIn, Frame& frameIn,
DataSet_Coords& CRDIN)
const
{
if (CRDIN.Size() < 2) {
mprintf("Warning: Only %zu frames in COORDS set '%s'; no assembly needed.\n", CRDIN.Size(), CRDIN.legend());
frameIn = CRDIN.AllocateFrame();
CRDIN.GetFrame(0, frameIn);
topIn = CRDIN.Top();
} else {
mprintf("\tCreating assembly from %zu structures:", CRDIN.Size());
for (unsigned int idx = 0; idx < CRDIN.Size(); idx++) {
mprintf(" %u", idx+1);
topIn.AppendTop( CRDIN.Top(), debug_, false, false );
}
frameIn.SetupFrameV( topIn.Atoms(), CRDIN.CoordsInfo() );
Frame frm = CRDIN.AllocateFrame();
mprintf("\n\tCopying coordinates for assembly:");
double *output = frameIn.xAddress();
for (unsigned int idx = 0; idx < CRDIN.Size(); idx++) {
// Coords
mprintf(" %u", idx+1);
CRDIN.GetFrame(idx, frm);
std::copy(frm.xAddress(), frm.xAddress()+frm.size(), output);
output += frm.size();
}
mprintf("\n");
topIn.Brief("Assembly");
}
return 0;
}
/** Standalone execute. For DataIO_LeapRC. Operate on inCrdPtr */
Exec::RetType Exec_Build::BuildStructure(DataSet* inCrdPtr, DataSetList& DSL, int debugIn,
std::string const& outset, std::string const& title,
bool enableExtraDetection, DataSet_LeapOpts* leapopts)
{
#ifndef CPPTRAJ_USE_LEAP_PI
mprintf("Warning: CPPTRAJ was not compiled with LEaP's value of PI.\n"
"Warning: Output Topology and Coordinates are expected to differ slightly from LEaP.\n"
"Warning: To obtain an exact match to LEaP CPPTRAJ must be compiled with\n"
"Warning: -DCPPTRAJ_USE_LEAP_PI (configure flag '-leappi').\n");
# endif
t_total_.Start();
if (inCrdPtr == 0) {
mprinterr("Internal Error: Exec_Build::BuildStructure(): Null input coordinates.\n");
return CpptrajState::ERR;
}
if (inCrdPtr->Group() != DataSet::COORDINATES) {