Assigning pre-allocated array to pointer in class constructor C++ - c++

I am working on a project for my advanced CFD class, in which we have to solve the heat equation over a curvilinear mesh. I am trying to create an object which will store all of my data, to allow me to visualize it easily later on. This object is created using a class called Solution. Solution contains 8 public variables, all of which are double precision, *x, *y, *u, *v, *T, nx, ny and N, where x and y store the coordinates for each point, u and v the velocities for each point, T stores the temperature for each point, nx and ny store the number of grid points in the x and y direction, and finally N stores the total number of grid points. I have 3 constructors, the first of which initializes the object with all null pointers or values of 0.
Solution::Solution() : X(nullptr), Y(nullptr), u(nullptr), v(nullptr), T(nullptr), nx(0), ny(0), N(0)
The second constructor takes a value for nx and ny, calculates the number of points, allocates memory for each of the arrays, and initializes their values to 0.
// Constructor to initialize solution struct with 0 values
Solution::Solution(unsigned long iNx, unsigned long iNy) : X(nullptr), Y(nullptr), u(nullptr), v(nullptr), T(nullptr), nx(iNx), ny(iNy)
{
N = nx * ny; // Total number of grid points
// Allocate memory for solution variables
O.alloc1D(&X, N);
O.alloc1D(&Y, N);
O.alloc1D(&u, N);
O.alloc1D(&v, N);
O.alloc1D(&T, N);
// Initialize variables values to 0
for(int i = 0; i < N; i++)
{
X[i] = 0.0;
Y[i] = 0.0;
u[i] = 0.0;
v[i] = 0.0;
T[i] = 0.0;
}
}
Where I am having trouble is for my 3rd constructor, in which I hope to create the object using pre-defined arrays.
// Constructor to initialize solution struct using vectors that already exist
Solution::Solution(unsigned long iNx, unsigned long iNy, double *iX, double *iY, double *iu, double *iv, double *iT) :
X(iX), Y(iY), u(iu), v(iv), T(iT), nx(iNx), ny(iNy)
I am having issues figuring out how to assign the arrays to these values. Looking at just X, if I try to implement an array
double x[4] = {1.0, 2.0, 3.0, 4.0};
for X in the constructor it gives me an error as it cannot assign a double to double*. If I try to write
double *x[4] = {1.0, 2.0, 3.0, 4.0};
it gives me an error as it cannot assign double to double* for each value in the array. If I try
double *x;
double x1[4] = {1, 2, 3, 4};
x = &x1;
it gives me an error because it cannot convert double(*)[4] to double in initialization. I feel like there is an easy solution to let me construct my Solution object with arrays that are already defined, but I'm getting stuck. Thank you for your help.

Related

Why is my code throwing a SIGBUS error, even when I store variables in heap?

In the method plotThermalNoise() of the Antenna class, for some reason the for loop does not run. Initially, I used int for n and i, however I need to work with much larger numbers than int can hold. SO, now I'm using a long int for both. The program no longer works, however. I stepped through it with GDB, and it seems I'm getting a SIGBUS error. I tried using new so as to store both variables in heap, however the loop still doesn't run.
#define k 0.0000000000000000000000138064852 //Boltzmann's constant
class Antenna{
double _srate, _sdur, _res, _temp, _band;
public:
Antenna(double sampling_rate, double sample_duration, double resistance_ohms, double temperature_kelvin, double bandwidth_Hz){
_srate = sampling_rate; _sdur = sample_duration;
_res = resistance_ohms; _temp = temperature_kelvin;
_band = bandwidth_Hz;
}
void plotThermalNoise();
};
void Antenna::plotThermalNoise(){
//calculate RMS, mean of Gaussian
double RMS = sqrt(4 * _res * k * _temp * _band);
double V = sqrt((4 * k * _temp * _band) / _res);
long int n = _srate / _sdur;
double x[*n],y[*n];
gRandom->SetSeed(time(NULL));
for(long int i = 0; i < n; ++i){
x[i] = i;
y[i] = gRandom->Gaus(V,RMS);
}
TGraph gr = new TGraph(n,x,y);
gr->SetTitle("Thermal Noise Voltage vs Time Trace;Seconds;Volts");
gr->Draw();
}
void dataAquisitionSim(){
Antenna test(4000000000, 0.000001, 50, 90, 500);
test.plotThermalNoise();
}
long int n = _srate / _sdur;
double x[*n],y[*n];
This code will not compile. I assume your actual code is:
long int n = _srate / _sdur;
double x[n],y[n];
With the parameters you pass in: 4000000000 for _srate and 0.000001 for _sdur, n becomes 4,000,000,000 / 0.000,000,1 == 4,000,000,000,000,000.
You then attempt to allocate two double arrays of that size on stack. The total size of these arrays is 64 peta-bytes.
The largest super-computer currently in existence has "over 10PiB of memory". So you only need something mere 6 times larger than that.
it seems I'm getting a SIGBUS error.
As you should. Some back of the envelope calculations should help you realize that just because your code compiles doesn't mean it will run.
even when I store variables in heap?
Unless you actually have a computer with more than 64PiB of RAM, stack vs. heap is irrelevant -- you'll run out of either.

