I am writing a program which will preform texture synthesis. I have been away from C++ for a while and am having trouble figuring out what I am doing wrong in my class. When I run the program, I get an unhandled exception in the copyToSample function when it tries to access the arrays. It is being called from the bestSampleSearch function when the unhandled exception occurs. The function has been called before and works just fine, but later on in the program it is called a second time and fails. Any ideas? Let me know if anyone needs to see more code. Thanks!
Edit1: Added the bestSampleSearch function and the compareMetaPic function
Edit2: Added a copy constructor
Edit3: Added main()
Edit4: I have gotten the program to work. However there is now a memory leak of some kind or I am running out of memory when I run the program. It seems in the double for loop in main which starts "// while output picture is unfilled" is the problem. If I comment this portion out the program finishes in a timely manner but only one small square is output. Something must be wrong with my bestSampleSearch function.
MetaPic.h
#pragma once
#include <pic.h>
#include <stdlib.h>
#include <cmath>
class MetaPic
{
public:
Pic* source;
Pixel1*** meta;
int x;
int y;
int z;
MetaPic();
MetaPic(Pic*);
MetaPic(const MetaPic&);
MetaPic& operator=(const MetaPic&);
~MetaPic();
void allocateMetaPic();
void copyPixelData();
void copyToOutput(Pic*&);
void copyToMetaOutput(MetaPic&, int, int);
void copyToSample(MetaPic&, int, int);
void freeMetaPic();
};
MetaPic.cpp
#include "MetaPic.h"
MetaPic::MetaPic()
{
source = NULL;
meta = NULL;
x = 0;
y = 0;
z = 0;
}
MetaPic::MetaPic(Pic* pic)
{
source = pic;
x = pic->nx;
y = pic->ny;
z = pic->bpp;
allocateMetaPic();
copyPixelData();
}
MetaPic::MetaPic(const MetaPic& mp)
{
source = mp.source;
x = mp.x;
y = mp.y;
z = mp.z;
allocateMetaPic();
copyPixelData();
}
MetaPic::~MetaPic()
{
freeMetaPic();
}
// create a 3 dimensional array from the original one dimensional array
void MetaPic::allocateMetaPic()
{
meta = (Pixel1***)calloc(x, sizeof(Pixel1**));
for(int i = 0; i < x; i++)
{
meta[i] = (Pixel1**)calloc(y, sizeof(Pixel1*));
for(int j = 0; j < y; j++)
{
meta[i][j] = (Pixel1*)calloc(z, sizeof(Pixel1));
}
}
}
void MetaPic::copyPixelData()
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < x; i++)
{
for(int k = 0; k < z; k++)
meta[i][j][k] = source->pix[(j*z*x)+(i*z)+k];
}
}
}
void MetaPic::copyToOutput(Pic* &output)
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < x; i++)
{
for(int k = 0; k < z; k++)
output->pix[(j*z*x)+(i*z)+k] = meta[i][j][k];
}
}
}
// copy the meta data to the final pic output starting at the top left of the picture and mapped to 'a' and 'b' coordinates in the output
void MetaPic::copyToMetaOutput(MetaPic &output, int a, int b)
{
for(int j = 0; (j < y) && ((j+b) < output.y); j++)
{
for(int i = 0; (i < x) && ((i+a) < output.x); i++)
{
for(int k = 0; k < z; k++)
output.meta[i+a][j+b][k] = meta[i][j][k];
}
}
}
// copies from a source image to a smaller sample image
// *** Must make sure that the x and y coordinates have enough buffer space ***
void MetaPic::copyToSample(MetaPic &sample, int a, int b)
{
for(int j = 0; (j < sample.y) && ((b+j) < y); j++)
{
for(int i = 0; i < (sample.x) && ((a+i) < x); i++)
{
for(int k = 0; k < sample.z; k++)
{
**sample.meta[i][j][k] = meta[i+a][j+b][k];**
}
}
}
}
// free the meta pic data (MetaPic.meta)
// *** Not to be used outside of class declaration ***
void MetaPic::freeMetaPic()
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < z; i++)
free(meta[i][j]);
}
for(int i = 0; i < x; i++)
free(meta[i]);
free(meta);
}
MetaPic MetaPic::operator=(MetaPic mp)
{
MetaPic newMP(mp.source);
return newMP;
}
main.cpp
#ifdef WIN32
// For VC++ you need to include this file as glut.h and gl.h refer to it
#include <windows.h>
// disable the warning for the use of strdup and friends
#pragma warning(disable:4996)
#endif
#include <stdio.h> // Standard Header For Most Programs
#include <stdlib.h> // Additional standard Functions (exit() for example)
#include <iostream>
// Interface to libpicio, provides functions to load/save jpeg files
#include <pic.h>
#include <string.h>
#include <time.h>
#include <cmath>
#include "MetaPic.h"
using namespace std;
MetaPic bestSampleSearch(MetaPic, MetaPic);
double compareMetaPics(MetaPic, MetaPic);
#define SAMPLE_SIZE 23
#define OVERLAP 9
// Texture source image (pic.h uses the Pic* data structure)
Pic *sourceImage;
Pic *outputImage;
int main(int argc, char* argv[])
{
char* pictureName = "reg1.jpg";
int outputWidth = 0;
int outputHeight = 0;
// attempt to read in the file name
sourceImage = pic_read(pictureName, NULL);
if(sourceImage == NULL)
{
cout << "Couldn't read the file" << endl;
system("pause");
exit(EXIT_FAILURE);
}
// *** For now set the output image to 3 times the original height and width ***
outputWidth = sourceImage->nx*3;
outputHeight = sourceImage->ny*3;
// allocate the output image
outputImage = pic_alloc(outputWidth, outputHeight, sourceImage->bpp, NULL);
Pic* currentImage = pic_alloc(SAMPLE_SIZE, SAMPLE_SIZE, sourceImage->bpp, NULL);
MetaPic metaSource(sourceImage);
MetaPic metaOutput(outputImage);
MetaPic metaCurrent(currentImage);
// seed the output image
int x = 0;
int y = 0;
int xupperbound = metaSource.x - SAMPLE_SIZE;
int yupperbound = metaSource.y - SAMPLE_SIZE;
int xlowerbound = 0;
int ylowerbound = 0;
// find random coordinates
srand(time(NULL));
while((x >= xupperbound) || (x <= xlowerbound))
x = rand() % metaSource.x;
while((y >= yupperbound) || (y <= ylowerbound))
y = rand() % metaSource.y;
// copy a random sample from the source to the metasample
metaSource.copyToSample(metaCurrent, x, y);
// copy the seed to the metaoutput
metaCurrent.copyToMetaOutput(metaOutput, 0, 0);
int currentOutputX = 0;
int currentOutputY = 0;
// while the output picture is unfilled...
for(int j = 0; j < yupperbound; j+=(SAMPLE_SIZE-OVERLAP))
{
for(int i = 0; i < xupperbound; i+=(SAMPLE_SIZE-OVERLAP))
{
// move the sample to correct overlap
metaSource.copyToSample(metaCurrent, i, j);
// find the best match for the sample
metaCurrent = bestSampleSearch(metaSource, metaCurrent);
// write the best match to the metaoutput
metaCurrent.copyToMetaOutput(metaOutput, i, j);
// update the values
}
}
// copy the metaOutput to the output
metaOutput.copyToOutput(outputImage);
// output the image
pic_write("reg1_output.jpg", outputImage, PIC_JPEG_FILE);
// clean up
pic_free(sourceImage);
pic_free(outputImage);
pic_free(currentImage);
// return success
cout << "Done!" << endl;
system("pause");
// return success
return 0;
}
// finds the best sample to insert into the image
// *** best must be the sample which consists of the overlap ***
MetaPic bestSampleSearch(MetaPic source, MetaPic best)
{
MetaPic metaSample(best);
double bestScore = 999999.0;
double currentScore = 0.0;
for(int j = 0; j < source.y; j++)
{
for(int i = 0; i < source.x; i++)
{
// copy the image starting at the top left of the source image
source.copyToSample(metaSample, i, j);
// compare the sample with the overlap
currentScore = compareMetaPics(best, metaSample);
// if best score is greater than current score then copy the better sample to best and continue searching
if( bestScore > currentScore)
{
metaSample.copyToSample(best, 0, 0);
bestScore = currentScore;
}
// otherwise, the score is less than current score then do nothing (a better sample has not been found)
}
}
return best;
}
// find the comparison score for the two MetaPics based on their rgb values
// *** Both of the meta pics should be the same size ***
double compareMetaPics(MetaPic pic1, MetaPic pic2)
{
float r1 = 0.0;
float g1 = 0.0;
float b1 = 0.0;
float r2 = 0.0;
float g2 = 0.0;
float b2 = 0.0;
float r = 0.0;
float g = 0.0;
float b = 0.0;
float sum = 0.0;
// take the sum of the (sqrt((r1-r2)^2 + ((g1-g2)^2 + ((b1-b2)^2))
for(int j = 0; (j < pic1.y) && (j < pic2.y); j++)
{
for(int i = 0; (i < pic1.x) && (i < pic2.x); i++)
{
r1 = PIC_PIXEL(pic1.source, i, j, 0);
r2 = PIC_PIXEL(pic2.source, i, j, 0);
g1 = PIC_PIXEL(pic1.source, i, j, 1);
g2 = PIC_PIXEL(pic2.source, i, j, 1);
b1 = PIC_PIXEL(pic1.source, i, j, 2);
b2 = PIC_PIXEL(pic2.source, i, j, 2);
r = r1 - r2;
g = g1 - g2;
b = b1 - b2;
sum += sqrt((r*r) + (g*g) + (b*b));
}
}
return sum;
}
I'm not sure if this is the root cause of the problem, but your assignment operator does not actually assign anything:
MetaPic MetaPic::operator=(MetaPic mp)
{
MetaPic newMP(mp.source);
return newMP;
}
This should probably look something like the following (based off of the code in your copy constructor):
edit: with credit to Alf P. Steinbach
MetaPic& MetaPic::operator=(MetaPic mp)
{
mp.swap(*this);
return *this;
}
It turns out that the deallocate function is incorrect. It should be freeing in the same manner that it was allocating.
void MetaPic::freeMetaPic()
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < z; i++)
free(meta[i][j]);
}
for(int i = 0; i < x; i++)
free(meta[i]);
free(meta);
}
Related
I tried to generate two random integers j and k using the OMNET++ function intrand() but the first variable j takes a number out of the range. I had the same problem on OMNeT++6.0pre11 (installed on Ubuntu 18.04) and I thought that it was related to the software misbehavior. Then, I upgraded my OS to Ubuntu 20.04 and installed the OMNeT++6.0pre15 but I'm still experiencing the same issue.
Below are my piece of code and the output:
In my .h
public:
struct clusteringStruct {
int CH_Index;
map<int,double> Members;
double FitnessValue;
int trial = 0;
double proba;
double X[];
};
void generateNewSol(int n,clusteringStruct Cluster[],int z);
In my .cc
int D = 2;
clusteringStruct Cluster[5];
// Initialization...
for(t = 0; t < 5; ++t) {
Cluster[t].X[0] = 0.5; // CH Residual Energy
Cluster[t].X[1] = 500*sqrt(2); // Max distance
}
// Execution...
for(int i = 0; i < 5; i++) {
generateNewSol(i,Cluster,D);
}
void generateNewSol(int i,clusteringStruct Cluster[],int D) {
// Randomly select the variable j that is to be changed
int j = intrand(D);
// Randomly select the neighbour k and ensure that he is different from i
int k = intrand(5);
while(k == i) {
k = intrand(5);
}
clusteringStruct sol = Cluster[i];
for(int q = 0; q < D; q++) {
sol.X[q] = Cluster[i].X[q];
}
EV_DEBUG <<" i = "<<i<<" || j = "<<j<<" || k = "<<k<<endl;
}
The Output of j and k variable is per the image below :
Thanks in advance for your help.
I am trying to use the suggestion from this post to free up time being spent in _platform_memmove$VARIANT$Haswell. According to a time profiler, this is occurring when I send a pointer to several class instances to a function. I have tried changing the way I declare the class instances, changing what the function takes, etc. but have not been able to resolve this.
The chunk of my code that may help:
Inputs *tables = new Inputs(OutputFolder, DataFolder);
ScreenStrat *strat_burnin = new ScreenStrat(ScreenStrat::NoScreen, ScreenStrat::NoScreen,
tables->ScreenStartAge, tables->ScreenStopAgeHIV,
tables->ScreenStopAge, ScreenStrat::NoVaccine);
calibrate *calib_output = new calibrate ();
StateMachine *Machine = new StateMachine();
for (int i = 0; i < n_sims; i++){
calib_output->saved_output[i] = RunCalibration(calib_output->calib_params[i], *strat_burnin, *tables, *Machine);
}
auto ret_val = *calib_output;
delete strat_burnin;
delete tables;
delete Machine;
delete calib_output;
return(ret_val);
and then the function declaration:
vector<double> RunCalibration(vector<double> calib_params, ScreenStrat &strat_burnin, Inputs &tables, StateMachine &Machine)
EDIT
I addressed the points #Botje suggest and it hasn't fixed the problems. Updated code:
void RunCalibration(calibrate &calib, ScreenStrat &strat_burnin, Inputs &tables, StateMachine &Machine, int i);
unique_ptr<calibrate> RunChain(string RunsFileName, string CurKey, string OutputFolder, string DataFolder);
int main(int argc, char* argv[]) {
string DataFolder;
string OutputFolder;
DataFolder = "../Data/";
OutputFolder = "../Output/";
unsigned int run;
string CurKey;
string RunsFileName(DataFolder);
if(argc == 1){
RunsFileName.append("test.ini");
}
else if(argc > 1){
RunsFileName.append(argv[1]);
}
CIniFile RunsFile(RunsFileName);
if (!RunsFile.ReadFile()) {
cout << "Could not read Runs File: " << RunsFileName << endl;
exit(1);
}
CurKey = RunsFile.GetKeyName (0);
if (RunsFile.GetValue(CurKey, "RunType") == "Calibration"){
int totaliters = RunsFile.GetValueI(CurKey, "Iterations");
int n_sims = RunsFile.GetValueI(CurKey, "Simulations");
vector<future<unique_ptr<calibrate>>> futures;
vector<unique_ptr<calibrate>> modeloutputs;
for (run = 0; run < totaliters; run++){
futures.push_back (async(launch::async, RunChain, RunsFileName, CurKey, OutputFolder, DataFolder));
}
for (int i = 0; i < futures.size(); i++){
modeloutputs.push_back (futures[i].get());
} return(0)}
unique_ptr<calibrate> RunChain(string RunsFileName, string CurKey, string OutputFolder, string DataFolder) {
Inputs *tables = new Inputs(OutputFolder, DataFolder);
tables->loadRFG (RunsFileName, CurKey);
tables->loadVariables ();
int n_sims = tables->Simulations;
int n_params = tables->Multipliers.size();
int n_targs = tables->CalibTargs.size();
ScreenStrat *strat_burnin = new ScreenStrat(ScreenStrat::NoScreen, ScreenStrat::NoScreen,
tables->ScreenStartAge, tables->ScreenStopAgeHIV,
tables->ScreenStopAge, ScreenStrat::NoVaccine);
calibrate *calib_output = new calibrate (n_sims, n_params, n_targs);
calib_output->multipliers_names = tables->MultipliersNames;
calib_output->calib_targs_names = tables->CalibTargsNames;
for (int i = 0; i < n_targs; i ++){
calib_output->calib_targs[i] = tables->CalibTargs[i][0];
calib_output->calib_targs_SD[i] = tables->CalibTargs[i][1];
}
for (int i = 0; i < n_params; i++){
for (int j = 0; j < 3; j++){
calib_output->multipliers[i][j] = tables->Multipliers[i][j];
}
}
StateMachine *Machine = new StateMachine();
for (int i = 0; i < n_sims; i++){
RunCalibration(*calib_output, *strat_burnin, *tables, *Machine, i);
}
unique_ptr<calibrate> ret_val = make_unique<calibrate>(*calib_output);
delete strat_burnin;
delete tables;
delete Machine;
delete calib_output;
return(ret_val);
}
void RunCalibration(calibrate &calib, ScreenStrat &strat_burnin, Inputs &tables, StateMachine &Machine, int i){
Adding in Calibrate definition per request from #botje
#include "calibrate.h"
using namespace std;
calibrate::calibrate(int n_sims, int n_params, int n_targs) {
calib_targs.resize (n_targs);
calib_targs_SD.resize (n_targs);
multipliers.resize(n_params);
for(int i = 0; i < n_params; i++){
multipliers[i].resize(3);
}
calib_params.resize (n_sims);
for (int i = 0; i < calib_params.size(); i++){
calib_params[i].resize (n_params);
}
saved_output.resize (n_sims);
for (int i = 0; i < saved_output.size(); i++){
saved_output[i].resize (n_targs);
}
best_params.resize (n_params);
GOF.clear();
tuned_SD.resize(n_params);
}
calibrate::~calibrate(void) {
}
void calibrate::CalculateGOF(int n_sims) {
GOF.push_back (WeightedDistance (saved_output[n_sims][0], calib_targs[0], calib_targs_SD[0]));
for (int i = 1; i < calib_targs.size(); i ++){
GOF[n_sims] += WeightedDistance (saved_output[n_sims][i], calib_targs[i], calib_targs_SD[i]);
}
if (n_sims == 0){
GOF_min = GOF[0];
best_params = calib_params[0];
} else {
auto it = std::min_element(std::begin(GOF), std::end(GOF));
int index = distance(GOF.begin(), it);
GOF_min_run = GOF[index];
if (GOF_min_run < GOF_min){
GOF_min = GOF_min_run;
best_params = calib_params[index];
}
}
}
std::vector<double> calibrate::loadCalibData(int n_params, int n_sim, int tuning_factor) {
if(n_sim == 0){
random_device rd;
mt19937 gen(rd());
for (int i = 0; i < n_params; i ++ ){
uniform_real_distribution<> dis(multipliers[i][0], multipliers[i][1]);
calib_params[n_sim][i] = dis(gen);
}
} else {
tuned_SD = tuningparam (n_sim, n_params, tuning_factor);
for (int i = 0; i < n_params; i ++ ){
calib_params[n_sim][i] = rnormal_trunc (best_params[i], tuned_SD[i], multipliers[i][1], multipliers[i][0]);
}
}
return(calib_params[n_sim]);
}
double calibrate::WeightedDistance(double data, double mean, double SD) {
double distance = pow((data - mean)/(SD * 2),2);
return distance;
}
double calibrate::rnormal_trunc(double mu, double sigma, double upper, double lower) {
std::default_random_engine generator;
std::normal_distribution<double> distribution(mu, sigma);
double prob = distribution(generator);
while (prob < lower || prob > upper){
prob = distribution(generator);
}
return(prob);
}
vector<double> calibrate::tuningparam(int n_sims, int n_param, int tuning_factor) {
vector<double> newSD;
for (int i = 0; i < n_param; i++){
newSD.push_back (multipliers[i][2]/pow(tuning_factor,n_sims));
}
return newSD;
}
I improved RunCalibration as follows. Note the comments for further improvement opportunities.
using std::make_unique;
using std::unique_ptr;
void RunCalibration(calibrate &calib, ScreenStrat &strat_burnin, Inputs &tables, StateMachine &Machine, int i);
unique_ptr<calibrate> RunChain(string RunsFileName, string CurKey, string OutputFolder, string DataFolder) {
auto tables = make_unique<Inputs>(OutputFolder, DataFolder);
tables->loadRFG (RunsFileName, CurKey);
tables->loadVariables ();
int n_sims = tables->Simulations;
int n_params = tables->Multipliers.size();
int n_targs = tables->CalibTargs.size();
auto strat_burnin = make_unique<ScreenStrat>(
ScreenStrat::NoScreen, ScreenStrat::NoScreen,
tables->ScreenStartAge, tables->ScreenStopAgeHIV,
tables->ScreenStopAge, ScreenStrat::NoVaccine);
auto calib_output = make_unique<calibrate>(n_sims, n_params, n_targs);
// I don't know the type of these fields, but IF you do not modify them in
// `RunCalibration`, consider making them `shared_ptr<vector<...>>`
// both in `calibrate` and in `Inputs` so you can simply copy
// the pointer instead of the full table.
calib_output->multipliers_names = tables->MultipliersNames;
calib_output->calib_targs_names = tables->CalibTargsNames;
// Same applies here. If you do not modify CalibTargs, make `calib_targs` a shared_ptr
// and only copy by pointer.
for (int i = 0; i < n_targs; i ++){
calib_output->calib_targs[i] = tables->CalibTargs[i][0];
calib_output->calib_targs_SD[i] = tables->CalibTargs[i][1];
}
// and again...
for (int i = 0; i < n_params; i++){
for (int j = 0; j < 3; j++){
calib_output->multipliers[i][j] = tables->Multipliers[i][j];
}
}
auto Machine = make_unique<StateMachine>();
for (int i = 0; i < n_sims; i++){
RunCalibration(*calib_output, *strat_burnin, *tables, *Machine, i);
}
// This will return the unique_ptr without copying.
return calib_output;
}
So I have my program here:
#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <math.h>
#include <stdlib.h>
using namespace std;
int const size = 3;
struct Arguments{
int array[];
float result1[];
float result2[];
};
//void calc(int arr[], float rarr1[], float rarr2[], int size);
void* calc(void *param);
int main(int argc, char *argv[]){
time_t t;
srand((unsigned) time(&t));
int arr[size][size] = {};
float rarr1[size][size-1] = {};
float rarr2[size][size-1] = {};
for(int x = 0; x < size; x++){
for(int y = 0; y < size; y++){
int number = rand()%10;
arr[x][y] = number;
}
}
for(int x = 0; x < size; x++){
for(int y = 0; y < size; y++){
cout << arr[x][y] << " ";
}
cout << endl;
}
cout << endl;
/////////////////////////////////////////
pthread_t child;
struct Arguments input;
for(int i = 0; i < size; i++){
input.array[i] = arr[0][i];
}
pthread_create(&child, NULL, calc, (void*)&input);
pthread_join(child, NULL);
//calc(&input);
for(int i = 0; i < size-1; i++){
rarr1[0][i] = input.result1[i];
cout << "Test: " << rarr1[0][i] << endl;
}
//////////////////////////////////
return 0;
}
//void calc(int arr[], float rarr1[], float rarr2[], int size){
void* calc(void *param){
struct Arguments *input = (struct Arguments*)param;
int arr1[] = {};
float rarr1[] = {};
float rarr2[] = {};
for(int i = 0; i < size; i++){
arr1[i] = input->array[i];
}
for(int i = 0; i < size; i++){
int a = arr1[i];
int b = arr1[i+1];
int difference = a-b;
if(difference < 0){
difference = difference * -1;
}
float euc = 1 + pow(difference, 2);
euc = sqrt(euc);
rarr1[i] = euc;
}
for(int i = 0; i <size-1; i++){
input->result1[i] = rarr1[i];
}
for(int i = 0; i <size-1; i++){
int a = arr1[i];
int b = arr1[i+1];
int difference = a-b;
if(difference < 0){
difference = difference * -1;
}
float apar = (difference/rarr1[i]);
float result = asin(apar);
result = result*(180/3.14);
rarr2[i] = result;
}
return NULL;
}
The important part that causes the trouble is between ////// lines but I left the rest of the code for the context, since it might be useful.
So I have the function calc(param); that does the important calculation in the program.
It is working just fine as long as I call it myself (by actually including the function call in the code) and the test loop right after it gives the correct results.
However, when I try to use pthread_create(); to create a new thread that will take care of executing that function, the test loop spits out nonsense and some random huge numbers different each time.
It's kinda weird because the code compiles either way, and literally the only thing that I change is these 2 lines.
What am I doing wrong and why the function spits out garbage when started by the Pthread? Is there a way to fix it?
Ok so if anyone's having a similar problem:
Declare the size of arrays no matter what. It turns out that my program didn't work properly because I initialized my result arrays as float result1[]; instead of float result1[size];
I have a vector of objects obj (of class Holder) with N elements with members like x and y which are also vectors of double type with M elements. I would like to write a text file creating an MxN matrix from this. I have tried lots of different things to no avail up to now.
vector<Holder> obj(N);
void savedata(string filename, vector<Holder> obj, int M, int N) {
ofstream out(filename);
for(int i = 0; i < M; i++) {
for(int j = 0; j < N; j++) {
out << obj[i][j] << "\t" << endl;
}
}
}
But this just takes the last set of values. How can I create such an MxN matrix where rows are from the object member vector x and columns are from the object vector itself?
Thank you in advance.
--
The bigger version of the code is as follows:
//
//
#include <iostream>
#include <cmath>
#include <fstream>
#include <string>
#include <vector>
#include <random>
using namespace std;
typedef vector< vector<double> > Matrix;
// Particles making up the cell
class Particle{
public:
double x; // x position
double y; // y position
double vx; // velocity in the x direction
double vy; // velocity in the y direction
double Fx; // force in the x direction
double Fy; // force in the y direction
// Default constructor
Particle()
: x(0.0),y(0.0),vx(0.0),vy(0.0),Fx(0.0),Fy(0.0){
}
};
// Holder for storing data
class HoldPar{
public:
vector<double> x;
vector<double> y;
vector<double> vx;
vector<double> vy;
// Default constructor
HoldPar()
: x(0.0),y(0.0),vx(0.0),vy(0.0){
}
// Add elements to vectors
void add_Xelement(double a) {
x.push_back(a);
}
void add_Yelement(double a) {
y.push_back(a);
}
void add_VXelement(double a) {
vx.push_back(a);
}
void add_VYelement(double a) {
vy.push_back(a);
}
};
int main() {
// Initialization of x, v and F
const float pi = 3.14;
int N = 30; // Number of 'particles' that make up the cell
float theta = 2*pi/N; // Angle between two particles in radians
float x0 = 0; // Center of the cell [x]
float y0 = 0; // Center of the cell [y]
float R = 5e-6; // Radius of the cell
vector<Particle> particles(N); // particles
// Assigning the initial points onto the circle
for(int i = 0; i < N; i++) {
particles[i].x = x0 + R*cos(theta*i);
particles[i].y = y0 + R*sin(theta*i);
}
float k = 4.3e-7; // Spring constant connecting the particles
float m = 2e-8; // Mass of the particles
// Calculating the initial spring force between the particles on the cell
particles[0].Fx = -k*(particles[1].x - particles[N].x);
particles[0].Fy = -k*(particles[1].y - particles[N].y);
for(int i = 1; i < N-1; i++) {
particles[i].Fx = -k*(particles[i+1].x - particles[i-1].x);
particles[i].Fy = -k*(particles[i+1].y - particles[i-1].y);
}
particles[N].Fx = -k*(particles[0].x - particles[N-1].x);
particles[N].Fy = -k*(particles[0].y - particles[N-1].y);
// Initial velocities are given to each particle randomly from a Gaussian distribution
random_device rdx; // Seed
default_random_engine generatorx(rdx()); // Default random number generator
random_device rdy; // Seed
default_random_engine generatory(rdy()); // Default random number generator
normal_distribution<float> distributionx(0,1); // Gaussian distribution with 0 mean and 1 variance
normal_distribution<float> distributiony(0,1); // Gaussian distribution with 0 mean and 1 variance
for(int i = 0; i < N; i++) {
float xnumber = distributionx(generatorx);
float ynumber = distributiony(generatory);
particles[i].vx = xnumber;
particles[i].vy = ynumber;
}
// Molecular dynamics simulation with velocity Verlet algorithm
// 'Old' variables
vector<Particle> particles_old(N);
for(int i = 0; i < N; i++) {
particles_old[i].x = particles[i].x;
particles_old[i].y = particles[i].y;
particles_old[i].vx = particles[i].vx;
particles_old[i].vy = particles[i].vy;
particles_old[i].Fx = particles[i].Fx;
particles_old[i].Fy = particles[i].Fy;
}
// Sampling variables
int sampleFreq = 2;
int sampleCounter = 0;
// MD variables
float dt = 1e-4;
float dt2 = dt*dt;
float m2 = 2*m;
int MdS = 1e+5; // Molecular dynamics step number
// Holder variables
vector<HoldPar> particles_hold(N);
// MD
for(int j = 0; j < MdS; j++) {
// Update x
for(int i = 0; i < N; i++) {
particles[i].x = particles_old[i].x + dt*particles_old[i].vx + dt2*particles_old[i].Fx/m2;
particles[i].y = particles_old[i].y + dt*particles_old[i].vy + dt2*particles_old[i].Fy/m2;
}
// Update F
particles[0].Fx = -k*(particles[1].x - particles[N].x);
particles[0].Fy = -k*(particles[1].y - particles[N].y);
for(int i = 1; i < N-1; i++) {
particles[i].Fx = -k*(particles[i+1].x - particles[i-1].x);
particles[i].Fy = -k*(particles[i+1].y - particles[i-1].y);
}
particles[N].Fx = -k*(particles[0].x - particles[N-1].x);
particles[N].Fy = -k*(particles[0].y - particles[N-1].y);
// Update v
for(int i = 0; i < N; i++) {
particles[i].vx = particles_old[i].vx + dt*(particles_old[i].Fx + particles[i].Fx)/m2;
particles[i].vy = particles_old[i].vy + dt*(particles_old[i].Fy + particles[i].Fy)/m2;
}
// Copy new variables to old variables
for(int i = 0; i < N; i++) {
particles_old[i].x = particles[i].x;
particles_old[i].y = particles[i].y;
particles_old[i].vx = particles[i].vx;
particles_old[i].vy = particles[i].vy;
particles_old[i].Fx = particles[i].Fx;
particles_old[i].Fy = particles[i].Fy;
}
// Store variables
if(j % sampleFreq == 0) {
for(int i = 0; i < N; i++) {
particles_hold[i].add_Xelement( particles[i].x );
particles_hold[i].add_Yelement( particles[i].y );
particles_hold[i].add_VXelement( particles[i].vx );
particles_hold[i].add_VYelement( particles[i].vy );
}
sampleCounter += 1;
}
}
//* End of molecular dynamics simulation
}
//
//*
//
Essentially I'm trying to write a txt file where particles_hold elements (from 1 to N) are columns and members of particles_hold elements like x (from 1 to some value M) are rows.
If you mean visually then the way is put endl or "\n" to the outer loop and remove endl from inner loop.But i do not know anythig about your Holder object and if you have [] operator defined there that is the answer.
vector<Holder> obj(N);
void savedata(string filename, vector<Holder> obj, int M, int N) {
ofstream out(filename);
for(int i = 0; i < M; i++) {
for(int j = 0; j < N; j++) {
out << obj[i][j] << "\t";
}
out<< "\n";
}
}
Your method is ok, however, made some minor change so that you have M lines, each lines represent obj[i], i = 0.. M-1. So, each column (jth index) is printed as tab separated in each line
vector<Holder> obj(N);
void savedata(string filename, vector<Holder> obj, int M, int N) {
ofstream out(filename);
for(int i = 0; i < M; i++) {
for(int j = 0; j < N; j++) {
out << obj[i][j] << "\t";
}
out << endl;
}
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I have this data member in my class:cell** rep. I want to set size of the 2d in constructor. I receive no error while compiling; but no result comes when i run it.
//main.cpp
#include <ctime>
#include <cstdlib>
#include "cell.h"
#include "world.h"
using namespace std;
int main(){
srand(time(0));
World Conway(6,6);
Conway.generateWorld();
int numAlive = 1;
do{
numAlive = Conway.print();
Conway.nextGeneration();
cout<<"\n\t\t\t*****************\n\n";
cin.get();
}while(numAlive);
cin.get();
return 0;
}
//cell.h
#ifndef CELL_H
#define CELL_H
class Cell {
private :
bool alive;
public :
Cell() ;
void setAlive(bool b);
bool isAlive();
};
#endif
//cell.cpp
#include "cell.h" // class's header file
Cell::Cell(){
alive = false;
}
void Cell::setAlive(bool b){
alive = b;
}
bool Cell::isAlive(){
return alive;
}
//world.h
#ifndef WORLD_H
#define WORLD_H
#include "Cell.h"
class World {
private :
bool ring;
int lines, columns ;
Cell** rep; //I could not write this with pointer
public :
World (int l, int c) ;
World (int l, int c, bool ring);
~World() ;
int getLines();
int getColumns();
void generateWorld();
int nbAliveNeighbor( int i, int j) ;
int nbAliveNeighborRing( int i, int j);
void nextGeneration();
int print(); //the output of this function help me to end main loop
} ;
#endif
//world.cpp
#include "world.h" // class's header file
#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
World::World (int l, int c) {
lines = l;
columns = c;
ring = false;
Cell **rep = 0;
// memory allocated for elements of rows.
rep = new Cell *[l];
// memory allocated for elements of each column.
for( int i = 0 ; i < l ; i++ ) {
rep[i] = new Cell[c];
}
}
World::World(int l,int c,bool r){
lines = l;
columns = c;
ring = r;
}
int World::getLines(){
return lines;
}
int World::getColumns(){
return columns;
}
int World::nbAliveNeighborRing( int i, int j){
int n = 0; //number of alives
for(int r = i-1; r < i+2; r++){
for(int c = j-1; c < j+2; c++){
//giving ring flexibility
if(c < 0)
c + columns;
if(c >= columns)
c - columns;
if(r < 0)
r + lines;
if(r >= lines)
r - lines;
if(c==j && r ==i)
continue; //ignoring the cell itself
if(rep[r][c].isAlive())
n++;
}
}
return n;
}
int World::nbAliveNeighbor( int i, int j) {
int n = 0; //number of alives
for(int r = i-1; r < i+2; r++){
for(int c = j-1; c < j+2; c++){
//ignoring if it's out of range
if(c < 0 || c >= columns)
continue;
if(r < 0 || r >= lines)
continue;
//ignoring the cell itself
if(c==j && r ==i)
continue;
if(rep[r][c].isAlive())
n++;
}
}
return n;
}
int random(int a,int b){
return a+rand()%(b-a+1); //including a & b
}
void World::generateWorld(){
int nAlive = (lines * columns)/ 4 + 1;
//why plus 1:
// because in random some are the same so we plus it with 1 so in the average
// the alive cells will be third of deads!
int randAry[nAlive];
for(int i=0, clm=0, row=0; i < nAlive; i++){
randAry[i] = random(0,lines*columns);
clm = 0;
row = 0;
while(randAry[i] >= lines){
row ++;
randAry[i] -= lines;
}
clm = randAry[i];
rep[row][clm].setAlive(true);
}
}
void World::nextGeneration(){
if(ring){
for(int i = 0; i < lines; i++){
for(int j = 0; j < columns; j++){
if(rep[i][j].isAlive()){
if(nbAliveNeighborRing(i,j) == 3 || nbAliveNeighborRing(i,j) == 2)
continue;
else
rep[i][j].setAlive(false);
}
else{
if(nbAliveNeighborRing(i,j) == 3)
rep[i][j].setAlive(true);
}
}
}
}
else{
for(int i = 0; i < lines; i++){
for(int j = 0; j < columns; j++){
if(rep[i][j].isAlive()){
if(nbAliveNeighbor(i,j) == 3 || nbAliveNeighbor(i,j) == 2){
continue;
}
else{
rep[i][j].setAlive(false);
}
}
else{
if(nbAliveNeighbor(i,j) == 3){
rep[i][j].setAlive(true);
}
}
}
}
}
}
int World::print(){
int n = 0;
for(int i = 0; i < lines; i++){
for(int j = 0; j < columns; j++){
if(rep[i][j].isAlive()){
cout<<" * ";
n++;
}
else
cout<<" - ";
}
cout<<endl;
}
return n;
}
World::~World(){
delete rep;
}
Your Cell** rep is never created. This should be done in the constructor. Now you're making int **rep = 0;, which doesn't seem to be used anywhere.
//int **rep = 0; //scratch this
rep = new Cell *[l];
// memory allocated for elements of each column.
for( int i = 0 ; i < l ; i++ ) {
rep[i] = new Cell[c];
}
Maybe that Cell.h is capitalized in include of world.h
In class World data member rep is defined as
class World {
private :
bool ring;
int lines, columns ;
Cell** rep; //I could not write this with pointer
...
However in the constructor you use a local variable rep that have type int ** and try to initialize that local variable that will be destroyed after exiting the constructor.
World::World (int l, int c) {
lines = l;
columns = c;
ring = false;
int **rep = 0;
// memory allocated for elements of rows.
rep = new int *[l];
// memory allocated for elements of each column.
for( int i = 0 ; i < l ; i++ ) {
rep[i] = new int[c];
}