void prepare_integrator () { // Initialize Integrator DEBUG_OUTPUT(2, "Initializing integrator" ); double begin_time = initial_ens.time_ranges().average; double destination_time = cfg.optional("destination_time", begin_time + 10 * M_PI ); integ = integrator::create(cfg); integ->set_ensemble(current_ens); integ->set_destination_time ( destination_time ); SYNC; }
// Since our program is short, we can put everything in the main function. int main(int argc, char* argv[]){ // First we create our reference ensemble. We use the automatic generation using generate_ensemble function // This function creates a very stable ensemble of systems for us. defaultEnsemble ref = generate_ensemble(cfg); // We have to make a copy of initial conditions. We would like to compare the results to initial conditions // after integration defaultEnsemble ens = ref.clone(); // Initialize Swarm library. Basically, it initializes CUDA system and default logging system. swarm::init(cfg); // Select and create the integrator. While you can create an integrator by calling its constructor directly. // It is recommended to use integrator::create since it gives you more flexibility at runtime. // The create function looks in the swarm library and finds the integrator you requested from // the list of available plugins. Pintegrator integ = integrator::create(cfg); // Now we set-up the integrator for integrating. // // First set the ensemble. For a GPU integrator, the GPU memory will be allocated. integ->set_ensemble(ens); // Now set the destination time where we want to stop the integration. integ->set_destination_time ( destination_time ); // Need to synchronize because \ref integrator::set_ensemble may upload data to GPU. SYNC; // Now that everything is set-up, it is safe to pull the trigger and // call the integrate method on integrator. Note that since we didn't set // a logger for the integrator, it will use the default logging system. integ->integrate(); // Need to synchronize because integrate is a GPU call. SYNC; // Once the integration done, we need to examine the data. The easiest // check is to see if the systems have preserved energy. // // find_max_energy_conservation_error is a utility function that compares // two ensemble of systems. We compare our working ensemble ens to the // unchanged ensemble ref. double max_deltaE = find_max_energy_conservation_error(ens, ref ); std::cout << "Max Energy Conservation Error = " << max_deltaE << std::endl; // This concludes the program, at this point you will need to clean up the data and ensembles. // But most of Swarm-NG objects are stored in reference-counter pointers and will be automatically // deallocated by C++ runtime library. return 0; }
void stability_test() { defaultEnsemble &ens = current_ens; double begin_time = ens.time_ranges().median; double destination_time = cfg.optional("destination_time", begin_time + 10 * M_PI ); double interval = cfg.optional("interval", (destination_time-begin_time) ) ; double logarithmic = cfg.optional("logarithmic", 0 ) ; double allowed_deltaE = cfg.optional("allowed_deltaE", 0.01 ); if(destination_time < begin_time ) ERROR("Destination time should be larger than begin time"); if(interval < 0) ERROR("Interval cannot be negative"); if(interval < 0.001) ERROR("Interval too small"); if(logarithmic != 0 && logarithmic <= 1) ERROR("logarithm base should be greater than 1"); std::cout << "Time, Energy Conservation Factor (delta E/E), Active Systems" << std::endl; for(double time = begin_time; time < destination_time; ) { if(logarithmic > 1) time = (time > 0) ? time * logarithmic : interval; else time += interval; double effective_time = min(time,destination_time); integ->set_destination_time ( effective_time ); DEBUG_OUTPUT(2, "Integrator ensemble" ); integ->integrate(); SYNC; DEBUG_OUTPUT(2, "Check energy conservation" ); ensemble::range_t deltaE_range = energy_conservation_error_range(ens, initial_ens ); int active_systems = ens.nsys() - number_of_disabled_systems( ens ); std::cout << effective_time << ", " << deltaE_range.max << ", " << deltaE_range.median << ", " << active_systems << std::endl; if(deltaE_range.median > allowed_deltaE){ INFO_OUTPUT(0, "At least half of systems are too unstable to conserve energy. dE/E: " << deltaE_range.median << std::endl ); exit(1); } } }
int main(int argc, char* argv[] ) { // We keep it simple, later on one can use boost::program_options to // have more options // but now we only use two configuration files. It is because the // initial conditions configuration file can get really big and // it has very little to do with other configuration options. if(argc < 3) cout << "Usage: montecarlo_ecclimit <integration configuration> <initial conditions configuration>" << endl; // First one is the configuration for integration string integ_configfile = argv[1]; // the second one is the configuration for generating // initial conditions it is used by \ref generate_ensemble_with_randomized_initial_conditions string initc_configfile = argv[2]; cfg = config::load(integ_configfile); // 1.read keplerian coordinates from a file // 2.generate guesses based on the keplerian coordinates // 3.convert keplerian coordinates to an ensemble // The following line that is taken from swarm_tutorial_montecarlo.cpp // does the first three steps. Its pretty amazing. defaultEnsemble ens ; if( cfg.count("input") ) { ens = snapshot::load(cfg["input"]); } else { ens = generate_ensemble_with_randomized_initial_conditions( config::load(initc_configfile) ); } // save the ensemble as a snapshot if(cfg.count("initial_snapshot")) { snapshot::save( ens, cfg["initial_snapshot"] ); } defaultEnsemble ens_init = ens.clone() ; std::vector<std::vector<double> > semimajor_axes_init = calc_semimajor_axes(ens); // We want to find the ones that are really stable, so we integrate for // a really long time and over time we get rid of unstable ones. double destination_time = cfg.optional("destination_time", 1.0E6); swarm::init(cfg); Pintegrator integ = integrator::create(cfg); integ->set_ensemble(ens); integ->set_destination_time ( destination_time ); // We can set the following two items if we really need // longer integrations before we stop for checking the // ensemble and saving snapshots. // one kernel call to allow for prompt CPU pruning of unstable systems int max_kernel_calls_per_integrate = cfg.optional("max_kernel_calls_per_integrate",1); // 10^2 inner orbits at 200 time steps per inner orbit int max_itterations_per_kernel_call = cfg.optional("max_itterations_per_kernel_call",20000); integ->set_max_attempts( max_kernel_calls_per_integrate ); integ->set_max_iterations ( max_itterations_per_kernel_call ); SYNC; // integrate ensemble // - drop the unstable ones as you go // - redistribute the systems for better efficiency // - save the results periodically // This can be an infitie loop. but we can always get out of this // the best way to do it is to use Ctrl-C. Further wecan // define Ctrl-C signal handler to get out // of this loop in a safe way. But we really want this loop // to run for a long time reactivate_systems(ens); // EBF Experiment trying to expose host log. swarm::log::ensemble(*(swarm::log::manager::default_log()->get_hostlog()),ens); integ->flush_log(); catch_ctrl_c(); while( number_of_active_systems(ens) > 0 && integration_loop_not_aborted_yet ) { // 1. Integrate, we could use core_integrate but the general integrate // saves all the headache. We should only use core_integrate if we are // going to do everything on GPU, but since we are saving a snapshot in // the middle, there's no point. It also has a nice for loop and can // to several kernel calls. integ->integrate(); // 2. CPU-based tests to identify systems that can be terminated int active_ones = number_of_active_systems(ens); const double deltaa_frac_threshold = cfg.optional("deltaa_frac_threshold", 0.5); disable_unstable_systems( ens, semimajor_axes_init, deltaa_frac_threshold ); // double med_deltaE = find_median_energy_conservation_error(ens, ens_init ); double max_deltaE = find_max_energy_conservation_error(ens, ens_init ); std::cerr << "# Time: " << ens.time_ranges().min << " " << ens.time_ranges().median << " " << ens.time_ranges().max << " Systems: " << ens.nsys() << ", " << active_ones << ", "; active_ones = number_of_active_systems(ens); std::cerr << active_ones << " max|dE/E|= " << max_deltaE << "\n"; // EBF Experiment trying to expose host log. swarm::log::ensemble_enabled(*(swarm::log::manager::default_log()->get_hostlog()),ens); integ->flush_log(); if (!cfg.count("input") && cfg.count("replace_unstable") ) { int nsys_to_replace = number_of_disabled_systems( ens ) ; if( nsys_to_replace >0 ) { replace_disabled_systems( ens ); integ->set_ensemble( ens ); } } else { // 3. Now we need to get rid of the inactive ones. There // should be some criteria, whatever it is we are // going to put it in a function and call it \ref needs_shrinking if ( needs_shrinking( ens ) ) { // Now this function will take care of trimming for us // We need to create a new ensemble of a smaller size // thats why we need to call set_ensemble again. because // the GPU ensemble should get recreated for us. // we need better memory management to safely allow // the following statement. Right now we don't have a // very good automatic memory management // std::cerr << "# Removing disabled systems\n"; ens = trim_disabled_systems( ens ); // std::cerr << "# Testing if ens has any systems left.\n"; if(ens.nsys()>0) { // std::cerr << "# Setting ensemble for integrator\n"; // WARNING: This appears to be the cause of SEGFAULT // if the ensemble is empty. integ->set_ensemble( ens ); } // std::cerr << "# Time: " << ens.time_ranges() << " Total Systems: " << ens.nsys() << " Active Systems: " << active_ones << ", "; // active_ones = number_of_active_systems(ens); // std::cerr << active_ones << "\n"; } } // std::cerr << std::endl; // 4. We need to save a snapshot in case system crashes or someone // gets tired of it and hits Ctrl-C // std::cerr << "# Saving snapshot\n"; save_snapshot( ens ); write_stable_systems(ens,ens_init); } // Now we are at the end of the system, before we examine // the output we need to // std::cerr << "# Removing disabled systems\n"; if(number_of_active_systems(ens)>0) { ens = trim_disabled_systems( ens ); // std::cerr << "# Saving snapshot\n"; save_snapshot( ens ); } write_stable_systems(ens,ens_init); }