I have been using the GSL integration package (gsl_integration.h) in attempt to integrate some multivariable function f(x,y,z) with respect to x between some limit [a,b]. In this example I have as a toy model: f(x,y,z) = xyz
I would like to output the result of this integral using a function
double integral(double a, double b, double y, double z){}
where I can keep y and z arbitrary up until this point. My attempts so far have mostly involved setting y, z equal to a constant in some predefined function and then using the
gsl_integration_qags
function to integrate over that function. However, I want to keep the values of y and z arbitrary until I define them in the above function. The closest I have got so far is as follows
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <string>
#include <cmath>
#include <gsl/gsl_integration.h>
#include<stdio.h>
#include<math.h>
#define PI 3.1415926535897
double integrand(double x, void * params){
double y = *(double *) params;
double z = *(double *) params; // PROBLEM: this just sets z = y
double tmp = x*z*y;
return tmp;
}
double integral(double a, double b, double y, double z){
gsl_integration_workspace * w
= gsl_integration_workspace_alloc (1000);
gsl_function F;
F.function = &integrand; // Set integrand
F.params = &y, &z; // Set the parameters you wish to treat as constant in the integration
double result, error;
gsl_integration_qags (&F, a, b, 0, 1e-7, 1000,
w, &result, &error);
gsl_integration_workspace_free (w); // Free the memory
return result;
}
int main(){
std::cout << "Result "<< integral(0.0,1.0,3.0,5.0)<<std::endl;
}
This gives an output of
Result 4.5
The code sets a = 0.0, b = 1.0, y = z = 3.0 -- I want a = 0.0, b = 1.0, y = 3.0, z = 5.0, which would give a result of 7.5.
I would like to stick to GSL integration rather than boost if possible. I have also consulted https://www.gnu.org/software/gsl/doc/html/integration.html but am none-the-wiser. Any advice would be greatly appreciated, thanks.
I'm taking a guess, but it seems to me you want
double params[] = { y, z };
F.params = params;
and
double y = ((double *)params)[0];
double z = ((double *)params)[1];
Related
I am currently working on a 3D Perlin noise implementation in C++, and there are strange block-like artifacts when I visualize it as a video of 2D slices through the 3D volume as defined by this code with just one octave:
#include <png++/png.hpp>
#include <memory>
#include <string>
#include "Octave.h"
constexpr unsigned IMAGE_SIZE = 512;
std::string numberToString(unsigned n, unsigned digits);
int main() {
std::mt19937_64 rnd(0);
auto octave = std::make_unique<Octave>(&rnd, 32, 1); //make_unique because Octave objects are too big to fit on the stack
for(unsigned z=0;z<625;++z){
std::cout << z << "/625" << std::endl;
png::image<png::rgb_pixel> image(IMAGE_SIZE, IMAGE_SIZE);
for(unsigned x=0;x<IMAGE_SIZE;++x){
for(unsigned y=0;y<IMAGE_SIZE;++y){
unsigned brightness = (octave->noise(x, z*(64.0/300.0), y)*.5+.5)*255;
image[y][x] = png::rgb_pixel(brightness, brightness, brightness);
}
}
image.write("output/perlin-" + numberToString(z, 4) + ".png");
}
return 0;
}
std::string numberToString(unsigned n, unsigned digits){
std::string string = std::to_string(n);
while(string.length() < digits){
string = "0" + string;
}
return string;
}
Each image from the above program is a single frame in a video. A video showing the output of this problem (converted to a video via ffmpeg) is available here: https://youtu.be/f7NxYo8U7TQ. Youtube added some compression artifacts in that video that are not present in the program's output.
As is clear in the above video, as the slice moves along the Z axis, square artifacts are present: . Depending on which plane slices are made in (eg. XZ or ZY), the artifacts slightly change in nature. It appears that they are worse just after a roll over in the frequency of the one rendered octave.
What is the cause of this?
Octave.h:
#pragma once
#include <array>
#include <random>
class Octave{
public:
Octave(std::mt19937_64 *rnd, double frequency, double amplitude);
double noise(double x, double y, double z);
private:
static constexpr int PERMUTATION_TABLE_PART_SIZE = 1000000;
static constexpr int PERMUTATION_TABLE_PART_COUNT = 3;
static constexpr int PERMUTATION_TABLE_SIZE = PERMUTATION_TABLE_PART_SIZE*PERMUTATION_TABLE_PART_COUNT;
std::array<int, PERMUTATION_TABLE_SIZE> m_permutationTable;
double m_frequency, m_amplitude;
double influence(int x, int y, int z, double distanceX, double distanceY, double distanceZ);
inline static double square(double d) { return d*d; }
inline static double vectorLength(double x, double y, double z);
inline static double interpolate(double a, double b, double x);
};
Octave.cpp:
#include "Octave.h"
#include <utility>
#include <cmath>
#include <iostream>
Octave::Octave(std::mt19937_64 *rnd, double frequency, double amplitude) : m_frequency(frequency), m_amplitude(amplitude) {
//fill in basic array
for(int i=0;i<PERMUTATION_TABLE_PART_SIZE;++i){
for(int j=0;j<PERMUTATION_TABLE_PART_COUNT;++j){
m_permutationTable[i+PERMUTATION_TABLE_PART_SIZE*j] = i;
}
}
//shuffle array
for(int i=0;i<PERMUTATION_TABLE_SIZE;++i){
int swapWith = ((*rnd)() % (PERMUTATION_TABLE_SIZE-i))+i;
std::swap(m_permutationTable[i], m_permutationTable[swapWith]);
}
}
double Octave::noise(double x, double y, double z) {
x /= m_frequency;
y /= m_frequency;
z /= m_frequency;
int intX = std::floor(x);
int intY = std::floor(y);
int intZ = std::floor(z);
double floatX = x - intX;
double floatY = y - intY;
double floatZ = z - intZ;
double influence1 = influence(intX, intY, intZ, floatX, floatY, floatZ);
double influence2 = influence(intX+1, intY, intZ, floatX-1, floatY, floatZ);
double influence3 = influence(intX+1, intY+1, intZ, floatX-1, floatY-1, floatZ);
double influence4 = influence(intX, intY+1, intZ, floatX, floatY-1, floatZ);
double influence5 = influence(intX, intY, intZ+1, floatX, floatY, floatZ-1);
double influence6 = influence(intX+1, intY, intZ+1, floatX-1, floatY, floatZ);
double influence7 = influence(intX+1, intY+1, intZ+1, floatX-1, floatY-1, floatZ-1);
double influence8 = influence(intX, intY+1, intZ+1, floatX, floatY-1, floatZ-1);
double frontUpperInterpolatedValue = interpolate(influence4, influence3, floatX);
double backUpperInterpolatedValue = interpolate(influence8, influence7, floatX);
double frontLowerInterpolatedValue = interpolate(influence1, influence2, floatX);
double backLowerInterpolatedValue = interpolate(influence5, influence6, floatX);
double upperInterpolatedValue = interpolate(frontUpperInterpolatedValue, backUpperInterpolatedValue, floatZ);
double lowerInterpolatedValue = interpolate(frontLowerInterpolatedValue, backLowerInterpolatedValue, floatZ);
return interpolate(lowerInterpolatedValue, upperInterpolatedValue, floatY)*m_amplitude;
}
double Octave::influence(int x, int y, int z, double distanceX, double distanceY, double distanceZ) {
//create un-normalized gradient vector
//the ordering of x, y, and z is arbitrary but different to produce different x y and z
double gradientX = (m_permutationTable[m_permutationTable[m_permutationTable[x]+y]+z]/static_cast<double>(PERMUTATION_TABLE_PART_SIZE))*2-1;
double gradientY = (m_permutationTable[m_permutationTable[m_permutationTable[y]+x]+z]/static_cast<double>(PERMUTATION_TABLE_PART_SIZE))*2-1;
double gradientZ = (m_permutationTable[m_permutationTable[m_permutationTable[y]+x]+z]/static_cast<double>(PERMUTATION_TABLE_PART_SIZE))*2-1;
//normalize gradient vector
double gradientVectorInverseLength = 1/vectorLength(gradientX, gradientY, gradientZ);
gradientX *= gradientVectorInverseLength;
gradientY *= gradientVectorInverseLength;
gradientZ *= gradientVectorInverseLength;
//compute dot product
double dot = gradientX*distanceX+gradientY*distanceY+gradientZ*distanceZ;
return dot;
}
double Octave::vectorLength(double x, double y, double z) {
return std::sqrt(square(x)+square(y)+square(z));
}
double Octave::interpolate(double a, double b, double x) {
return (b-a)*(6*x*x*x*x*x-15*x*x*x*x+10*x*x*x)+a;
}
I determined the issue. I forgot to do floatZ-1 when calculating influence6.
I spent quiet some time looking on the internet to find a solution to this, maybe it's out there but nothing of what I saw helped me.
I have a function !
double integrand(double r, double phi, double theta)
That I want to integrate with some given definite bounds over the three dimensions. I found multiple lines of code on the internet that implement single variable definite integrals numerical schemes. I was thinking to myself "well, I'll just integrate along one dimension after the other".
Algorithmically speaking what I wanted to do was :
double firstIntegral(double r, double phi) {
double result = integrationFunction(integrand,lower_bound,upper_bound);
return result;
}
And simply do it again two more times. This works easily in languages like Matlab where I can create functions handler anywhere but I don't know how to do it in C++. I would have to first define a function that some r and phi will calculate integrand(r, phi, theta) for any theta and make it in C++ a function of one variable only but I don't know how to do that.
How can I compute the triple integral of my three-variables function in C++ using a one -dimensional integration routine (or anything else really...) ?
This is a very slow and inexact version for integrals over cartesian coordinates, which should work with C++11.
It is using std::function and lambdas to implement the numerical integration. No steps have been taken to optimize this.
A template based solution could be much faster (by several orders of magnitude) than this, because it may allow the compiler to inline and simplify some of the code.
#include<functional>
#include<iostream>
static double integrand(double /*x*/, double y, double /*z*/)
{
return y;
}
double integrate_1d(std::function<double(double)> const &func, double lower, double upper)
{
static const double increment = 0.001;
double integral = 0.0;
for(double x = lower; x < upper; x+=increment) {
integral += func(x) * increment;
}
return integral;
}
double integrate_2d(std::function<double(double, double)> const &func, double lower1, double upper1, double lower2, double upper2)
{
static const double increment = 0.001;
double integral = 0.0;
for(double x = lower2; x < upper2; x+=increment) {
auto func_x = [=](double y){ return func(x, y);};
integral += integrate_1d(func_x, lower1, upper1) * increment;
}
return integral;
}
double integrate_3d(std::function<double(double, double, double)> const &func,
double lower1, double upper1,
double lower2, double upper2,
double lower3, double upper3)
{
static const double increment = 0.001;
double integral = 0.0;
for(double x = lower3; x < upper3; x+=increment) {
auto func_x = [=](double y, double z){ return func(x, y, z);};
integral += integrate_2d(func_x, lower1, upper1, lower2, upper2) * increment;
}
return integral;
}
int main()
{
double integral = integrate_3d(integrand, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
std::cout << "Triple integral: " << integral << std::endl;
return 0;
}
You can use functors
#include <iostream>
struct MyFunctorMultiply
{
double m_coeff;
MyFunctorMultiply(double coeff)
{
m_coeff = coeff;
}
double operator()(double value)
{
return m_coeff * value;
}
};
struct MyFunctorAdd
{
double m_a;
MyFunctorAdd(double a)
{
m_a = a;
}
double operator()(double value)
{
return m_a + value;
}
};
template<class t_functor>
double calculate(t_functor functor, double value, double other_param)
{
return functor(value) - other_param;
}
int main()
{
MyFunctorMultiply multiply2(2.);
MyFunctorAdd add3(3.);
double result_a = calculate(multiply2, 4, 1); // should obtain 4 * 2 - 1 = 7
double result_b = calculate(add3, 5, 6); // should obtain 5 + 3 - 6 = 2
std::cout << result_a << std::endl;
std::cout << result_b << std::endl;
}
If your concern is just about getting the right prototype to pass to the integration function, you can very well use alternative data passing mechanisms, the simpler of which is using global variables.
Assuming that the order of integration is on theta, then phi, then r, write three functions of a single argument:
It(theta) computes the integrand from the argument theta passed explicitly and the global phi and r.
Ip(phi) computes the bounds on theta from the argument phi passed explicitly and the global r; it also copies the phi argument to the global variable and invokes integrationFunction(It, lower_t, upper_t).
Ir(r) computes the bounds on phi from the argument r passed explicitly; it also copies the r argument to the global variable and invokes integrationFunction(Ip, lower_p, upper_p).
Now you are ready to call integrationFunction(Ir, lower_r, upper_r).
It may also be that integrationFunction supports a "context" argument where you can store what you want.
I have a program in C++ (compiled using g++). I'm trying to apply two doubles as operands to the modulus function, but I get the following error:
error: invalid operands of types 'double' and 'double' to binary 'operator%'
Here's the code:
int main() {
double x = 6.3;
double y = 2;
double z = x % y;
}
The % operator is for integers. You're looking for the fmod() function.
#include <cmath>
int main()
{
double x = 6.3;
double y = 2.0;
double z = std::fmod(x,y);
}
fmod(x, y) is the function you use.
You can implement your own modulus function to do that for you:
double dmod(double x, double y) {
return x - (int)(x/y) * y;
}
Then you can simply use dmod(6.3, 2) to get the remainder, 0.3.
Use fmod() from <cmath>. If you do not want to include the C header file:
template<typename T, typename U>
constexpr double dmod (T x, U mod)
{
return !mod ? x : x - mod * static_cast<long long>(x / mod);
}
//Usage:
double z = dmod<double, unsigned int>(14.3, 4);
double z = dmod<long, float>(14, 4.6);
//This also works:
double z = dmod(14.7, 0.3);
double z = dmod(14.7, 0);
double z = dmod(0, 0.3f);
double z = dmod(myFirstVariable, someOtherVariable);
I am making a program that converts rectangular coordinates into polar coordinates and whenever I go to run the program it tells me that the "angle" is undeclared even though I am sure I have declared it. As well I know that the program isn't returning anything, I just want to be able to run it for now.
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
double random_float(double min, double max);
void rect_to_polar(double x, double y, double &distance, double &angle);
int main() {
double x, y;
x = random_float(-1, 1);
y = random_float(-1, 1);
rect_to_polar(x, y, distance, angle);
}
double random_float(double min, double max) {
unsigned int n = 2;
srand(n);
return ((double(rand()) / double(RAND_MAX)) * (max - min)) + min;
}
void rect_to_polar(double x, double y, double &distance, double &angle) {
const double toDegrees = 180.0/3.141593;
distance = sqrt(x*x + y*y);
angle = atan(y/x) * toDegrees;
}
You did not declare anything called angle in your main(), but still used the name angle there. Thus the error.
You might want to read up on scopes.
You should declare distance and angle in your main.
int main() {
double x, y, angle, distance;
x = random_float(-1, 1);
y = random_float(-1, 1);
rect_to_polar(x, y, distance, angle);
}
I am getting the following error message when I try to run the following code when I try to add the function RK4 using a header file.
C:\Documents\C code\RK4\addRK4.h|7|error: expected ')' before '(' token|
There are a bunch of other error messages after that but I don't think they are important. I can't figure out what's wrong, especially since when I define the prototype of RK4 in main.cpp, everything runs just fine. The relevant code is below. Any help on this matter (or if you have any other suggestions since I am pretty new to c++) would be greatly appreciated!
main.cpp
#include <iostream>
#include <fstream>
#include <Eigen/Dense>
#include "gnuplot.h"
#include "addfitzhough.h"
#include "addRK4.h"
using namespace std;
using namespace Eigen;
int main()
{
//int mydims = 2;
double u = 0;
double *Iion;
double h = .5;
double y1ans[800];
double y2ans[800];
double tans[800];
Vector2d ycurr;
Vector2d Ynot, yplus;
Ynot << .2,
.1;
y1ans[0] = Ynot(0);
y2ans[0] = Ynot(1);
tans[0] = 0.0;
for(int i = 1;i<800;i++){
tans[i] = tans[i-1] + h;
ycurr << y1ans[i-1],
y2ans[i-1];
yplus = RK4(fitzhough,tans[i],ycurr,h,u,Iion,2);
y1ans[i] = yplus(0);
y2ans[i] = yplus(1);
}
}
addRK4.h
#ifndef RK4
#define RK4
using namespace Eigen;
VectorXd RK4(VectorXd (*f) (double t, Vector2d Y, double u, double * Iion), double t, VectorXd z, double h, double u, double *Iion, int d);
#endif // RK4
RK4.cpp
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
Vector2d RK4(Vector2d (*f)(double, Vector2d, double, double*), double t, VectorXd z, double h, double u, double *Iion, int d){
VectorXd Y1(d), Y2(d), Y3(d), Y4(d), Y1buf(d), Y2buf(d), Y3buf(d);
Y1 = z;
Y1buf = (*f)(t,Y1,u, Iion);
Y2 = z + 0.5*h*Y1buf;
Y2buf = (*f)(t+.5*h,Y2,u, Iion);
Y3 = z + 0.5*h*Y2buf;
Y3buf = (*f)(t+.5*h,Y3,u, Iion);
Y4 = z + h*Y3buf;
Vector2d yn = z + (h/6.0)*(Y1buf + 2.0*Y2buf + 2.0*Y3buf + (*f)(t+h,Y4,u, Iion));
return yn;
}
fitzhough.cpp
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
Vector2d fitzhough(double t, Vector2d Y, double u, double * Iion){
Vector2d dy;
double v = Y(0);
double w = Y(1);
double a = .13;
double b = .013;
double c1 = .26;
double c2 = .1;
double d = 1.0;
dy(0) = c1*v*(v-a)*(1-v)-c2*w*v + u;
dy(1) = b*(v-d*w);
*Iion = dy(0)-u;
return dy;
}
You have a symbol clash.
You #define the symbol RK4 and then you try to create a function with that name. Because you have defined it as an empty macro, it will be replaced with nothing. Then the compiler sees this as your function declaration:
VectorXd (VectorXd (*f) (double t, Vector2d Y, double u, double * Iion), double t, VectorXd z, double h, double u, double *Iion, int d);
It's a good idea to add extra characters for your header cages. Something like:
#ifndef RK4__H
#define RK4__H
It appears to be something wrong with the types Vector2d and VectorXd.
Edit: good catch #Paddy. Leaving the rest of the answer here since it is still valid.
Also, your declaration in addRK4.h doesnt match the definition in RK4.cpp. This will be the next error you will be fixing.