Exemplo n.º 1
0
    virtual int exec(double* integral,double* error){
        cubature_integrand_wrapper c;
        c.params    = params;
        c.integrand = integrand;

        double xl[ndim];
        double xu[ndim];
        std::fill(xl,xl+ndim,0.); // unit cube!
        std::fill(xu,xu+ndim,1.); // unit cube!
        
        return pcubature(ncomp,cubature_integrand_wrapper::f,(void*) &c,
                        ndim,xl,xu,maxEval,epsabs,epsrel,err_norm,integral,error);
        }
Exemplo n.º 2
0
/*!
Returns average magnetic field over an area from point dipole(s).

\param [dipole_moments_positions] is a list of dipole moments and the
corresponding positions
\param [start] is the starting point of averaging
\param [dimensions] is a list of dimensions over which to integrate as
values in the range [0, 2], with rest of the dimensions as
values > 2. Dimensions over which to integrate must be listed
first and must be listed in ascending order.
\param [lengths] is a list of lengths for which to integrate from start
in dimensions at the corresponding index in dimensions
\param [maxEval] See http://ab-initio.mit.edu/wiki/index.php/Cubature
\param [reqAbsError] See http://ab-initio.mit.edu/wiki/index.php/Cubature
\param [reqRelError] See http://ab-initio.mit.edu/wiki/index.php/Cubature

Assumes Vector_T is a 3d Eigen vector or similar.

In case of error returns negative values for the accuracy of integration.

Example calculating a 1d integral in x dimension:
\code
Eigen::Vector3d integrated, error;

std::tie(
	integrated,
	error
) = get_dipole_field<Eigen::Vector3d>(
	// earth dipole centered at origin
	{{{0, 0, -7.94e22}, {0, 0, 0}}},
	// integrate from (1, 0, 0) earth radii
	{6.3712e6, 0, 0},
	// integrate in x dimension
	{0, 9, 9},
	// integrate for 1 earth radii in +x
	{6.3712e6, 0, 0}
);
\endcode

Example calculating a 2d integral in y and z dimensions:
\code
Eigen::Vector3d integrated, error;

std::tie(
	integrated,
	error
) = get_dipole_field<Eigen::Vector3d>(
	{{{0, 0, -7.94e22}, {0, 0, 0}}},
	{6.3712e6, 0, 0},
	// integrate in y and z dimensions
	{1, 2, 9},
	// integrate for 1 earth radii in +y and +z
	{0, 6.3712e6, 6.3712e6}
);
\endcode
*/
template <class Vector_T> std::pair<Vector_T, Vector_T> get_dipole_field(
	const std::vector<std::pair<Vector_T, Vector_T>>& dipole_moments_positions,
	const Vector_T& start,
	const std::array<size_t, 3>& dimensions,
	const Vector_T& lengths,
	const size_t maxEval = 0,
	const double reqAbsError = 0,
	const double reqRelError = 1e-6
) {
	static_assert(
		Vector_T::SizeAtCompileTime == 3,
		"ERROR: Only 3 component vectors supported"
	);

	if (dimensions[0] > 3) {
		return std::make_pair(
			get_dipole_field_0d(
				dipole_moments_positions,
				start
			),
			Vector_T(0, 0, 0)
		);
	}

	// check given dimensions
	int largest = -1;
	for (size_t i = 0; i < dimensions.size(); i++) {
		if (dimensions[i] > 3) {
			break;
		}

		if (largest < int(dimensions[i])) {
			largest = int(dimensions[i]);
		} else  {
			return std::make_pair(
				Vector_T(0, 0, 0),
				Vector_T(-1, -1, -1)
			);
		}
	}

	std::tuple<
		std::array<size_t, 3>,
		std::array<double, 3>,
		std::vector<std::pair<Vector_T, Vector_T>>
	> integration_parameters;

	std::get<0>(integration_parameters) = dimensions;
	std::get<1>(integration_parameters)[0] = start[0];
	std::get<1>(integration_parameters)[1] = start[1];
	std::get<1>(integration_parameters)[2] = start[2];
	std::get<2>(integration_parameters) = dipole_moments_positions;

	/*
	Get r_dims, normalization and integration
	range in format used by integrand
	*/
	unsigned r_dims = 0;
	double normalization = 1;
	Vector_T cubature_start(start), cubature_end(start);
	for (size_t i = 0; i < dimensions.size(); i++) {
		if (dimensions[i] > 2) {
			break;
		}

		r_dims++;

		normalization *= lengths[dimensions[i]];

		cubature_start[i] = start[dimensions[i]];
		cubature_end[i] = cubature_start[i] + lengths[dimensions[i]];
	}

	Vector_T integral, error;


	/*
	Returns the dipole field(s) at given point for cubature.

	In dimension(s) over which pcubature is integrating, x, y or z
	are given by r, the rest are given in extra_data. The location
	and dipole moments of dipoles are also given in extra_data.
	Format of extra_data:
	std::tuple<
		std::array<size_t, 3>,
		std::array<double, 3>,
		std::vector<std::pair<Vector_T, Vector_T>>
	>
	where:
	size_t array has the dimensions over which cubature will
	integrate. Only the first r_dims values are used, e.g. if
	integrating over y and z, r_dims == 2 and the first two values
	of the array must be 1 and 2.
	double array tells the coordinates over which cubature is not
	integrating, only the values not set by cubature are used e.g.
	if integrating over x and z at y == -1 then the second value
	must be -1 and the others can be left unspecified.
	The vector has all dipole moments and their positions that
	should be included in the integral.

	For example when integrating x and z from 0 to 1 with y == -2
	integrand could be called by cubature as (999's mark unused data):
	f = integrand(
		2,
		std::array<double, 2>{0, 0}.data(),
		std::tuple<
			std::array<size_t, 3>,
			std::array<double, 3>,
			std::vector<std::pair<Vector_T, Vector_T>>
		>{{0, 2, 999}, {999, -2, 999}, {{0, 0, -7.94e22}, {0, 0, 0}}}.data(),
		3,
		ret_val.data()
	);
	and when integrating y from -2 to -1 with x == 0.5 and z == 2/3:
	f = integrand(
		1,
		std::array<double, 1>{-2}.data(),
		std::pair<
			std::array<size_t, 3>,
			std::array<double, 3>
		>{{1, 999, 999}, {0.5, 999, 2/3}, {{0, 0, -7.94e22}, {0, 0, 0}}.data(),
		3,
		ret_val.data()
	);
	*/
	auto integrand
		= [](
			unsigned r_dims,
			const double* r,
			void* extra_data,
			unsigned f_dims,
			double* f
		) {
			if (r_dims == 0) {
				return -1;
			}

			if (r_dims > 3) {
				return -2;
			}

			if (f_dims != 3) {
				return -3;
			}

			if (r == NULL) {
				std::cerr <<  __FILE__ << "(" << __LINE__ << ")" << std::endl;
				abort();
			}

			if (f == NULL) {
				std::cerr <<  __FILE__ << "(" << __LINE__ << ")" << std::endl;
				abort();
			}

			if (extra_data == NULL) {
				std::cerr <<  __FILE__ << "(" << __LINE__ << ")" << std::endl;
				abort();
			}

			const auto integration_parameters
				= *static_cast<
					std::tuple<
						std::array<size_t, 3>,
						std::array<double, 3>,
						std::vector<std::pair<Vector_T, Vector_T>>
					>*
				>(extra_data);

			Vector_T real_r(std::get<1>(integration_parameters).data());

			for (size_t i = 0; i < r_dims; i++) {
				if (std::get<0>(integration_parameters)[i] > 3) {
					std::cerr <<  __FILE__ << "(" << __LINE__ << "): "
						<< " index " << i
						<< ", value " << std::get<0>(integration_parameters)[i]
						<< std::endl;
					abort();
				}

				real_r[std::get<0>(integration_parameters)[i]] = *(r + i);
			}

			Eigen::Map<Vector_T> ret_val(f);

			ret_val = get_dipole_field_0d(
				std::get<2>(integration_parameters),
				real_r
			);

			return 0;
		};


	const int result
		= pcubature(
			3,
			integrand,
			static_cast<void*>(&integration_parameters),
			r_dims,
			cubature_start.data(),
			cubature_end.data(),
			maxEval,
			reqAbsError,
			reqRelError,
			ERROR_LINF,
			integral.data(),
			error.data()
		);

	if (result != 0) {
		std::cerr <<  __FILE__ << "(" << __LINE__ << "): "
			<< "Could not calculate line integral of a dipole, return value: "
			<< result
			<< std::endl;
		abort();
	}

	return std::make_pair(integral / normalization, error);
}
Exemplo n.º 3
0
scalar SASFITqrombIQdR(Tcl_Interp *interp,
			int   *dF_dpar,
			scalar l[],
			scalar s[],
			scalar Q, 
			scalar a[],
			sasfit_function*  SD, 
			sasfit_function*  FF,
			sasfit_function*  SQ,
			int   distr,
			scalar Len_start, 
			scalar Len_end, 
			bool  *error)
{
    scalar *aw, res,err;
    scalar cubxmin[1], cubxmax[1], fval[1], ferr[1];
    gsl_integration_workspace * w;
    gsl_integration_cquad_workspace * wcquad;
    gsl_integration_glfixed_table * wglfixed;
    gsl_function F;
    size_t neval;
    int lenaw=4000;
    sasfit_param4int param4int;
    param4int.dF_dpar=dF_dpar;
    param4int.l=l;
    param4int.s=s;
    param4int.Q=Q;
    param4int.a=a;
    param4int.SD=SD;
    param4int.FF=FF;
    param4int.SQ=SQ;
    param4int.distr=distr;
    param4int.error=error;
    
    switch(sasfit_get_int_strategy()) {
    case OOURA_DOUBLE_EXP_QUADRATURE: {
            aw = (scalar *)malloc((lenaw)*sizeof(scalar));
            sasfit_intdeini(lenaw, GSL_DBL_MIN, sasfit_eps_get_nriq(), aw);
            sasfit_intde(&IQ_IntdLen, Len_start,Len_end, aw, &res, &err,&param4int);
            free(aw);
            break;
            } 
    case OOURA_CLENSHAW_CURTIS_QUADRATURE: {
            aw = (scalar *)malloc((lenaw+1)*sizeof(scalar));
            sasfit_intccini(lenaw, aw);
            sasfit_intcc(&IQ_IntdLen, Len_start,Len_end, sasfit_eps_get_nriq(), lenaw, aw, &res, &err,&param4int);
            free(aw);
            break;
            }
    case GSL_CQUAD: {
            wcquad = gsl_integration_cquad_workspace_alloc(lenaw);
            F.function=&IQ_IntdLen;
            F.params = &param4int;
            gsl_integration_cquad (&F, Len_start, Len_end, 0, sasfit_eps_get_nriq(), wcquad, &res, &err,&neval);
            gsl_integration_cquad_workspace_free(wcquad);
            break;
            }
    case GSL_QAG: {
            w = gsl_integration_workspace_alloc(lenaw);
            F.function=&IQ_IntdLen;
            F.params = &param4int;
            gsl_integration_qag (&F, Len_start, Len_end, 0, sasfit_eps_get_nriq(), lenaw, 3,
                        w, &res, &err);
            gsl_integration_workspace_free (w);
            break;
            }
    case H_CUBATURE: {
            param4int.function=&IQ_IntdLen;
            cubxmin[0]=Len_start;
            cubxmax[0]=Len_end;
            hcubature(1, &f1D_cubature,&param4int,1, cubxmin, cubxmax, 
              10000, 0.0, sasfit_eps_get_nriq(), 
              ERROR_INDIVIDUAL, fval, ferr);
            res = fval[0];
            break;
            }
    case P_CUBATURE: {
            param4int.function=&IQ_IntdLen;
            cubxmin[0]=Len_start;
            cubxmax[0]=Len_end;
            pcubature(1, &f1D_cubature, &param4int,1, cubxmin, cubxmax, 
              10000,0.0, sasfit_eps_get_nriq(), 
              ERROR_INDIVIDUAL, fval, ferr);
            res = fval[0];
            break;
            }
    case NR_QROMB: {
            res = SASFITqrombIQdR_old(interp,dF_dpar,l,s,Q,a,
		                    SD,FF,SQ,
							distr,Len_start, Len_end,error);
            break;
            }
    default: {
            sasfit_err("Unknown integration strategy\n");
            break;
            }
    }
    if (err < 0) {
        sasfit_err("Integration Int[N(R)I(Q,R),R=0,Infty] did not converged for Q=%lf",Q);
    }
    return res;
}