How to customize range of setRandom?

Eigen provides facilities to play with Matrices, and vectors (where one dimension is 1). I'm trying to develop a function which fills a vector (double *array) with random numbers made by setRandom.
double *gen_random(int size, double min, double max) {
double *array = new double[size * sizeof(double)];
Matrix<double, Dynamic, Dynamic, RowMajor>::Map(array, size, 1).setRandom();
return array;
}
The code above does that but random range is [-1:1] as per https://eigen.tuxfamily.org/dox/classEigen_1_1PlainObjectBase.html#title35.
How do I change range to i.e. [0:99]?
Answer and comments so far seems to suggest adding a loop to obtain the desired result, like:
double *gen_random(int size, double min, double max) {
double *array = new double[size * sizeof(double)];
Matrix<double, Dynamic, Dynamic, RowMajor>::Map(array, size, 1).setRandom();
for (int i = 0; i < size; ++i)
array[i] = (array[i]+1)*50;
return array;
}
Here is a complete, single line, solution:
double *gen_random(int size, double min, double max) {
double *array = new double[size * sizeof(double)];
ArrayXd::Map(array,size) = (ArrayXd::Random(size)+1.)*0.5*(max-min) + min;
return array;
}
I'm using Array instead of linear-algebra Vector or Matrix to enable addition with a scalar.
As suggested in the comments, you should probably just perform arithmetic to get your random values into the desired range (i.e. +1, then * 50). This is basically what would happen with a different requested range anyway.

Initializing a box with N particles arranged in a specific pattern

I'm new to C++, and as an exercise I'm trying to reproduce what was done by Metropolis et al. (Metropolis Monte Carlo).
What I have done thus far - Made 2 classes: Vector and Atom
class Vector {
public:
double x;
double y;
Vector() {
}
Vector (double x_, double y_) {
x = x_;
y = y_;
}
double len() {
return sqrt(x*x + y*y);
}
double lenSqr() {
return x*x + y*y;
}
};
class Atom {
public:
Vector pos;
Vector vel;
Vector force;
Atom (double x_, double y_) {
pos = Vector(x_, y_);
vel = Vector(0, 0);
force = Vector(0, 0);
}
double KE() {
return .5 * vel.lenSqr();
}
};
I am not certain that the way I have defined the class Atom is... the best way to go about things since I will not be using a random number generator to place the atoms in the box.
My problem:
I need to initialize a box of length L (in my case L=1) and load it with 224 atoms/particles in an offset lattice (I have included a picture). I have done some reading and I was wondering if maybe an array would be appropriate here.
One thing that I am confused about is how I could normalize the array to get the appropriate distance between the particles and what would happen to the array once the particles begin to move. I am also not sure how an array could give me the x and y position of each and every atom in the box.
Metropolis offset (hexagonal) lattice
Well, It seems, that generally you don't need to use array to represent the lattice. In practice most often it may sense to represent lattice as array only if your atoms can naturally move only on the cells (for example as figures in chess). But seems that your atoms can move in any direction (already not practicle to use such rigid structure as array, because it has naturally 4 or 8 directions for move in 2D) by any step (it is bad for arrays too, because in this case you need almost countless cells in array to represent minimal distance step).
So basically what do you need is just use array as storage for your 224 atoms and set particular position in lattice via pos parameter.
std::vector<Atom> atoms;
// initialize atoms to be in trigonal lattice
const double x_shift = 1. / 14;
const double y_shift = 1. / 16;
double x_offset = 0;
for (double y = 0; y < 1; y += y_shift){
for (double x = x_offset; x < 1; x += x_shift){
// create atom in position (x, y)
// and store it in array of atoms
atoms.push_back(Atom(x, y));
}
// every new row flip offset 0 -> 1/28 -> 0 -> 1/28...
if (x_offset == 0){
x_offset = x_shift / 2;
}
else{
x_offset = 0;
}
}
Afterwards you just need to process this array of atoms and change their positions, velocities and what you need else according to algorithm.

Matrix multiplication issues using C++ Eigen, and matlab mexFunction

