/home/users/khuck/src/octotiger/src/node_server_actions_3.cpp

Line% of fetchesSource
1  
#include "node_server.hpp"
2  
#include "node_client.hpp"
3  
#include "future.hpp"
4  
#include "options.hpp"
5  
#include "util.hpp"
6  
7  
#include <hpx/include/run_as.hpp>
8  
#include <hpx/include/lcos.hpp>
9  
#include <hpx/include/util.hpp>
10  
11  
extern options opts;
12  
13  
typedef node_server::send_gravity_boundary_action send_gravity_boundary_action_type;
14  
HPX_REGISTER_ACTION(send_gravity_boundary_action_type);
15  
16  
hpx::future<void> node_client::send_gravity_boundary(gravity_boundary_type&& data,
17  
    const geo::direction& dir, bool monopole) const {
18  
    return hpx::async<typename node_server::send_gravity_boundary_action>(get_gid(),
19  
        std::move(data), dir, monopole);
20  
}
21  
22  
void node_server::recv_gravity_boundary(gravity_boundary_type&& bdata,
23  
    const geo::direction& dir, bool monopole) {
24  
    neighbor_gravity_type tmp;
25  
    tmp.data = std::move(bdata);
26  
    tmp.is_monopole = monopole;
27  
    tmp.direction = dir;
28  
    neighbor_gravity_channels[dir].set_value(std::move(tmp));
29  
}
30  
31  
typedef node_server::send_gravity_expansions_action send_gravity_expansions_action_type;
32  
HPX_REGISTER_ACTION(send_gravity_expansions_action_type);
33  
34  
void node_server::recv_gravity_expansions(expansion_pass_type&& v) {
35  
    parent_gravity_channel.set_value(std::move(v));
36  
}
37  
38  
hpx::future<void> node_client::send_gravity_expansions(expansion_pass_type&& data) const {
39  
    return hpx::async<typename node_server::send_gravity_expansions_action>(get_gid(),
40  
        std::move(data));
41  
}
42  
43  
typedef node_server::send_gravity_multipoles_action send_gravity_multipoles_action_type;
44  
HPX_REGISTER_ACTION(send_gravity_multipoles_action_type);
45  
46  
hpx::future<void> node_client::send_gravity_multipoles(multipole_pass_type&& data,
47  
    const geo::octant& ci) const {
48  
    return hpx::async<typename node_server::send_gravity_multipoles_action>(get_gid(),
49  
        std::move(data), ci);
50  
}
51  
52  
void node_server::recv_gravity_multipoles(multipole_pass_type&& v,
53  
    const geo::octant& ci) {
54  
    child_gravity_channels[ci].set_value(std::move(v));
55  
}
56  
57  
typedef node_server::send_hydro_boundary_action send_hydro_boundary_action_type;
58  
HPX_REGISTER_ACTION(send_hydro_boundary_action_type);
59  
60  
hpx::future<void> node_client::send_hydro_boundary(std::vector<real>&& data,
61  
    const geo::direction& dir) const {
62  
    return hpx::async<typename node_server::send_hydro_boundary_action>(get_gid(),
63  
        std::move(data), dir);
64  
}
65  
66  
void node_server::recv_hydro_boundary(std::vector<real>&& bdata,
67  
    const geo::direction& dir) {
68  
    sibling_hydro_type tmp;
69  
    tmp.data = std::move(bdata);
70  
    tmp.direction = dir;
71  
    sibling_hydro_channels[dir].set_value(std::move(tmp));
72  
}
73  
74  
typedef node_server::send_hydro_children_action send_hydro_children_action_type;
75  
HPX_REGISTER_ACTION(send_hydro_children_action_type);
76  
77  
void node_server::recv_hydro_children(std::vector<real>&& data, const geo::octant& ci) {
78  
    child_hydro_channels[ci].set_value(std::move(data));
79  
}
80  
81  
hpx::future<void> node_client::send_hydro_children(std::vector<real>&& data,
82  
    const geo::octant& ci) const {
83  
    return hpx::async<typename node_server::send_hydro_children_action>(get_gid(),
84  
        std::move(data), ci);
85  
}
86  
87  
typedef node_server::send_hydro_flux_correct_action send_hydro_flux_correct_action_type;
88  
HPX_REGISTER_ACTION(send_hydro_flux_correct_action_type);
89  
90  
hpx::future<void> node_client::send_hydro_flux_correct(std::vector<real>&& data,
91  
    const geo::face& face,
92  
    const geo::octant& ci) const {
93  
    return hpx::async<typename node_server::send_hydro_flux_correct_action>(get_gid(),
94  
        std::move(data), face, ci);
95  
}
96  
97  
void node_server::recv_hydro_flux_correct(std::vector<real>&& data, const geo::face& face,
98  
    const geo::octant& ci) {
99  
    const geo::quadrant index(ci, face.get_dimension());
100  
    niece_hydro_channels[face][index].set_value(std::move(data));
101  
}
102  
103  
typedef node_server::line_of_centers_action line_of_centers_action_type;
104  
HPX_REGISTER_ACTION(line_of_centers_action_type);
105  
106  
hpx::future<line_of_centers_t> node_client::line_of_centers(
107  
    const std::pair<space_vector, space_vector>& line) const {
108  
    return hpx::async<typename node_server::line_of_centers_action>(get_gid(), line);
109  
}
110  
111  
void output_line_of_centers(FILE* fp, const line_of_centers_t& loc) {
112  
    for (integer i = 0; i != loc.size(); ++i) {
113  
        fprintf(fp, "%e ", loc[i].first);
114  
        for (integer j = 0; j != NF + NGF; ++j) {
115  
            fprintf(fp, "%e ", loc[i].second[j]);
116  
        }
117  
        fprintf(fp, "\n");
118  
    }
119  
}
120  
121  
line_of_centers_t node_server::line_of_centers(
122  
    const std::pair<space_vector, space_vector>& line) const {
123  
    std::list < hpx::future < line_of_centers_t >> futs;
124  
    line_of_centers_t return_line;
125  
    if (is_refined) {
126  
        for (integer ci = 0; ci != NCHILD; ++ci) {
127  
            futs.push_back(children[ci].line_of_centers(line));
128  
        }
129  
        std::map<real, std::vector<real>> map;
130  
        for (auto&& fut : futs) {
131  
            auto tmp = fut.get();
132  
            for (integer ii = 0; ii != tmp.size(); ++ii) {
133  
                if (map.find(tmp[ii].first) == map.end()) {
134  
                    map.emplace(std::move(tmp[ii]));
135  
                }
136  
            }
137  
        }
138  
        return_line.resize(map.size());
139  
        std::move(map.begin(), map.end(), return_line.begin());
140  
    } else {
141  
        return_line = grid_ptr->line_of_centers(line);
142  
    }
143  
144  
    return return_line;
145  
}
146  
147  
void line_of_centers_analyze(const line_of_centers_t& loc, real omega,
148  
    std::pair<real, real>& rho1_max, std::pair<real, real>& rho2_max,
149  
    std::pair<real, real>& l1_phi, std::pair<real, real>& l2_phi,
150  
    std::pair<real, real>& l3_phi, real& rho1_phi, real& rho2_phi) {
151  
152  
    for (auto& l : loc) {
153  
        ASSERT_NONAN(l.first);
154  
        for (integer f = 0; f != NF + NGF; ++f) {
155  
            ASSERT_NONAN(l.second[f]);
156  
        }
157  
    }
158  
159  
    rho1_max.second = rho2_max.second = 0.0;
160  
    integer rho1_maxi, rho2_maxi;
161  
    ///	printf( "LOCSIZE %i\n", loc.size());
162  
    for (integer i = 0; i != loc.size(); ++i) {
163  
        const real x = loc[i].first;
164  
        const real rho = loc[i].second[rho_i];
165  
        const real pot = loc[i].second[pot_i];
166  
        //	printf( "%e %e\n", x, rho);
167  
        if (rho1_max.second < rho) {
168  
            //	printf( "!\n");
169  
            rho1_max.second = rho;
170  
            rho1_max.first = x;
171  
            rho1_maxi = i;
172  
            real phi_eff = pot / ASSERT_POSITIVE(rho) - 0.5 * x * x * omega * omega;
173  
            rho1_phi = phi_eff;
174  
        }
175  
    }
176  
    for (integer i = 0; i != loc.size(); ++i) {
177  
        const real x = loc[i].first;
178  
        if (x * rho1_max.first < 0.0) {
179  
            const real rho = loc[i].second[rho_i];
180  
            const real pot = loc[i].second[pot_i];
181  
            if (rho2_max.second < rho) {
182  
                rho2_max.second = rho;
183  
                rho2_max.first = x;
184  
                rho2_maxi = i;
185  
                real phi_eff = pot / ASSERT_POSITIVE(rho) - 0.5 * x * x * omega * omega;
186  
                rho2_phi = phi_eff;
187  
            }
188  
        }
189  
    }
190  
    l1_phi.second = -std::numeric_limits < real > ::max();
191  
    l2_phi.second = -std::numeric_limits < real > ::max();
192  
    l3_phi.second = -std::numeric_limits < real > ::max();
193  
    for (integer i = 0; i != loc.size(); ++i) {
194  
        const real x = loc[i].first;
195  
        const real rho = loc[i].second[rho_i];
196  
        const real pot = loc[i].second[pot_i];
197  
        real phi_eff = pot / ASSERT_POSITIVE(rho) - 0.5 * x * x * omega * omega;
198  
        if (x > std::min(rho1_max.first, rho2_max.first)
199  
            && x < std::max(rho1_max.first, rho2_max.first)) {
200  
            if (phi_eff > l1_phi.second) {
201  
                l1_phi.second = phi_eff;
202  
                l1_phi.first = x;
203  
            }
204  
        } else if (std::abs(x) > std::abs(rho2_max.first) && x * rho2_max.first > 0.0) {
205  
            if (phi_eff > l2_phi.second) {
206  
                l2_phi.second = phi_eff;
207  
                l2_phi.first = x;
208  
            }
209  
        } else if (std::abs(x) > std::abs(rho1_max.first)) {
210  
            if (phi_eff > l3_phi.second) {
211  
                l3_phi.second = phi_eff;
212  
                l3_phi.first = x;
213  
            }
214  
        }
215  
    }
216  
}
217  
218  
typedef node_server::start_run_action start_run_action_type;
219  
HPX_REGISTER_ACTION(start_run_action_type);
220  
221  
hpx::future<void> node_client::start_run(bool b) const {
222  
    return hpx::async<typename node_server::start_run_action>(get_gid(), b);
223  
}
224  
225  
void node_server::start_run(bool scf) {
226  
    timings::scope ts(timings_, timings::time_total);
227  
    integer output_cnt;
228  
229  
    if (!hydro_on) {
230  
        save_to_file("X.chk");
231  
        diagnostics();
232  
        return;
233  
    }
234  
    printf("%e %e\n", grid::get_A(), grid::get_B());
235  
    if (scf) {
236  
        run_scf();
237  
        set_pivot();
238  
        printf("Adjusting velocities:\n");
239  
        auto diag = diagnostics();
240  
        space_vector dv;
241  
        dv[XDIM] = -diag.grid_sum[sx_i] / diag.grid_sum[rho_i];
242  
        dv[YDIM] = -diag.grid_sum[sy_i] / diag.grid_sum[rho_i];
243  
        dv[ZDIM] = -diag.grid_sum[sz_i] / diag.grid_sum[rho_i];
244  
        this->velocity_inc(dv);
245  
        save_to_file("scf.chk");
246  
    }
247  
248  
    printf("Starting...\n");
249  
    solve_gravity(false);
250  
    int ngrids = regrid(me.get_gid(), false);
251  
252  
    real output_dt = opts.output_dt;
253  
254  
    printf("OMEGA = %e, output_dt = %e\n", grid::get_omega(), output_dt);
255  
    real& t = current_time;
256  
    integer step_num = 0;
257  
258  
    auto fut_ptr = me.get_ptr();
259  
    node_server* root_ptr = fut_ptr.get();
260  
261  
    output_cnt = root_ptr->get_rotation_count() / output_dt;
262  
    hpx::future<void> diag_fut = hpx::make_ready_future();
263  
    profiler_output (stdout);
264  
    real bench_start, bench_stop;
265  
    while (current_time < opts.stop_time) {
266  
        if (step_num > opts.stop_step)
267  
            break;
268  
269  
        auto time_start = std::chrono::high_resolution_clock::now();
270  
        if (!opts.disable_output && root_ptr->get_rotation_count() / output_dt >= output_cnt) {
271  
            //	if (step_num != 0) {
272  
273  
            char fname[33];    // 21 bytes for int (max) + some leeway
274  
            sprintf(fname, "X.%i.chk", int(output_cnt));
275  
            save_to_file(fname);
276  
277  
            sprintf(fname, "X.%i.silo", int(output_cnt));
278  
            output(fname, output_cnt, false);
279  
280  
            //	SYSTEM(std::string("cp *.dat ./dat_back/\n"));
281  
            //	}
282  
            ++output_cnt;
283  
284  
        }
285  
        if (step_num == 0) {
286  
            bench_start = hpx::util::high_resolution_clock::now() / 1e9;
287  
        }
288  
289  
        //	break;
290  
        auto ts_fut = hpx::async([=]() {return timestep_driver();});
291  
        step().get();
292  
        real dt = ts_fut.get();
293  
        real omega_dot = 0.0, omega = 0.0, theta = 0.0, theta_dot = 0.0;
294  
        omega = grid::get_omega();
295  
        if (opts.problem == DWD) {
296  
            auto diags = diagnostics();
297  
298  
            const real dx = diags.secondary_com[XDIM] - diags.primary_com[XDIM];
299  
            const real dy = diags.secondary_com[YDIM] - diags.primary_com[YDIM];
300  
            const real dx_dot = diags.secondary_com_dot[XDIM]
301  
                - diags.primary_com_dot[XDIM];
302  
            const real dy_dot = diags.secondary_com_dot[YDIM]
303  
                - diags.primary_com_dot[YDIM];
304  
            theta = atan2(dy, dx);
305  
            omega = grid::get_omega();
306  
            theta_dot = (dy_dot * dx - dx_dot * dy) / (dx * dx + dy * dy) - omega;
307  
            const real w0 = grid::get_omega() * 100.0;
308  
            const real theta_dot_dot = (2.0 * w0 * theta_dot + w0 * w0 * theta);
309  
            omega_dot = theta_dot_dot;
310  
            omega += omega_dot * dt;
311  
//            omega_dot += theta_dot_dot*dt;
312  
            grid::set_omega(omega);
313  
        }
314  
        double time_elapsed = std::chrono::duration_cast<std::chrono::duration<double>>(
315  
            std::chrono::high_resolution_clock::now() - time_start).count();
316  
317  
        // run output on separate thread
318  
        if (!opts.disable_output)
319  
        {
320  
            hpx::threads::run_as_os_thread([=]()
321  
            {
322  
                FILE* fp = fopen( "step.dat", "at");
323  
                fprintf(fp, "%i %e %e %e %e %e %e %e %e %i\n",
324  
                    int(step_num), double(t), double(dt), time_elapsed, rotational_time,
325  
                    theta, theta_dot, omega, omega_dot, int(ngrids));
326  
                fclose(fp);
327  
            });     // do not wait for it fo finish
328  
        }
329  
330  
        printf("%i %e %e %e %e %e %e %e %e\n", int(step_num), double(t), double(dt),
331  
            time_elapsed, rotational_time, theta, theta_dot, omega, omega_dot);
332  
333  
//		t += dt;
334  
        ++step_num;
335  
336  
        if (step_num % refinement_freq() == 0) {
337  
            ngrids = regrid(me.get_gid(), false);
338  
339  
            // run output on separate thread
340  
            auto need_break = hpx::threads::run_as_os_thread([&]()
341  
            {
342  
                FILE* fp = fopen("profile.txt", "wt");
343  
                profiler_output(fp);
344  
                fclose(fp);
345  
346  
                //		set_omega_and_pivot();
347  
                bench_stop = hpx::util::high_resolution_clock::now() / 1e9;
348  
                if (scf || opts.bench) {
349  
                    printf("Total time = %e s\n", double(bench_stop - bench_start));
350  
                    FILE* fp = fopen("bench.dat", "at");
351  
                    fprintf(fp, "%i %e\n", int(hpx::find_all_localities().size()),
352  
                        double(bench_stop - bench_start));
353  
                    fclose(fp);
354  
                    return true;
355  
                }
356  
                return false;
357  
            });
358  
            if (need_break.get())
359  
                break;
360  
        }
361  
        //		set_omega_and_pivot();
362  
        if (scf) {
363  
            bench_stop = hpx::util::high_resolution_clock::now() / 1e9;
364  
            printf("Total time = %e s\n", double(bench_stop - bench_start));
365  
            //	FILE* fp = fopen( "bench.dat", "at" );
366  
            //	fprintf( fp, "%i %e\n", int(hpx::find_all_localities().size()), double(bench_stop - bench_start));
367  
            //	fclose(fp);
368  
            break;
369  
        }
370  
    }
371  
    compare_analytic();
372  
    output("final.silo", output_cnt, true);
373  
}
374  
375  
typedef node_server::step_action step_action_type;
376  
HPX_REGISTER_ACTION(step_action_type);
377  
378  
hpx::future<void> node_client::step() const {
379  
    return hpx::async<typename node_server::step_action>(get_gid());
380  
}
381  
382  
hpx::future<void> node_server::refined_step(std::vector<hpx::future<void>> child_futs) {
383  
    timings::scope ts(timings_, timings::time_computation);
384  
    const real dx = TWO * grid::get_scaling_factor() / real(INX << my_location.level());
385  
    real cfl0 = cfl;
386  
387  
    // FIXME: is this correct? ('a' was never re-initialized for refined == true)
388  
    real a = std::numeric_limits<real>::min();
389  
390  
    dt_ = cfl0 * dx / a;
391  
392  
    hpx::future<void> fut = all_hydro_bounds();
393  
    for (integer rk = 0; rk < NRK; ++rk) {
394  
395  
        fut = fut.then(
396  
            [rk, this](hpx::future<void> f)
397  
            {
398  
                f.get();        // propagate exceptions
399  
400  
                if (rk == 0) {
401  
                    local_timestep_channel.set_value(dt_);
402  
                }
403  
404  
                compute_fmm(DRHODT, false);
405  
406  
                if (rk == 0) {
407  
                    dt_ = global_timestep_channel.get_future().get();
408  
                }
409  
410  
                compute_fmm(RHO, true);
411  
                return all_hydro_bounds();
412  
            });
413  
    }
414  
415  
    return hpx::dataflow(
416  
        [this](hpx::future<void> f, std::vector<hpx::future<void>> children)
417  
        {
418  
            // propagate exceptions
419  
            f.get();
420  
            for (auto& f: children)
421  
            {
422  
                if (f.has_exception())
423  
                    f.get();
424  
            }
425  
426  
            grid_ptr->dual_energy_update();
427  
            current_time += dt_;
428  
            if (grid::get_omega() != 0.0) {
429  
                rotational_time += grid::get_omega() * dt_;
430  
            } else {
431  
                rotational_time = current_time;
432  
            }
433  
            ++step_num;
434  
        },
435  
        std::move(fut), std::move(child_futs));
436  
}
437  
438  
hpx::future<void> node_server::nonrefined_step() {
439  
    timings::scope ts(timings_, timings::time_computation);
440  
441  
    real cfl0 = cfl;
442  
    dt_ = ZERO;
443  
444  
    hpx::future<void> fut = all_hydro_bounds();
445  
446  
    grid_ptr->store();
447  
448  
    for (integer rk = 0; rk < NRK; ++rk) {
449  
450  
        fut = fut.then(
451  
            [rk, cfl0, this](hpx::future<void> f)
452  
            {
453  
                f.get();        // propagate exceptions
454  
455  
                grid_ptr->reconstruct();
456  
                real a = grid_ptr->compute_fluxes();
457  
458  
                hpx::future<void> fut_flux = exchange_flux_corrections();
459  
460  
                if (rk == 0) {
461  
                    const real dx = TWO * grid::get_scaling_factor() /
462  
                        real(INX << my_location.level());
463  
                    dt_ = cfl0 * dx / a;
464  
                    local_timestep_channel.set_value(dt_);
465  
                }
466  
467  
                return fut_flux.then(
468  
                    [rk, this](hpx::future<void> f)
469  
                    {
470  
                        f.get();        // propagate exceptions
471  
472  
                        grid_ptr->compute_sources(current_time);
473  
                        grid_ptr->compute_dudt();
474  
475  
                        compute_fmm(DRHODT, false);
476  
477  
                        if (rk == 0) {
478  
                            dt_ = global_timestep_channel.get_future().get();
479  
                        }
480  
481  
                        grid_ptr->next_u(rk, current_time, dt_);
482  
483  
                        compute_fmm(RHO, true);
484  
                        return all_hydro_bounds();
485  
                    });
486  
            });
487  
    }
488  
489  
    return fut.then(
490  
        [this](hpx::future<void> f)
491  
        {
492  
            f.get();        // propagate exceptions
493  
494  
            grid_ptr->dual_energy_update();
495  
496  
            current_time += dt_;
497  
            if (grid::get_omega() != 0.0) {
498  
                rotational_time += grid::get_omega() * dt_;
499  
            } else {
500  
                rotational_time = current_time;
501  
            }
502  
            ++step_num;
503  
        });
504  
}
505  
506  
hpx::future<void> node_server::step() {
507  
    grid_ptr->set_coordinates();
508  
509  
    if (is_refined) {
510  
        std::vector<hpx::future<void>> child_futs;
511  
        child_futs.reserve(NCHILD);
512  
        for (integer ci = 0; ci != NCHILD; ++ci) {
513  
            child_futs.push_back(children[ci].step());
514  
        }
515  
        return refined_step(std::move(child_futs));
516  
    }
517  
518  
    return nonrefined_step();
519  
}
520  
521  
typedef node_server::timestep_driver_ascend_action timestep_driver_ascend_action_type;
522  
HPX_REGISTER_ACTION(timestep_driver_ascend_action_type);
523  
524  
hpx::future<void> node_client::timestep_driver_ascend(real dt) const {
525  
    return hpx::async<typename node_server::timestep_driver_ascend_action>(get_gid(), dt);
526  
}
527  
528  
void node_server::timestep_driver_ascend(real dt) {
529  
    global_timestep_channel.set_value(dt);
530  
    if (is_refined) {
531  
        std::vector<hpx::future<void>> futs;
532  
        futs.reserve(children.size());
533  
        for(auto& child: children) {
534  
            futs.push_back(child.timestep_driver_ascend(dt));
535  
        }
536  
        wait_all_and_propagate_exceptions(futs);
537  
    }
538  
}
539  
540  
typedef node_server::timestep_driver_descend_action timestep_driver_descend_action_type;
541  
HPX_REGISTER_ACTION(timestep_driver_descend_action_type);
542  
543  
hpx::future<real> node_client::timestep_driver_descend() const {
544  
    return hpx::async<typename node_server::timestep_driver_descend_action>(get_gid());
545  
}
546  
547  
hpx::future<real> node_server::timestep_driver_descend() {
548  
    if (is_refined) {
549  
        std::vector<hpx::future<real>> futs;
550  
        futs.reserve(children.size() + 1);
551  
        for(auto& child: children) {
552  
            futs.push_back(child.timestep_driver_descend());
553  
        }
554  
        futs.push_back(local_timestep_channel.get_future());
555  
556  
        return hpx::dataflow(
557  
            [](std::vector<hpx::future<real>> dts_fut) -> double
558  
            {
559  
                auto dts = hpx::util::unwrapped(dts_fut);
560  
                return *std::min_element(dts.begin(), dts.end());
561  
            },
562  
            std::move(futs));
563  
    } else {
564  
        return local_timestep_channel.get_future();
565  
    }
566  
}
567  
568  
typedef node_server::timestep_driver_action timestep_driver_action_type;
569  
HPX_REGISTER_ACTION(timestep_driver_action_type);
570  
571  
hpx::future<real> node_client::timestep_driver() const {
572  
    return hpx::async<typename node_server::timestep_driver_action>(get_gid());
573  
}
574  
575  
real node_server::timestep_driver() {
576  
    const real dt = timestep_driver_descend().get();
577  
    timestep_driver_ascend(dt);
578  
    return dt;
579  
}
580  
581  
typedef node_server::velocity_inc_action velocity_inc_action_type;
582  
HPX_REGISTER_ACTION(velocity_inc_action_type);
583  
584  
hpx::future<void> node_client::velocity_inc(const space_vector& dv) const {
585  
    return hpx::async<typename node_server::velocity_inc_action>(get_gid(), dv);
586  
}
587  
588  
void node_server::velocity_inc(const space_vector& dv) {
589  
    if (is_refined) {
590  
        std::vector<hpx::future<void>> futs;
591  
        futs.reserve(NCHILD);
592  
        for (auto& child : children) {
593  
            futs.push_back(child.velocity_inc(dv));
594  
        }
595  
        wait_all_and_propagate_exceptions(futs);
596  
    } else {
597  
        grid_ptr->velocity_inc(dv);
598  
    }
599  
}
600  
601  

Copyright (c) 2006-2012 Rogue Wave Software, Inc. All Rights Reserved.
Patents pending.