File: ExampleFoldPolyalanine.cpp

package info (click to toggle)
molmodel 3.1.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,384 kB
  • sloc: cpp: 39,830; perl: 526; ansic: 107; makefile: 41
file content (274 lines) | stat: -rw-r--r-- 11,249 bytes parent folder | download | duplicates (4)
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
/* -------------------------------------------------------------------------- *
 *                 SimTK Molmodel Example: Fold Polyalanine                   *
 * -------------------------------------------------------------------------- *
 * This example attempts to fold polyalanine from an extended configuration.  *
 * We expect a sequence of alanines to form a helix.                          *
 *                                                                            *
 * The strategy we'll follow here is a crude annealing protocol in which      *
 * we'll start at a high temperature and progressively lower the temperature  *
 * as we simulate. We hope to see the polyalanine settle into a helix         *
 * when the temperature gets low enough. As we go along we'll track the       *
 * potential energy and save the lowest-energy state we've seen so far. In    *
 * the end we'll report that state as the result.                             *
 *                                                                            *
 * This example demonstrates                                                  *
 *   - modeling a protein directly from sequence                              *
 *   - the Nose-Hoover thermostat                                             *
 *   - use of an event handler to interrupt the simulation to make            *
 *     discontinuous changes (here lowering the requested temperature)        *
 *   - how to use OpenMM for GPU acceleration if it is available, falling     *
 *     back to multithreading otherwise                                       *
 *   - how to remove overall rigid body momentum to keep the molecule from    *
 *     drifting                                                               *
 *   - how to generate a live movie using the Simbody Visualizer and how to   *
 *     write to a pdb file for later visualization in VMD or another advanced *
 *     molecule visualizer                                                    *
 *   - use of Simbody's CPU and real timers, and Pathname class to find out   *
 *     what directory we're running in (that's where the pdb file will be).   *
 *                                                                            *
 * Author: Michael Sherman                                                    *
 * -------------------------------------------------------------------------- */


#include "Molmodel.h"

#include <iostream>
#include <fstream>
#include <exception>
using namespace SimTK;

// Comment this out if it causes trouble for you.
#define TRY_TO_USE_OPENMM


// See below.
static Real startCPU, startRT; // timers
static State minState;
static Real minPE = Infinity;


// This is a reporter so we can get some output during the simulation and
// capture the lowest-energy state we've seen so far.
class SaySomething : public PeriodicEventReporter {
public:
	SaySomething(const CompoundSystem& system, 
                 const NoseHooverThermostat& thermo,
                 Real reportInterval) 
        :   PeriodicEventReporter(reportInterval), system(system), thermo(thermo) {}

    void handleEvent(const State& state) const {
		const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();
        system.realize(state, Stage::Dynamics);
        const Real pe = system.calcPotentialEnergy(state);

		std::cout << "TIME = " << state.getTime() 
              << " PE=" << pe
              << " T=" << thermo.getCurrentTemperature(state)
              << " RT=" << realTime()-startRT << "s"
              << " CPU=" << cpuTime()-startCPU << "s\n"; 
 
        if (pe < minPE) {
            std::cout << "***** best so far *****\n";
            minState = state;
            minPE = pe;
        }
    }
private:
    const CompoundSystem&               system;
    const NoseHooverThermostat&         thermo;
};

// This event handler implements the annealing protocol by changing
// the temperature of the thermal bath that interacts with our peptide.
class ChangeTemperature : public PeriodicEventHandler {
public:
    ChangeTemperature(const CompoundSystem& system,                  
                      const NoseHooverThermostat& thermo,
                      Real interval,
                      Real frac=.75, // fraction by which we reduce T
                      Real minT=10)  // temperature at which we'll quit
    :   PeriodicEventHandler(interval), system(system), thermo(thermo),
        frac(frac), minT(minT) {}

    // The Simbody TimeStepper invokes this method periodically, based on
    // the time interval that was provided in the constructor.
    void handleEvent(State& state, Real accuracy, bool& shouldTerminate) const 
    {
		const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();

        const Real bathT = thermo.getBathTemperature(state);
        if (state.getTime() == 0) {
            std::cout << "STARTING T=" << bathT << "K. Reduce to " << frac << " every " 
                      << getEventInterval() << "ps until " << minT << "K." << std::endl;
            return;
        }
        
        const Real newBathT = std::max(minT, bathT*frac);
        if (bathT == newBathT) {
            if (bathT <= minT) shouldTerminate=true;
            return;
        }

        thermo.setBathTemperature(state, newBathT);
        std::cout << "Changed bath T to " << newBathT << std::endl;
    }
private:
    const CompoundSystem&       system;
    const NoseHooverThermostat& thermo;
    const Real frac;
    const Real minT;
};