// computing the matrix operation here
// resultEigen = Input matrix
// result1Eigen = hidden bias
// result2Eigen = visible bias
// result3Eigen = weight matrix
MatrixXd H;
MatrixXd V;
double well[36];
Map<MatrixXd>( well, H.rows(), H.cols() ) = H;
H = resultEigen * result3Eigen + result1Eigen;
mexPrintf("H is here\n");
for (int i=0; i<36; i++)
{
mexPrintf("%d\n",H);
}
mexPrintf("\n");
I need to build a reconstructing function for my RBM and since direct matrix multiplication could get me a better result, I have been referring to eigen library to solve my issues but I am facing some difficulties.
when running the above code I end up getting a single value for the H matrix and I wonder why!
Moreover the parameters used in for the computation of H have been initiated as follows:
double *data1 = hbias;
Map<VectorXd>hidden_bias(data1,6,1);
VectorXd result1Eigen;
double result1[6];
result1Eigen = hidden_bias.transpose();
Map<VectorXd>(result1, result1Eigen.cols()) = result1Eigen;
// next param
double *data2 = vbias;
Map<VectorXd>visible_bias(data2,6,1);
VectorXd result2Eigen;
double result2[6];
result2Eigen = visible_bias.transpose();
Map<VectorXd>(result2, result2Eigen.cols()) = result2Eigen;
// next param
double *data3 = w;
Map<MatrixXd>weight_matrix(data3,n_visible,n_hidden);
MatrixXd result3Eigen;
// double result3[36];
mxArray * result3Matrix = mxCreateDoubleMatrix(n_visible, n_hidden, mxREAL );
double *result3=(double*)mxGetData(result3Matrix);
result3Eigen = weight_matrix.transpose();
Map<MatrixXd>(result3, result3Eigen.rows(), result3Eigen.cols()) = result3Eigen
At last I also face issues printing out data using std::cout from inside the mexFunction.
Thanks for any hints.
The problem is in the printing code which should be:
mexPrintf("%d\n",H(i));
Then, there is no need to duplicate vectors and matrices. For instance, result1 is useless, as you can get a raw pointer to the data stored in result1Eigen using result1Eigen.data(). Likewise, you can directly assign weight_matrix.transpose() to Map<MatrixXd>(result3,...), and I don't see the purpose of well.
Finally, if sizes are really known at compile-time, then better using Matrix<double,6,1> instead of a VectorXd and Matrix<double,6,6> instead of a MatrixXd. Yo ucan expect significant speedup.

How do I get the Polynomial Interpolation coefficients using gsl_interp?

So I have the code below. It perfectly calculates all the y-points of the polynomial (and prints them to plot with gnuplot), but how do i get the resulting polynomial (1-x² in this case)?
void twoDegreePoly() {
int n = 3;
double x[n],y[n];
printf ("#m=0,S=16\n");
for (int i=0; i<n ;i++) {
x[i] = ((double)2*i)/2 -1;
y[i] = f(x[i]);
printf ("%g %g\n", x[i], y[i]);
}
printf ("#m=1,S=0\n");
gsl_interp_accel *acc = gsl_interp_accel_alloc ();
const gsl_interp_type *t = gsl_interp_polynomial;
gsl_interp* poly = gsl_interp_alloc(t,n);
gsl_interp_init (poly, x, y,n);
for (double xi=x[0]; xi<x[n-1]; xi+= 0.01) {
double yi = gsl_interp_eval (poly, x, y, xi, acc);
printf ("%g %g\n", xi, yi);
}
}
After a quick scan over the documentation, it doesn't seem that such a feature is available in the GSL. This could be caused by two reasons: first, getting polynomial coeffcients is special to this interpolation method doesn't fit well into the general design (which can handle arbitrary functions). Second, citing Numerical Recipes:
Please be certain, however, that the coefficients are what you need. Generally, the coefficients of the interpolating polynomial can be determined much less accurately than its value at a desired abscissa. Therefire, it is not a good idea to determine the coefficients only for use in calculating interpolating values. Values thus calculated will not pass exactly through the tabulated points, for example, ...
The reason for this is that in principle, calculating the coefficients involves solving a linear system with a Vandermonde matrix, which is highly ill-conditioned.
Still, Numerical Recipes gives a routine polcoe by which you can obtain the interpolating polynomial. You can find it in chapter 3.5. in the free second edition.
I have done something similar with the Akima's interpolation.
First, define the state as GSL do:
typedef struct
{
double *b;
double *c;
double *d;
double *_m;
}akima_state_t;
Then, create the interpolant
spline = gsl_spline_alloc (gsl_interp_akima, M_size);
gsl_spline_init (spline, x, y, M_size);
and after that, you can do :
const akima_state_t *state = (const akima_state_t *) ( spline -> interp -> state);
double _b,_c,_d;
for (int i = 0; i < M_size; i++)
{
_b = state->b[i];
_c = state->c[i];
_d = state->d[i];
std::cout << "(x>"<<x[i]<<")*(x<"<<x[i+1]<<")*("<<y[i]<< "+ (x-"<< x[i]<<")*("<<_b<<"+(x-"<< x[i]<<")*("<<_c<<"+"<<_d<<"*(x-"<<x[i]<<")))) + ";
}
I do not have tried with a polynomial interpolation, but here the state struct for polynomial, it should be a good starting point.
typedef struct
{
double *d;
double *coeff;
double *work;
}
polynomial_state_t;