ABACUS/src/INTEG/Integration_par.cc

156 lines
5.7 KiB
C++

/****************************************************************
This software is part of J.-S. Caux's C++ library.
Copyright (c) J.-S. Caux.
-----------------------------------------------------------
Integration_par.cc
Defines all functions to perform integration of functions, parallel (MPI).
******************************************************************/
#include "ABACUS.h"
#include "mpi.h"
using namespace std;
namespace ABACUS {
void Improve_estimate_par (MPI_Comm comm, Integral_data& integdat, DP (*function) (Vect_DP, I_table),
Vect_DP& args, int arg_to_integ, I_table Itable, int max_nr_pts)
{
// This function is only ever called by process rank 0.
// We generate a max of 3* n_vals points
data_pt* new_data = new data_pt[3* integdat.integ_res.n_vals];
DP* new_abs_d2f_dx = new DP[integdat.integ_res.n_vals];
// Check points in batches of 3; if needed, improve
int threei = 0;
int index_new = 0;
int i, j;
integdat.integ_res.abs_prec = 0.0;
integdat.integ_res.integ_est = 0.0;
DP new_max_abs_d2f_dx = 0.0;
for (i = 0; i < integdat.integ_res.n_vals/3; ++i) {
threei = 3 * i;
if (integdat.abs_d2f_dx[i] <= 0.1 * integdat.max_abs_d2f_dx
|| index_new + integdat.integ_res.n_vals - threei > max_nr_pts) {
// simply transfer the data points into new_data
new_abs_d2f_dx[index_new/3] = integdat.abs_d2f_dx[i];
new_max_abs_d2f_dx = ABACUS::max(new_max_abs_d2f_dx, new_abs_d2f_dx[index_new/3]);
for (j = 0; j < 3; ++j) {
new_data[index_new].x = integdat.data[threei + j].x;
new_data[index_new].f = integdat.data[threei + j].f;
new_data[index_new].dx = integdat.data[threei + j].dx;
integdat.integ_res.integ_est += new_data[index_new].dx * new_data[index_new].f;
index_new++;
}
integdat.integ_res.abs_prec += abs_d2f_dx[i];
}
else { // create six new entries and transfer the three existing ones
new_data[index_new].dx = integdat.data[threei].dx/3.0;
for (j = 1; j < 9; ++j) new_data[index_new + j].dx = new_data[index_new].dx;
new_data[index_new].x = integdat.data[threei].x - new_data[index_new].dx;
new_data[index_new + 1].x = integdat.data[threei].x;
new_data[index_new + 2].x = integdat.data[threei].x + new_data[index_new].dx;
new_data[index_new + 3].x = integdat.data[threei + 1].x - new_data[index_new].dx;
new_data[index_new + 4].x = integdat.data[threei + 1].x;
new_data[index_new + 5].x = integdat.data[threei + 1].x + new_data[index_new].dx;
new_data[index_new + 6].x = integdat.data[threei + 2].x - new_data[index_new].dx;
new_data[index_new + 7].x = integdat.data[threei + 2].x;
new_data[index_new + 8].x = integdat.data[threei + 2].x + new_data[index_new].dx;
args[arg_to_integ] = new_data[index_new].x;
new_data[index_new].f = function(args, Itable);
new_data[index_new + 1].f = integdat.data[threei].f;
args[arg_to_integ] = new_data[index_new + 2].x;
new_data[index_new + 2].f = function(args, Itable);
args[arg_to_integ] = new_data[index_new + 3].x;
new_data[index_new + 3].f = function(args, Itable);
new_data[index_new + 4].f = integdat.data[threei + 1].f;
args[arg_to_integ] = new_data[index_new + 5].x;
new_data[index_new + 5].f = function(args, Itable);
args[arg_to_integ] = new_data[index_new + 6].x;
new_data[index_new + 6].f = function(args, Itable);
new_data[index_new + 7].f = integdat.data[threei + 2].f;
args[arg_to_integ] = new_data[index_new + 8].x;
new_data[index_new + 8].f = function(args, Itable);
new_abs_d2f_dx[index_new/3] = fabs(new_data[index_new].dx * (new_data[index_new].f - 2.0 * new_data[index_new + 1].f + new_data[index_new + 2].f));
new_abs_d2f_dx[index_new/3 + 1] = fabs(new_data[index_new].dx * (new_data[index_new + 3].f - 2.0 * new_data[index_new + 4].f + new_data[index_new + 5].f));
new_abs_d2f_dx[index_new/3 + 2] = fabs(new_data[index_new].dx * (new_data[index_new + 6].f - 2.0 * new_data[index_new + 7].f + new_data[index_new + 8].f));
new_max_abs_d2f_dx = ABACUS::max(new_max_abs_d2f_dx, new_abs_d2f_dx[index_new/3]);
new_max_abs_d2f_dx = ABACUS::max(new_max_abs_d2f_dx, new_abs_d2f_dx[index_new/3 + 1]);
new_max_abs_d2f_dx = ABACUS::max(new_max_abs_d2f_dx, new_abs_d2f_dx[index_new/3 + 2]);
integdat.integ_res.integ_est += new_data[index_new].dx * (new_data[index_new].f + new_data[index_new + 1].f + new_data[index_new + 2].f
+ new_data[index_new + 3].f + new_data[index_new + 4].f + new_data[index_new + 5].f
+ new_data[index_new + 6].f + new_data[index_new + 7].f + new_data[index_new + 8].f);
integdat.integ_res.abs_prec += new_abs_d2f_dx[index_new/3] + new_abs_d2f_dx[index_new/3 + 1] + new_abs_d2f_dx[index_new/3 + 2];
index_new += 9;
} // else
} // for (i < nvals/3)
integdat.integ_res.rel_prec = integdat.integ_res.abs_prec/integdat.integ_res.integ_est;
integdat.integ_res.n_vals = index_new;
delete[] integdat.data;
integdat.data = new_data;
integdat.max_abs_d2f_dx = new_max_abs_d2f_dx;
delete[] integdat.abs_d2f_dx;
integdat.abs_d2f_dx = new_abs_d2f_dx;
return;
}
Integral_result Integrate_optimal_par_using_table (MPI_Comm comm, DP (*function) (Vect_DP, I_table),
Vect_DP& args, int arg_to_integ,
I_table Itable, DP xmin, DP xmax,
DP req_rel_prec, DP req_abs_prec, int max_nr_pts, ofstream& outfile)
{
if (xmax < xmin) ABACUSerror("Use xmax > xmin in Integrate.");
Integral_data integ_dat (function, args, arg_to_integ, Itable, xmin, xmax);
while ((integ_dat.integ_res.rel_prec > req_rel_prec || integ_dat.integ_res.abs_prec > req_abs_prec)
&& integ_dat.integ_res.n_vals < max_nr_pts) {
Improve_estimate_par (comm, integ_dat, function, args, arg_to_integ, Itable, max_nr_pts);
integ_dat.Save (outfile);
}
return(integ_dat.integ_res);
}
} // namespace ABACUS