int main() {
try {

	// molecule-specialized Simbody System
    CompoundSystem system;
	SimbodyMatterSubsystem matter(system);
    GeneralForceSubsystem forces(system);
    DecorationSubsystem decorations(system);

	// Molecular force field. GBSA solvation is used by default.
    DuMMForceFieldSubsystem forceField(system);
    forceField.loadAmber99Parameters();

    // optional -- try OpenMM accelerations
    #ifdef TRY_TO_USE_OPENMM
        forceField.setUseOpenMMAcceleration(true);
    #endif
    // This causes tracing even if we aren't trying to use OpenMM.
    forceField.setTracing(true); // log OpenMM info to console

    // Multithreading is used by default unless you disable it.
    //forceField.setUseMultithreadedComputation(false);
    forceField.setNumThreadsRequested(0); // default

    // You can change to vacuum by uncommenting this line.
    //forceField.setGbsaGlobalScaleFactor(0);

    std::cout << "num threads before realizeTopology (should be zero): " 
              << forceField.getNumThreadsInUse() << std::endl;

    // The Protein constructor always adds neutral end caps unless
    // you suppress them.

    //Protein protein("SIMTK");
    //Protein protein("AAAAAA"); // 6
    //Protein protein("AAAAAAAAAA"); // 10
    //Protein protein("AAAAAAAAAAAA"); // 12
    Protein protein("AAAAAAAAAAAAAAA"); // 15


    // This is the Tryptophan cage 1L2Y.pdb.
    // (ACE) ASN LEU TYR ILE GLN TRP LEU LYS ASP GLY GLY PRO SER          
    // SER GLY ARG PRO PRO PRO SER (NAC)
    //Protein protein("NLYIQWLKDGGPSSGRPPPS");

    protein.assignBiotypes();
    system.adoptCompound(protein);

	// finalize multibody system
    system.modelCompounds(); 

    // Create a PeriodicPdbWriter (a Molmodel-provided Reporter) for 
    // generating pdb frames. We'll keep a pointer to it here so we can generate 
    // a few frames before and after the simulation. We'll ask the TimeStepper
    // to call this every 100fs.
    std::cout << "\nNOTE: Writing pdb file 'polyalanine.pdb' in " 
              << Pathname::getCurrentWorkingDirectory() << "\n\n";
    std::ofstream pdbFile; pdbFile.open("polyalanine.pdb");
    PeriodicPdbWriter* pdbWriter = new PeriodicPdbWriter(system, pdbFile, 0.1);
    system.addEventReporter(pdbWriter); // System takes ownership

    // Create a Visualizer for live animation while simulating and ask
    // the TimeStepper to invoke it every 100fs.
    Visualizer viz(system);
    system.addEventReporter(new Visualizer::Reporter(viz, 0.1) );


    const Real startT = 1000;
    NoseHooverThermostat thermo(forces, matter, startT, .5);

    // We'll stay at a given temperature for a time proportional to
    // the number of residues we're trying to fold.
    const Real timePerResidue = 1.; // ps
    system.addEventHandler(
        new ChangeTemperature(system, thermo, 
                timePerResidue*protein.getNumResidues(), 
                0.9,    // reduce by setting newT = 90% * oldT
                150));  // stop when we get to this temperature

    // We'll remove overall rigid body momentum every 10ps so the
    // molecule doesn't run off the screen.
    system.addEventHandler(new MassCenterMotionRemover(system, 10));

    // Output some stats every 1ps, and remember the lowest energy
    // state we've seen.
    system.addEventReporter(new SaySomething(system, thermo, 1));


	// Instantiate Simbody model
	system.realizeTopology();
	State state = system.getDefaultState();

    std::cout << "num threads in use after realizeTopology: " 
              << forceField.getNumThreadsInUse() << std::endl;

    system.realize(state, Stage::Position);
    viz.report(state);             // first animation frame
    pdbWriter->handleEvent(state); // pdb frame

	// Relax the structure before dynamics run
	LocalEnergyMinimizer::minimizeEnergy(system, state, 10);

    system.realize(state, Stage::Position);
    viz.report(state);             // post-relaxation frame
    pdbWriter->handleEvent(state); // pdb frame

    startCPU = cpuTime();   // start the cpu timer
    startRT  = realTime(); // and the real timer


    // Simulate it.
    //VerletIntegrator integ(system);
    RungeKuttaMersonIntegrator integ(system);
    integ.setAccuracy(1e-2);
    TimeStepper ts(system, integ);
    ts.initialize(state);
    ts.stepTo(1000.0);


    std::cout << "Done. " << integ.getTime() << "ps in elapsed(s)=" 
              << realTime()-startRT << " CPU=" << cpuTime()-startCPU
              << std::endl;

    State finalState = minState;
    system.realize(finalState, Stage::Dynamics);
    std::cout << "Best PE=" << system.calcPotentialEnergy(finalState) << std::endl;
    viz.report(finalState);             // show best conformation
    pdbWriter->handleEvent(finalState); // pdb frame

	LocalEnergyMinimizer::minimizeEnergy(system, finalState, 5);

    system.realize(finalState, Stage::Dynamics);
    std::cout << "Final PE=" << system.calcPotentialEnergy(finalState) << std::endl;
    viz.report(finalState);             // post-minimization animation frame
    pdbWriter->handleEvent(finalState); // final pdb frame

    pdbFile.close();
    std::cout << "\nWrote pdb file "
              << Pathname::getCurrentWorkingDirectory() << "polyalanine.pdb\n";
    return 0;

} 
catch(const std::exception& e) {
    std::cerr << "ERROR: " << e.what() << std::endl;
    return 1;
}
catch(...) {
    std::cerr << "ERROR: An unknown exception was raised" << std::endl;
    return 1;
}

}