Interpolation error with gsl_interp_linear - c++

I need to interpolate a modified Bessel function and I use for that the function gsl_spline_eval(). I get a 'gsl: interp.c:145: ERROR: interpolation error' with the following code:
#define MAXPOINTS 10000
int main()
{
double nu;
gsl_function F;
F.function = &sync;
F.params =0;
size_t size;
double table[2][MAXPOINTS];
size = read_table(table[0],table[1]);
gsl_interp_accel *acc = gsl_interp_accel_alloc ();
gsl_spline *spline = gsl_spline_alloc (gsl_interp_linear, 5401);
gsl_spline_init(spline,table[0],table[1],size);
cout <<" nu: "<< nu<< " GSL_FN_EVAL(&F,nu): "<<nu*GSL_FN_EVAL(&F,nu)<<endl;
return 0;
}
Where sync() returns the integral of the function sync_kern() using the gsl function gsl_integration_qag(). The function read_table() is defined as follow:
size_t read_table(double *xa, double *ya)
{
size_t datapoints;
datapoints = 5401;
double x[] = {
1.388794e-11,
1.395756e-11,
... };
double y[] = {
5.166810e-04,
5.175428e-04,
...
};
int i = 0;
while(i<datapoints){
xa[i]=log(x[i]);
ya[i]=log(y[i]);
i++;
}
return datapoints;
}
The function sync_kern() is the following:
double sync_kern(double gamma, void *params)
{
struct func_params *part= (struct func_params *)params;
double result;
double P,x, nuc, nu_0;
double nu = *(double *)params;
gamma = exp(gamma);
nu_0 = (3*E_COULOMB*B*sqrt(2/3.0))/(4.0*M_PI*M*C);
nuc = nu_0*sq(gamma);
x = nu/nuc;
gsl_interp_accel *acc = gsl_interp_accel_alloc ();
gsl_spline *spline = gsl_spline_alloc (gsl_interp_linear, 5401);
/* double table[2][MAXPOINTS];
size = read_table(table[0],table[1]);
gsl_interp_accel *acc = gsl_interp_accel_alloc ();
gsl_spline *spline = gsl_spline_alloc (gsl_interp_interp, 5401);
gsl_spline_init(spline,table[0],table[1],size); */
P = gsl_spline_eval(spline,log(x),acc);
result = exp(P)*f(gamma)*gamma;
return(result);
}
When I include the lines
/* double table[2][MAXPOINTS];
size = read_table(table[0],table[1]);
gsl_interp_accel *acc = gsl_interp_accel_alloc ();
gsl_spline *spline = gsl_spline_alloc (gsl_interp_interp, 5401);
gsl_spline_init(spline,table[0],table[1],size); */
in the function sync_kern() and not in main() then it works: I get the right value of GSL_FN_EVAL(&F,nu) but it takes of course too much time...
I hope my message wasn't too long...I am not a great expert of c++ and I've look all the aspects of the problem and I still don't understand where it comes from...Does someone have any idea?
Please don't hesitate do ask me if you need any further informations.
Thanks a lot for your help!
Maybe I should precise that I got my code from my supervisor's code. Which is slightly different:
int main(int argc,char *argv[])
{
FILE *fp;
struct func_params params;
size_t size;
int i;
/* initializing parameters */
initialize(argc, argv, &params);
/* Interpolation of Synchrotronfunction F(x) */
double table[2][MAXPOINTS];
size = read_table(table[0],table[1]); /*Tabelle fuer Interpolation einlesen aus create_table.c*/
params.acc = gsl_interp_accel_alloc();
params.spline = gsl_spline_alloc(gsl_interp_linear, size);
gsl_spline_init(params.spline,table[0],table[1],size);
...
return (0);
}
double
sync_kern(double gamma, void *params)
{
struct func_params *part= (struct func_params *)params;
double result;
double P,nu_c,x;
gamma = exp(gamma);
nu_c = part->nu_0*sq(gamma);
x = part->nu_s/nu_c;
P = gsl_spline_eval(part->spline,log(x),part->acc); /*Aus Interpolation: Pointer auf spline */
result = exp(P)*f(gamma)*gamma;
return(result);
}
Where spline and acc are defined in a file.h:
struct func_params
{
gsl_spline *spline;
gsl_interp_accel *acc;
...
}
void initialize(int argc, char *argv[], void *params)
{
struct func_params *part= (struct func_params *)params;
/* Default values for parameters: */
part->gmin=1.0e7/M_E_EV;
part->gamma=1.0e10/M_E_EV;
part->gmax=2.0e18/M_E_EV; /*Integrationgrenzen fuer gamma festlegen*/
part->nu=1e-9/H_EV;
...
}
I defined spline and acc in my function sync_kern() and him in a structure. Does someone has an idea where the error can come from?

