Swarm-NG  1.1
tutorial_gpu.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  * Copyright (C) 2009-2010 by Eric Ford & the Swarm-NG Development Team *
3  * *
4  * This program is free software; you can redistribute it and/or modify *
5  * it under the terms of the GNU General Public License as published by *
6  * the Free Software Foundation; either version 3 of the License. *
7  * *
8  * This program is distributed in the hope that it will be useful, *
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11  * GNU General Public License for more details. *
12  * *
13  * You should have received a copy of the GNU General Public License *
14  * along with this program; if not, write to the *
15  * Free Software Foundation, Inc., *
16  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
17  ************************************************************************/
18 
25 /* This is a tutorial used in doxygen pages
26  * should go through program2doxgyen before
27  * it can be used by doxygen.
28  *
29  */
30 // \page TutorialGPU Advanced tutorial for using GPU integrators
31 //
32 // The basic API gives you control for selecting integrators and
33 // using them. If you need to have more control over the integration
34 // process and how GPU memory is managed, you need to use more
35 // advanced API. This tutorial gives demonstrates how to use
36 // API for managing GPU integrators and ensembles.
37 //
38 // Basic set up: include the headers needed and others.
39 //
40 #include <iostream>
41 #include "swarm/swarm.h"
42 #include "swarm/snapshot.hpp"
43 #define SYNC cudaThreadSynchronize()
44 using namespace swarm;
45 using namespace std;
46 
48 int main(int argc, char* argv[]){
49 
50 
51  // This is the easy way to load config from a file our config file
52  // will include parameters to set up a GPU integrator
53  //
54  config cfg = config::load( "myconfig.cfg" );
55 
56  // We load initial conditions from an textual input file
57  defaultEnsemble ref = snapshot::load_text( "input.txt" );
58 
59  // Make a working copy of the initial conditions
60  defaultEnsemble ens = ref.clone();
61 
62  // Initialize Swarm library. Basically, it initializes CUDA system and default logging system.
63  swarm::init(cfg);
64 
65  // Select and initialize the integrator using the config. We assume
66  // that the integrator specified is a GPU integrator. Note that we
67  // cannot easily check if the integrator is a GPU integrator. The
68  // application will fail if the integrator specified is not a GPU
69  // integrator.
70  gpu::Pintegrator integ = boost::dynamic_pointer_cast<gpu::integrator>(integrator::create(cfg));
71 
72  // Since we are managing GPU memory, we need to make a copy of the ensemble on the GPU. For GPU allocated ensembles we
73  // need to use an object of type deviceEnsemble. Only
74  // basic properties of a deviceEnsemble is accessible on
75  // the host like nbod() and nsys(). Note that you cannot
76  // read the data in a deviceEnsemble on the host.
77  // The following line uses cudaMalloc to allocate memory
78  // for an ensemble of the same size as ens on the GPU.
79  // The uses some cudaMemcpy calls to copy the ensemble
80  // to the GPU.
81  deviceEnsemble device_ens = ens.cloneTo<deviceEnsemble>();
82 
83  // To set the ensemble for the integrator we need to use
84  // a different version of integrator::set_ensemble that
85  // takes two parameters. The simple version of set_ensemble
86  // makes a copy of the given ensemble on the GPU.
87  //
88  // We need to provide the host and device ensemble.
89  // The integrator will keep a reference to the
90  // ensembles.
91  integ->set_ensemble( ens, device_ens );
92 
93  // This time we do more clever trick for setting the
94  // destination time. If we set the destination time
95  // to a predefined value and the ensemble is already
96  // past that time, nothing is going to happen. Instead
97  // we take the median of times of the systems and
98  // add a predefined value to that.
99  //
100  const double integration_time = 5 * 2 * M_PI ;
101  const double begin_time = ens.time_ranges().median ;
102  const double destination_time = begin_time + integration_time;
103  integ->set_destination_time ( destination_time );
104 
105  SYNC;
106 
107  // Now we can launch the integration many times
108  // without downloading the results. The
109  // systems won't go past the destination time
110  // but we have to integrate many times.
111  for(int i= 0; i < 10; i++ ){
112  integ->core_integrate();
113  }
114 
115  // Before we can use the results we have to
116  // download the results. The following call
117  // translates to some cudaMemcpy calls
118  device_ens.copyTo( ens );
119 
120  // TODO: Do something better with the data
121  // find_max_energy_conservation_error is a utility function that compares
122  // two ensemble of systems. We compare our working ensemble ens to the
123  // unchanged ensemble ref.
124  double max_deltaE = find_max_energy_conservation_error(ens, ref );
125  std::cout << "Max Energy Conservation Error = " << max_deltaE << std::endl;
126 
127 }
128 // To find the complete listing of this tutorial look at \ref src/tutorials/tutorial_gpu.cpp in the source code repository.