The function read_table() gives the arrays 'x[]' and 'y[]' used for
the interpolation
double table[2][MAXPOINTS];
size = read_table(table[0],table[1]);
You define an array of doubles, but don't initialize it. It contains random values. So likely it runs with absurd results.
You pass two values to read_table(). If you want the function to change them, the definition of this function should be
size_t read_table(double& val1, double& val2);
Review your code. There are some vars without declaration (nu_0, nuc, acc)
EDIT
After you edited the question, I see how read_table() is defined. It uses two pointers. You have an only array, two dimensions, fixed size. Because of this fixed size, it's OK to pass the array by using two pointers, table[0] and table[1].
double table[2][N] is same as double** table. So passing table[1] is passing a pointer to an array[N].
The gsl error is due to this code at gsl:interp.c
https://github.com/ampl/gsl/blob/master/interpolation/interp.c
if (x < interp->xmin || x > interp->xmax)
{
GSL_ERROR_VAL("interpolation error", GSL_EDOM, GSL_NAN);
}
It seems you are trying an interpolation out of limits (called "extrapolation")

Related

Why do I get the "identifier "a" is undefined" in a function where I have a as a parameter?

In the following code:
void benchmark(string desc, int(*pf)(int a[50])) {
printf("\n Benchmark for %s", desc.c_str());
double tStart = omp_get_wtime();
int result = pf(a[50]);
double tFinal = omp_get_wtime();
printf("\n\t Final result: %d", result);
printf("\n\t Duration: %f (s)", tFinal - tStart);
int main() {
int i, b;
int a[50];
for (i = 0; i < 50; i++)
{
b = rand() % 10000 + 1;
a[i] = b;
}
benchmark("Parallel solution without mutex for counting primes", Squential);
benchmark("Parallel solution with load balancing", Parallel1);
benchmark("Parallel solution with load balancing", Parallel2);
}
On line "int result = pf(a[50]);" the compiler says "identifier "a" is undefined" although I listed it in the parameters list. It may have something to do with the pointer, I'm not used to working with pointers.
This does not have a parameter a
void benchmark(string desc, int(*pf)(int a[50])) {
This has the parameters:
* desc: Type -> string
* pf: Type -> A function (pointer) that returns int and takes an array of int
This is a function pointer type:
int (*pf)(int a[50])
^^ This is the name of the paramter.
// This is the type
int (*)(int[50])
// This is a pointer to a function that returns an `int`
// and takes `int[50]` as a parameter.
Just to get this copiling do this:
int result = pf(a[50]);
// change into this:
int data[50]; // or get this from somewhere else.
int result = pf(data);

Ceres Solver C++: Segmentation fault: 11

I am trying to solve a nonlinear system using Ceres Solver by Google. The example below comes from this page: http://terpconnect.umd.edu/~petersd/460/html/newtonex1z.html
I first create a class called MatlabExample, where I compute the residuals and jacobians:
class MatlabExample
: public SizedCostFunction<2,2> {
public:
virtual ~MatlabExample() {}
virtual bool Evaluate(double const* const* parameters,
double* residuals,
double** jacobians) const {
double x1 = parameters[0][0];
double x2 = parameters[0][1];
residuals[0] = 2*x1+x1*x2-2;
residuals[1] = 2*x2-x1*pow(x2,2)-2 ;
if (jacobians != NULL && jacobians[0] != NULL) {
jacobians[0][0] = 2+x2;
jacobians[0][1] = x1;
jacobians[1][0] = -pow(x2,2);
jacobians[1][1] = 2-2*x1*x2;
}
return true;
}
};
The main file is as follows:
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
double x[] = { 0.0,0.0 };
Problem problem;
CostFunction* cost_function = new MatlabExample;
problem.AddResidualBlock(cost_function, NULL, &x);
Solver::Options options;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
return 0;
}
When compiling, I got a Segmentation fault: 11 error. Any ideas?
You are accessing the jacobians array wrong. Here is why.
When you added the residual block, you told Ceres that the cost function only depends on one parameter block of size 2 and produces a residual of size 2.
The jacobians array is an array of row-major jacobians. One for each parameter block. So in this case it is of size 1, and contains a pointer to size 4 array that should contain a row major Jacobian.
Your Jacobian filling code should instead read
if (jacobians != NULL && jacobians[0] != NULL) {
jacobians[0][0] = 2+x2;
jacobians[0][1] = x1;
jacobians[0][2] = -pow(x2,2);
jacobians[0][3] = 2-2*x1*x2;
}

C++ got wrong value from array of struct

The problem is as described above. When I try to read values from loaded *.so file (using libdl), whih are in struct I am getting wrong values
Code of application:
#include <dlfcn.h>
#include <iostream>
/* For face data type reproduction */
#define GET_FACE_XYZ_SIZE 1
/* For face_array reproduction */
#define GET_FACE_ARRAY_SIZE 2
#define GET_OBJECT_DATA 3
typedef struct face {
float x[1000];
float y[1000];
float z[1000];
int vertices;
} face;
int main()
{
void *hook;
int (*fn)(int request_type, void *ptr);
hook = dlopen("/root/osms/dlopen-test/lib.so", RTLD_LAZY);
if(!hook)
{
std::cout << "Couldn't find lib.so" << std::endl;
}
fn = dlsym(hook, "object_info");
int face_array_size = fn(GET_FACE_ARRAY_SIZE, NULL);
std::cout << "FACE_ARRAY_SIZE: " << face_array_size << std::endl;
face pointer[face_array_size];
fn(NULL, pointer);
dlclose(hook);
std::cout << "pointer[0].z[1]: " << pointer[0].z[1] << std::endl;
return 0;
}
and code of lib.so:
/* For face data type reproduction */
#define GET_FACE_XYZ_SIZE 1
/* For face array reproduction */
#define GET_FACE_ARRAY_SIZE 2
#define GET_OBJECT_DATA 3
typedef struct face {
float x[1000];
float y[1000];
float z[1000];
int vertices;
} face;
extern "C" int object_info(int request, void *ptr)
{
face face_array[2];
face_array[0].x[0] = 1.1;
face_array[0].y[0] = 0.5;
face_array[0].z[0] = 1.2;
face_array[0].x[1] = 1.6;
face_array[0].y[1] = -0.11;
face_array[0].z[1] = -12;
face_array[0].x[2] = -0.12;
face_array[0].y[2] = 0.24;
face_array[0].z[2] = -0.12;
face_array[0].vertices = 3;
face_array[1].x[0] = -1.1;
face_array[1].y[0] = 0.15;
face_array[1].z[0] = -1.2;
face_array[1].x[1] = -1.6;
face_array[1].y[1] = 0.11;
face_array[1].z[1] = 1.2;
face_array[1].x[2] = 0.12;
face_array[1].y[2] = -0.24;
face_array[1].z[2] = 0.12;
face_array[1].vertices = 3;
if(request == GET_FACE_ARRAY_SIZE)
{
return 2;
}
else
{
ptr = face_array;
}
}
The expected output is pointer[0].z[1]: -12 but I am getting pointer[0].z[1]: -0.12. What's wrong in my code ?
Thanks in advance
Accessing
pointer[0].z[1]
Has undefined behaviour, because it has an indeterminate value.
object_info never modifies the array pointed by ptr. It simply modifies a local array, and assigns the local ptr to point to that local array.
A solution: Don't declare a local array, and instead modify the array pointed by the argument. In other words, repace face face_array[2]; with:
face* face_array = (face*)ptr;
And get rid of the ptr = face_array; that does nothing meaningful.
object_info is declared to return int, but not all code paths return a value. When the function reaches the end of object_info without a return statement, the behaviour is undefined.
A solution: Always return a value if the function is not void.
face_array_size is not a compile time constant value, so face pointer[face_array_size]; will declare a variable length array. VLA are not allowed in C++.
Either use C (VLA are supported since C99, but only optionally supported since C11) instead or use a dynamic array: std::vector<face> or make peace with the fact that your program is not standard compliant.
The variable "face_array" in function object_info and the variable "pointer" in main are not the same variable.
The statement "ptr = face_array" does not change the content of "pointer".
extern "C" int object_info(int request, face *face_array)
{
if(request == GET_FACE_ARRAY_SIZE)
return 2;
face_array[0].x[0] = 1.1;
face_array[0].y[0] = 0.5;
face_array[0].z[0] = 1.2;
face_array[0].x[1] = 1.6;
face_array[0].y[1] = -0.11;
face_array[0].z[1] = -12;
face_array[0].x[2] = -0.12;
face_array[0].y[2] = 0.24;
face_array[0].z[2] = -0.12;
face_array[0].vertices = 3;
face_array[1].x[0] = -1.1;
face_array[1].y[0] = 0.15;
face_array[1].z[0] = -1.2;
face_array[1].x[1] = -1.6;
face_array[1].y[1] = 0.11;
face_array[1].z[1] = 1.2;
face_array[1].x[2] = 0.12;
face_array[1].y[2] = -0.24;
face_array[1].z[2] = 0.12;
face_array[1].vertices = 3;
}

C++ Deep Copy Object

I am trying to deep copy objects back and forth. When I run the gdb, I get the following error after one iteration of the loop.
Program received signal SIGSEGV, Segmentation fault.
0x0804ab96 in DGCPM::DGCPM (this=0x844b760, cur=0x1) at DGCPM.C:27
27 memcpy(vRCells, cur->vRCells,sizeof(float)*nThetaCells);
I suspect the problem has to do with creating the "new class," but I'm not sure. Any suggestions?
(Note: The "_initialize" code calls a FORTRAN subroutine that sets the values in the program.)
Here is the run.C main file:
#include "../include/DGCPM.h"
#define particle_num 5
class DGCPM **mallocModels(int n);
int main(int argc, char *argv[]){
class DGCPM **m;
class DGCPM **cur;
m=mallocModels(particle_num);//update
for(int t = 0; t < 48; t++){
//Update m, and then...
cur = m;
m = (DGCPM**)malloc(sizeof(class DGCPM *)*particle_num);
for(int i=0;i<particle_num;i++){
randomidx = ((double)rand() / ((double)RAND_MAX + 1));
currentidx = find(cumPw,randomidx,particle_num);
m[i] = new class DGCPM(cur[currentidx]);
}
for(int i=0;i<particle_num;i++){
delete cur[i];
}
free(cur);
}
return 0;
}
/*============================================================================
mallocModels - allocate the ensemble of models
============================================================================*/
class DGCPM **mallocModels(int n){
class DGCPM **m;
m=(class DGCPM **)amjSafeMalloc(sizeof(class DGCPM *)*n,
(char *)"mallocModels:m");
for(int i=0;i<n;i++)
m[i]=new class DGCPM();
return m;
}
/*============================================================================
Find - Return a particle index that has a high probability of having a high weight.
============================================================================*/
int find(float *cumPw, double randomidx, int nM){
/*Wrong implementation*/
int index = 0;
flag = 0;
while(flag == 0){
if(cumPw[i] >= randomidx){
flag = 1;
i++;
}
else{
index ++;
}
}
return index; //Sometimes, index was going to number of models, or number of models + 1, which are out of bounds.
/*Correct implementation*/
int index = 0;
for(int i = 0; i < nM-1; i++){
if(cumPw[i] >= randomidx){
index = i;
break;
}
}
if(index >= nM){
index = nM-1;
printf("Error: random index exceeds bounds");
}
return index;
}
Here is the DGCPM.h header file:
class DGCPM{
public:
DGCPM(); /* Initialized with defaults setup */
DGCPM(class DGCPM *cur); //Copy constructor
DGCPM(int nThetaCells, int nPhiCells, float thetaMin, float thetaMax);
~DGCPM(); /* Free memory */
private:
int internal; /* 1=memory allocated internally and should be deallocated when ~DGCPM is called, 2=memory is internal except for mGridN which is external */
int nThetaCells,nRCells,nPhiCells;
float thetaMin,thetaMax;
float rMin,rMax;
float delR,delPhi;
float deltMax;
float *vRCells; /* [nThetaCells] */
float *vThetaCells; /* [nThetaCells] */
float *vPhiCells; /* [nPhiCells] */
float **mGridB; /* [nPhiCells][nThetaCells] */
float **mGridBi; /* [nPhiCells][nThetaCells] */
float **mGridPot; /* [nPhiCells][nThetaCells] */
float **mGridEr; /* [nPhiCells][nThetaCells] */
float **mGridEp; /* [nPhiCells][nThetaCells] */
float **mGridVr; /* [nPhiCells][nThetaCells] */
float **mGridVp; /* [nPhiCells][nThetaCells] */
float **mGridN; /* [nPhiCells][nThetaCells] */
float **mGridHalf; /* [nPhiCells][nThetaCells] Particles / weber (workspace for upwind and superbee) */
float **mGridDen; /* [nPhiCells][nThetaCells] */
float **mGridVol; /* [nPhiCells][nThetaCells] */
float **mGridX; /* [nPhiCells][nThetaCells] */
float **mGridY; /* [nPhiCells][nThetaCells] */
float **mGridOc; /* [nPhiCells][nThetaCells] */
float **std; /* [nPhiCells][nThetaCells] */
float parI[2];
float delTMax;
float Re;
void initialize(int nThetaCells, int nPhiCells, float thetaMin,
float thetaMax);
};
And finally the DGCPM.C object wrapper:
/******************************************************************************
* DGCPM.C - This implements the DGCPM plasmasphere model class *
******************************************************************************/
#define TWO_PI 6.2831853071795864769252866
#include "../include/DGCPM.h"
# include <cstdlib>
# include <cmath>
/*============================================================================
DGCPM::DGCPM()
Initialize with default setup
============================================================================*/
DGCPM::DGCPM(){
internal=1;
initialize(200,200,14.963217,60.0);/*(180,200,14.963217,60.0);*/
}
//Copy Constructor
DGCPM::DGCPM(class DGCPM *cur){
internal=1;
initialize(200,200,14.963217,60.0);/*(180,200,14.963217,60.0);*/
memcpy(vRCells, cur->vRCells,sizeof(float)*nThetaCells);
memcpy(vPhiCells, cur->vPhiCells,sizeof(float)*nPhiCells);
memcpy(vThetaCells, cur->vThetaCells,sizeof(float)*nThetaCells);
memcpy(mGridB[0], cur->mGridB[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridBi[0], cur->mGridBi[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridPot[0], cur->mGridPot[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridEr[0], cur->mGridEr[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridEp[0], cur->mGridEp[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridVr[0], cur->mGridVr[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridVp[0], cur->mGridVp[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridN[0], cur->mGridN[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridHalf[0], cur->mGridHalf[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridDen[0], cur->mGridDen[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridVol[0], cur->mGridVol[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridOc[0], cur->mGridOc[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridX[0], cur->mGridX[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(mGridY[0], cur->mGridY[0],sizeof(float)*nThetaCells*nPhiCells);
memcpy(std[0], cur->std[0],sizeof(float)*nThetaCells*nPhiCells);
}
/*============================================================================
DGCPM::~DGCPM()
Free allocated memory
============================================================================*/
DGCPM::~DGCPM(){
if(internal>=1){
amjFree1dFloat(vRCells);
amjFree1dFloat(vThetaCells);
amjFree1dFloat(vPhiCells);
amjFree2dFloat(mGridB);
amjFree2dFloat(mGridBi);
amjFree2dFloat(mGridEr);
amjFree2dFloat(mGridEp);
amjFree2dFloat(mGridVr);
amjFree2dFloat(mGridVp);
if(internal==1) amjFree2dFloat(mGridN);
amjFree2dFloat(mGridHalf);
amjFree2dFloat(mGridDen);
amjFree2dFloat(mGridVol);
amjFree2dFloat(mGridX);
amjFree2dFloat(mGridY);
amjFree2dFloat(mGridOc);
amjFree2dFloat(std);
}
}
/******************************************************************************
******************************************************************************
** Private functions **
******************************************************************************
******************************************************************************/
/*============================================================================
DGCPM::initialize(int nThetaCells, int nPhiCells, float thetaMin,
float thetaMax);
This is the initialization function used when all memory should be
allocated internally.
============================================================================*/
void DGCPM::initialize(int nThetaCells, int nPhiCells, float thetaMin,
float thetaMax){
initialize(nThetaCells,nPhiCells,thetaMin,thetaMax,
amjMalloc1dFloat(nThetaCells,(char *)"DGCPM::DGCPM:vRCells"),
amjMalloc1dFloat(nThetaCells,(char *)"DGCPM::DGCPM:vThetaCells"),
amjMalloc1dFloat(nPhiCells,(char *)"DGCPM::DGCPM:vPhiCells"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridB"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridBi"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridPot"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridEr"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridEp"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridVr"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridVp"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridN"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridHalf"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridDen"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridVol"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridX"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridY"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridOc"),
//Added by J.Wise
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:std"));
}
/*============================================================================
DGCPM::initialize(int nThetaCells, int nPhiCells, float thetaMin,
float thetaMax);
This is the initialization function used when mGridN is passed from
the outside but all other memory is allocated internally.
============================================================================*/
void DGCPM::initialize(int nThetaCells, int nPhiCells, float thetaMin,
float thetaMax, float **mGridN){
initialize(nThetaCells,nPhiCells,thetaMin,thetaMax,
amjMalloc1dFloat(nThetaCells,(char *)"DGCPM::DGCPM:vRCells"),
amjMalloc1dFloat(nThetaCells,(char *)"DGCPM::DGCPM:vThetaCells"),
amjMalloc1dFloat(nPhiCells,(char *)"DGCPM::DGCPM:vPhiCells"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridB"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridBi"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridPot"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridEr"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridEp"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridVr"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridVp"),
mGridN,
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridHalf"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridDen"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridVol"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridX"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridY"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:mGridOc"),
amjMalloc2dFloat(nPhiCells,nThetaCells,
(char *)"DGCPM::DGCPM:std"));
}
/*
initialize() - this initialization function uses pre-allocated
memory areas passed in from the outside. This function is used both
when DGCPM allocates memory itself and when it receives
pre-allocated memory from the outside in order to eliminate
duplication of code with the associated risk of errors.
============================================================================*/
void DGCPM::initialize(int nThetaCells, int nPhiCells, float thetaMin,
float thetaMax, float *vRCells, float *vThetaCells,
float *vPhiCells, float **mGridB, float **mGridBi,
float **mGridPot, float **mGridEr, float **mGridEp,
float **mGridVr, float **mGridVp, float **mGridN,
float **mGridHalf, float **mGridDen, float **mGridVol,
float **mGridX, float **mGridY, float **mGridOc, float **std){
DGCPM::nThetaCells=nThetaCells;
DGCPM::nPhiCells=nPhiCells;
DGCPM::thetaMin=thetaMin;
DGCPM::thetaMax=thetaMax;
DGCPM::vRCells=vRCells;
DGCPM::vThetaCells=vThetaCells;
DGCPM::vPhiCells=vPhiCells;
DGCPM::mGridB=mGridB;
DGCPM::mGridBi=mGridBi;
DGCPM::mGridPot=mGridPot;
DGCPM::mGridEr=mGridEr;
DGCPM::mGridEp=mGridEp;
DGCPM::mGridVr=mGridVr;
DGCPM::mGridVp=mGridVp;
DGCPM::mGridN=mGridN;
DGCPM::mGridHalf=mGridHalf;
DGCPM::mGridDen=mGridDen;
DGCPM::mGridVol=mGridVol;
DGCPM::mGridX=mGridX;
DGCPM::mGridY=mGridY;
DGCPM::mGridOc=mGridOc;
DGCPM::std=std;
Re=6.378e6;
initialize_(&nThetaCells,&nRCells,&nPhiCells,&thetaMin,&thetaMax,&rMin,&rMax,
&delR,&delPhi,vRCells,vThetaCells,vPhiCells,mGridB[0],mGridBi[0],
mGridN[0],mGridDen[0],mGridVol[0],mGridX[0],mGridY[0],mGridOc[0],std[0]);
}
Here's a sample custom memory function, which takes care of initialization and allocation:
void *amjSafeMalloc(int n, char *message){
void *d;
d=malloc(n);
if(d==NULL){
fprintf(stderr,"amjSafeMalloc error: Could not allocate %d bytes "
"for %s. Exiting.\n",n,message);
exit(1);
}
return d;
}
float *amjMalloc1dFloat(int a, char *message){
float *d;
sprintf(msg,"%s:amjMalloc1DFloat:d",message);
d=(float *)amjSafeMalloc(sizeof(float)*a,msg);
return d;
}
float **amjMalloc2dFloat(int a, int b, char *message){
float **d;
int i;
sprintf(msg,"%s:amjMalloc2DFloat:d",message);
d=(float **)amjSafeMalloc(sizeof(float *)*a,msg);
sprintf(msg,"%s:amjMalloc2DFloat:d[0]",message);
d[0]=(float *)amjSafeMalloc(sizeof(float)*a*b,msg);
for(i=1;i<a;i++) d[i]=d[i-1]+b;
return d;
}
class DGCPM
{
public:
DGCPM(int nThetaCells, int nPhiCells)
: nThetaCells(nThetaCells)
, nPhiCells(nPhiCells)
, mGridB(nThetaCells, vector<float>(nPhiCells)) // first Y then X
{
}
private:
int nThetaCells, nPhiCells;
vector<vector<float>> mGridB;
};
Deep copies for free. Deletes memory for free.
By free I mean you don't have to write the code..
From your comment /* [nPhiCells][nThetaCells] */ in your class definition, I take it that you intent the float** to be 2D arrays. However, if you can use them like 2D arrays, they are actually arrays of pointers to arrays. That is a huge difference: it means, you have to copy nPhiCells individual arrays of nThetaCells elements and you have to setup the pointer array itself. Now, when you do
memcpy(mGridHalf[0], cur->mGridHalf[0],sizeof(float)*nThetaCells*nPhiCells);
in your copy constructor, you assume that there is no pointer array, and that all line arrays are sequential in memory. Either this copy exceeds the bounds of the pointer array (segfaulting), or accessing you array via mGridHalf[i][j] simply does the wrong thing, reinterpreting float data as pointers (and segfaulting).
Unfortunately, C++ is a horrible language for interacting with fortran multidimensional arrays because it has no notion of variable sized arrays. So the following is C code, not C++ code. In C, you can tackle the issue like this:
float (*mGridHalf)[nThetaCells] = malloc(nPhiCells*sizeof(*mGridHalf));
will correctly allocate and type a 2D array (i. e. an array of arrays) that can be accessed with
mGridHalf[phi][theta] = 7.3;
Since all elements are consecutive in memory, the entire thing can correctly be copied with
memcpy(mGridHalf, cur->mGridHalf, nPhiCells*sizeof(*mGridHalf));
and freed with
free(mGridHalf);
Technically, mGridHalf is now a pointer to an array, the pointer arithmetic that is invoked by the array access effectively does the same computation as if you had written:
float* foo = malloc(nPhiCells*nThetaCells*sizeof(*foo));
foo[phi*nThetaCells + theta] = 7.3;
However, using the correct pointer type float (*)[nThetaCells] allows you to avoid doing the index computation yourself.
The issue is more than likely you're assuming that float** has data that is one contiguous chunk of memory. If so, here is one way of accomplishing this. First, I show the wrong way (but used often):
float** createFloat2D(int nRows, int nCols)
{
float** p1 = new float*[nRows];
for (int i = 0; i < nCols; ++i )
p1[i] = new float[nCols];
return p1;
}
void destroyFloat2D(float**f, int nRows, int nCols)
{
for (int i = 0; i < nCols; ++i )
delete [] f[i];
delete [] f;
}
Looks simple, and works for most purposes, but will fail if the assumption is made that the data is in a contiguous chunk of memory.
The other way to create a 2D array is to make the data contiguous.
float** createFloat2D(int nRows, int nCols)
{
float** p1 = new float*[nRows]; // allocate row pointers
float* p2 = new float[nRows * nCols]; // allocate data in one chunk
for (int i = 0; i < nCols; ++i, p2 += nCols )
p1[i] = p2; // point the row pointers into the pool of memory
return p1;
}
void destroyFloat2D(float**f)
{
delete [] f[0];
delete [] f;
}
Note above that the data is created in one contiguous "pool". Now, using yourArray[0] actually points to the beginning of this memory. Also note that destruction is done without having to know the number of rows or columns, since f[0] points to the pool of memory.
So now, code like this should work
float** mGridB = createFloat2D(nThetaCells, nPhiCells);
//...
memcpy(mGridB[0], cur->mGridB[0], sizeof(float)*nThetaCells*nPhiCells);
The code above now works correctly, if we use the second method of creating the 2d array.
I would still stick with the vector for 1-d float arrays, as you have the pointer to the data (see my earlier comment). For the code above, I would wrap it in a class that handles creation and destruction easily.
The last thing is the copy constructor. A copy constructor in C++ has the following possible signatures:
DGCPM(const DGCPM&);
DGCPM(DGCPM&);
DGCPM(volatile DBCPM&);
I may have missed one, but the signature should be one of those above, more than likely, the first one (you can also have additional arguments after the reference argument, but they all must have default values).
Note that a DBCPM* is not a valid argument for a copy constructor as your code stated -- remember that a copy constructor is not only for use, but also the compiler will use it to make copies. So to signal the compiler that "yes, this function is used to make copies", your function must match one of the signatures above.
In addition, you need an assignment operator, in other words, the class needs to implement the "rule of 3".
This going to sound so stupid (elementary programming error): my index "i" was going beyond (number of models - 1), so I was getting a segmentation fault from accessing memory that didn't exist.

Can't return anything other than 1 or 0 from int function

I wish my first post wasn't so newbie. I've been working with openframeworks, so far so good, but as I'm new to programming I'm having a real headache returning the right value from an int function. I would like the int to increment up until the Boolean condition is met and then decrement to zero. The int is used to move through an array from beginning to end and then back. When I put the guts of the function into the method that I'm using the int in, everything works perfectly, but very messy and I wonder how computationally expensive it is to put there, it just seems that my syntactic abilities are lacking to do otherwise. Advice appreciated, and thanks in advance.
int testApp::updown(int j){
if(j==0){
arp =true;
}
else if (j==7){
arp = false;
}
if(arp == true){
j++;
}
else if(arp == false){
j--;
}
return (j);
}
and then its called like this in an audioRequest block of the library I'm working with:
for (int i = 0; i < bufferSize; i++){
if ((int)timer.phasor(sorSpeed)) {
z = updown(_j);
noteOut = notes [z];
cout<<arp;
cout<<z;
}
EDIT: For addition of some information. Removed the last condition of the second if statement, it was there because I was experiencing strange happenings where j would start walking off the end of the array.
Excerpt of testApp.h
int z, _j=0;
Boolean arp;
EDIT 2: I've revised this now, it works, apologies for asking something so rudimentary and with such terrible code to go with. I do appreciate the time that people have taken to comment here. Here are my revised .cpp and my .h files for your perusal. Thanks again.
#include "testApp.h"
#include <iostream>
using namespace std;
testApp::~testApp() {
}
void testApp::setup(){
sampleRate = 44100;
initialBufferSize = 1024;
//MidiIn.openPort();
//ofAddListener(MidiIn.newMessageEvent, this, &testApp::newMessage);
j = 0;
z= 0;
state = 1;
tuning = 440;
inputNote = 127;
octave = 4;
sorSpeed = 2;
freqOut = (tuning/32) * pow(2,(inputNote-69)/12);
finalOut = freqOut * octave;
notes[7] = finalOut+640;
notes[6] = finalOut+320;
notes[5] = finalOut+160;
notes[4] = finalOut+840;
notes[3] = finalOut+160;
notes[2] = finalOut+500;
notes[1] = finalOut+240;
notes[0] = finalOut;
ofSoundStreamSetup(2,0,this, sampleRate, initialBufferSize, 4);/* Call this last ! */
}
void testApp::update(){
}
void testApp::draw(){
}
int testApp::updown(int &_j){
int tmp;
if(_j==0){
arp = true;
}
else if(_j==7) {
arp = false;
}
if(arp == true){
_j++;
}
else if(arp == false){
_j--;
}
tmp = _j;
return (tmp);
}
void testApp::audioRequested (float * output, int bufferSize, int nChannels){
for (int i = 0; i < bufferSize; i++){
if ((int)timer.phasor(sorSpeed)) {
noteOut = notes [updown(z)];
}
mymix.stereo(mySine.sinewave(noteOut),outputs,0.5);
output[i*nChannels ] = outputs[0];
output[i*nChannels + 1] = outputs[1];
}
}
testApp.h
class testApp : public ofBaseApp{
public:
~testApp();/* destructor is very useful */
void setup();
void update();
void draw();
void keyPressed (int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
void newMessage(ofxMidiEventArgs &args);
ofxMidiIn MidiIn;
void audioRequested (float * input, int bufferSize, int nChannels); /* output method */
void audioReceived (float * input, int bufferSize, int nChannels); /* input method */
Boolean arp;
int initialBufferSize; /* buffer size */
int sampleRate;
int updown(int &intVar);
/* stick you maximilian stuff below */
double filtered,sample,outputs[2];
maxiFilter filter1;
ofxMaxiMix mymix;
ofxMaxiOsc sine1;
ofxMaxiSample beats,beat;
ofxMaxiOsc mySine,myOtherSine,timer;
int currentCount,lastCount,i,j,z,octave,sorSpeed,state;
double notes[8];
double noteOut,freqOut,tuning,finalOut,inputNote;
};
It's pretty hard to piece this all together. I do think you need to go back to basics a bit, but all the same I think I can explain what is going on.
You initialise _j to 0 and then never modify the value of _j.
You therefore call updown passing 0 as the parameter every time.
updown returns a value of 1 when the input is 0.
Perhaps you meant to pass z to updown when you call it, but I cannot be sure.
Are you really declaring global variables in your header file? That's not good. Try to use local variables and/or parameters as much as possible. Global variables are pretty evil, especially declared in the header file like that!