Esempio n. 1
0
void BOCTX::Sweep(SEGM2 * aSegms, UINT32 nSegms)
{
	CollectEvents(aSegms, nSegms);

	while (not m_E.empty())
	{
		// store the current state of main active list
		SAVE_LIST save_list;
		save_list.reserve(32);
		
		for (SEGM_LIST::iterator segm = m_S.begin(); segm != m_S.end(); ++segm)
			save_list.push_back(&*segm);

		// do Pass 1
		EVENT e = m_E.top();
		m_E.pop();
		EVENTLIST elist;
		elist.reserve(8);

		assert(INT20_MIN <= e.x and e.x <= INT20_MAX);

			AddEvent(&elist, e);
			HandleEvent(e);

		while (not m_E.empty() and m_E.top().x == e.x)
		{
			e = m_E.top();
			m_E.pop();
			AddEvent(&elist, e);
			HandleEvent(e);
		}

		// do Pass 2
		Pass2(&elist, &save_list);
	}
} // Sweep
Esempio n. 2
0
int main()
{
	unsigned int i, im, iw;

	const double pressure = 2.0;		// pressure
	const double beta = 0.5;			// inverse temperature

	const double mass[2] = { 1, 3 };	// alternating masses

	const unsigned int nsweeps = 13;	// number of 'sweeps' of the event table

	// enable run-time memory check for debug builds
	#if defined(_WIN32) & (defined(DEBUG) | defined(_DEBUG))
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	#endif

	printf("pressure: %g\n", pressure);
	printf("beta:     %g\n", beta);

	printf("alternating masses: (%g, %g)\n", mass[0], mass[1]);

	printf("N: %d\n", NUM_SITES);
	assert(NUM_SITES == 16);

	// artificial UNIX time
	unsigned int itime = 1420000241;

	// random generator seed; multiplicative constant from Pierre L'Ecuyer's paper
	randseed_t seed;
	Random_SeedInit(1865811235122147685LL * (uint64_t)itime, &seed);

	// lattice field
	field_t f;
	Field_Create(mass, &f);
	// initialize elongations and momenta using single-site probability density, Eq. (2.11)
	EquilibrateCanonical(pressure, beta, &seed, &f);

	// initial mean values
	double r_mean0 = 0;		// mean of r's (elongations), remains constant in time
	double p_mean0 = 0;		// mean momentum
	double e_mean0 = 0;		// mean energy
	for (im = 0; im < 2; im++)
	{
		for (i = im; i < NUM_SITES; i += 2)
		{
			const lattpoint_t *point = &f.pts[i];
			r_mean0 += point->r;							// elongation
			p_mean0 += mass[im] * point->v;					// momentum
			e_mean0 += LattPoint_Energy(mass[im], point);	// energy
		}
	}
	r_mean0 /= NUM_SITES;
	p_mean0 /= NUM_SITES;
	e_mean0 /= NUM_SITES;
	//e_mean0 -= 0.5 * square(p_mean0);	// internal energy per particle

	// stochastic expectation values
	double r_avr = AverageElongation(pressure, beta);
	double p_avr = 0;
	double e_avr = AverageEnergy(beta);

	// compare mean values with stochastic expectation values
	printf("elongation mean: %g, stochastic average: %g\n", r_mean0, r_avr);
	printf("momentum   mean: %g, stochastic average: %g\n", p_mean0, p_avr);
	printf("energy     mean: %g, stochastic average: %g\n", e_mean0, e_avr);

	// save elongations and momenta to disk
	{
		double r[NUM_SITES];
		double p[NUM_SITES];

		for (im = 0; im < 2; im++)
		{
			for (i = im; i < NUM_SITES; i += 2)
			{
				r[i] = f.pts[i].r;
				p[i] = mass[im] * f.pts[i].v;
			}
		}

		WriteData("../test/collision_test_field_r0.dat", r, sizeof(double), NUM_SITES, false);
		WriteData("../test/collision_test_field_p0.dat", p, sizeof(double), NUM_SITES, false);
	}

	// event table
	event_table_t tab;
	assert(NUM_SLOTS == 4);
	EventTable_Allocate(0.1, &tab);	// dt, table
	printf("event table number of slots: %i, slot interval dt: %g, events per slot: %i\n", NUM_SLOTS, tab.dt, EVENTS_PER_SLOT);
	// time period
	const double period = NUM_SLOTS * tab.dt;
	printf("event table time period: %g\n", period);

	// initial kinetic and potential energy
	double en0 = Field_Energy(&f);
	printf("initial energy: %g\n", en0);

	// collect collision events
	CollectEvents(&f, &tab);

	for (iw = 0; iw < nsweeps; iw++)	// several sweeps
	{
		// process events
		SweepTable(&f, &tab);

		// synchronize up to period of event table
		Field_Synchronize(period, &f);

		// subtract 'period' from all timing events
		GlobalTimeshift(period, &f, &tab);
		// correspondingly add 'period' to time offset of event log
		#ifdef _DEBUG
		event_log.time_offset += period;
		#endif
	}

	printf("finished simulation, simulation time: %g\n", nsweeps * period);

	// final mean values (should be conserved)
	double r_mean1 = 0;		// mean of r's (elongations), remains constant in time
	double p_mean1 = 0;		// mean momentum
	double e_mean1 = 0;		// mean energy
	for (im = 0; im < 2; im++)
	{
		for (i = im; i < NUM_SITES; i += 2)
		{
			const lattpoint_t *point = &f.pts[i];
			r_mean1 += point->r;							// elongation
			p_mean1 += mass[im] * point->v;					// momentum
			e_mean1 += LattPoint_Energy(mass[im], point);	// energy
		}
	}
	r_mean1 /= NUM_SITES;
	p_mean1 /= NUM_SITES;
	e_mean1 /= NUM_SITES;
	//e_mean1 -= 0.5 * square(p_mean1);	// internal energy per particle

	// compare initial and final mean values (should be conserved)
	printf("final elongation mean: %g, difference to initial value: %g (should be zero)\n", r_mean1, fabs(r_mean0 - r_mean1));
	printf("final momentum   mean: %g, difference to initial value: %g (should be zero)\n", p_mean1, fabs(p_mean0 - p_mean1));
	printf("final energy     mean: %g, difference to initial value: %g (should be zero)\n", e_mean1, fabs(e_mean0 - e_mean1));

	// final energy
	double en1 = Field_Energy(&f);
	printf("final energy: %g\n", en1);
	printf("energy difference: %g (should be zero)\n", en1 - en0);

	#ifdef _DEBUG

	// report events
	i = 0;
	event_node_t *node = event_log.first;
	double *evtime = malloc(event_log.num * sizeof(double));
	int    *eviprt = malloc(event_log.num * sizeof(int));
	int    *evtype = malloc(event_log.num * sizeof(int));
	while (node != NULL)
	{
		printf("next event: time: %g, iprt: %i, type: %s\n", node->ev.time, node->ev.iprt, COLL_STR[node->ev.type]);
		evtime[i] = node->ev.time;
		eviprt[i] = node->ev.iprt;
		evtype[i] = node->ev.type;
		node = node->next;
		i++;
	}
	assert(i == event_log.num);

	// save event data to disk
	WriteData("../test/collision_test_event_time.dat", evtime, sizeof(double), event_log.num, false);
	WriteData("../test/collision_test_event_iprt.dat", eviprt, sizeof(int),    event_log.num, false);
	WriteData("../test/collision_test_event_type.dat", evtype, sizeof(int),    event_log.num, false);

	// read reference data from disk
	double *evtime_ref = malloc(event_log.num * sizeof(double));
	int    *eviprt_ref = malloc(event_log.num * sizeof(int));
	int    *evtype_ref = malloc(event_log.num * sizeof(int));
	ReadData("../test/collision_test_ref_event_time.dat", evtime_ref, sizeof(double), event_log.num);
	ReadData("../test/collision_test_ref_event_iprt.dat", eviprt_ref, sizeof(int),    event_log.num);
	ReadData("../test/collision_test_ref_event_type.dat", evtype_ref, sizeof(int),    event_log.num);

	// calculate average error
	printf("comparing with reference collision data...\n");
	double err = 0;
	for (i = 0; i < event_log.num; i++)
	{
		err += fabs(evtime[i] - evtime_ref[i]);
		err +=  abs(eviprt[i] - eviprt_ref[i]);
		err +=  abs(evtype[i] - evtype_ref[i]);
	}
	err /= event_log.num;
	printf("average error: %g\n", err);

	// clean up
	free(evtype);
	free(eviprt);
	free(evtime);
	free(evtype_ref);
	free(eviprt_ref);
	free(evtime_ref);
	EventLog_Delete(&event_log);
	#endif	// _DEBUG

	// clean up
	EventTable_Delete(&tab);

	return 0;
}
Esempio n. 3
0
int main()
{
	unsigned int i, j;

	const double pressure = 1.2;			// pressure
	const double beta = 2.0;				// inverse temperature

	const unsigned int nsweeps = /*500*/250;	// number of 'sweeps' of the event table

	// enable run-time memory check for debug builds
	#if defined(_WIN32) & (defined(DEBUG) | defined(_DEBUG))
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	#endif

	printf("pressure: %g\n", pressure);
	printf("beta:     %g\n", beta);

	printf("N: %d\n", NUM_SITES);
	assert(NUM_SITES == 256);

	// lattice field
	field_t f;
	Field_Create(&f);
	{
		// artificial UNIX time
		unsigned int itime = 1420000241;

		// random generator seed; multiplicative constant from Pierre L'Ecuyer's paper
		randseed_t seed;
		Random_SeedInit(1865811235122147685LL * (uint64_t)itime, &seed);

		ensemble_params_t params;
		EnsembleParams_Fill(pressure, beta, &params);

		// initialize elongations and momenta using single-site probability density, Eq. (2.11)
		EquilibrateCanonical(&params, &seed, &f);

		// current mean values
		double r_mean = 0;		// mean of r's (elongations), remains constant in time
		double p_mean = 0;		// mean momentum
		double e_mean = 0;		// mean energy
		for (i = 0; i < NUM_SITES; i++)
		{
			const lattpoint_t *point = &f.pts[i];
			r_mean += point->r;
			p_mean += point->p;
			e_mean += LattPoint_Energy(point);
		}
		r_mean /= NUM_SITES;
		p_mean /= NUM_SITES;
		e_mean /= NUM_SITES;
		//e_mean -= 0.5 * square(p_mean);	// internal energy per particle

		// compare with stochastic expectation values
		double r_avr = AverageElongation(pressure, beta);
		double p_avr = 0;
		double e_avr = AverageEnergy(pressure, beta);

		printf("elongation mean: %g, stochastic average: %g\n", r_mean, r_avr);
		printf("momentum   mean: %g, stochastic average: %g\n", p_mean, p_avr);
		printf("energy     mean: %g, stochastic average: %g\n", e_mean, e_avr);
	}

	// event table
	event_table_t tab;
	assert(NUM_SLOTS == 128/*64*/);
	EventTable_Allocate(0.01, &tab);	// dt, table
	printf("event table number of slots: %d, slot interval dt: %g\n", NUM_SLOTS, tab.dt);
	// time period
	const double period = NUM_SLOTS * tab.dt;
	printf("event table time period: %g\n", period);

	// spatial correlation structure
	spatial_correlation_t scorr;
	SpatialCorrelation_Allocate(&scorr);
	// lattice point data
	pointdata_t data_ref[NUM_SITES];
	pointdata_t data_cur[NUM_SITES];
	// actual covariance matrix
	cov_mat_t *cov = malloc(NUM_SITES * sizeof(cov_mat_t));

	// initial kinetic and potential energy
	double en0 = Field_Energy(&f);
	printf("initial energy: %g\n", en0);

	// start timer
	clock_t t_start = clock();

	// collect initial collision events
	CollectEvents(&f, &tab);

	for (i = 0; i < nsweeps; i++)	// repeat several sweeps
	{
		// store elongation and momentum, and calculate energies of field variables
		for (j = 0; j < NUM_SITES; j++)
		{
			const lattpoint_t *point = &f.pts[j];
			assert(point->t == 0);
			data_ref[j].r = point->r;					// elongation
			data_ref[j].p = point->p;					// momentum
			data_ref[j].e = LattPoint_Energy(point);	// energy
		}

		// process events
		SweepTable(&f, &tab);

		// synchronize up to period of event table
		Field_Synchronize(period, &f);

		// store elongation and momentum, and calculate energies of field variables
		for (j = 0; j < NUM_SITES; j++)
		{
			const lattpoint_t *point = &f.pts[j];
			assert(point->t == period);
			data_cur[j].r = point->r;					// elongation
			data_cur[j].p = point->p;					// momentum
			data_cur[j].e = LattPoint_Energy(point);	// energy
		}

		// collect and accumulate spatial correlations (for time offset 'period')
		SpatialCorrelation_Collect(data_ref, data_cur, &scorr);

		// subtract 'period' from all timing events
		GlobalTimeshift(period, &f, &tab);
		// correspondingly add 'period' to time offset of event log
		#ifdef _DEBUG
		event_log.time_offset += period;
		#endif
	}

	clock_t t_end = clock();
	printf("finished simulation, simulation time: %g, CPU time: %g\n", nsweeps * period, (double)(t_end - t_start) / CLOCKS_PER_SEC);

	// divide by 'nsweeps'
	SpatialCorrelation_ScalarMultiply(1.0/nsweeps, &scorr);
	// calculate covariance matrix
	CalculateCovariance(&scorr, cov);
	// save to disk
	printf("saving covariance matrix to disk...\n");
	WriteData("../test/simulation_test_cov.dat", cov, sizeof(cov_mat_t), NUM_SITES, false);

	// final kinetic and potential energy
	double en1 = Field_Energy(&f);
	printf("final energy: %g\n", en1);
	printf("energy difference: %g (should be zero)\n", en1 - en0);

	#ifdef _DEBUG
	printf("total number of events: %i\n", event_log.num);
	// save event data to disk
	i = 0;
	event_node_t *node = event_log.first;
	double *evtime = malloc(event_log.num * sizeof(double));
	int    *eviprt = malloc(event_log.num * sizeof(int));
	int    *evtype = malloc(event_log.num * sizeof(int));
	while (node != NULL)
	{
		evtime[i] = node->ev.time;
		eviprt[i] = node->ev.iprt;
		evtype[i] = (int)node->ev.type;
		node = node->next;
		i++;
	}
	assert(i == event_log.num);
	// save event data to disk
	WriteData("../test/simulation_test_event_time.dat", evtime, sizeof(double), event_log.num, false);
	WriteData("../test/simulation_test_event_iprt.dat", eviprt, sizeof(int),    event_log.num, false);
	WriteData("../test/simulation_test_event_type.dat", evtype, sizeof(int),    event_log.num, false);
	// clean up
	free(evtype);
	free(eviprt);
	free(evtime);
	EventLog_Delete(&event_log);
	#endif

	// clean up
	free(cov);
	SpatialCorrelation_Delete(&scorr);
	EventTable_Delete(&tab);
	fftw_cleanup();

	return 0;
}
Esempio n. 4
0
int main(int argc, const char* argv[])
{
	unsigned int ic, is, ip, ir, it;

	const double pressure = 1.2;		// pressure
	const double beta = 2.0;			// inverse temperature

	#define NUM_SPATIAL_CORR 3			// number of time points at which spatial correlations are collected

	// cumulative number of 'sweeps' of the event table
	const unsigned int nsweeps[NUM_SPATIAL_CORR] = { 256, 512, 1024 };

	printf("pressure: %g\n", pressure);
	printf("beta:     %g\n", beta);

	printf("N: %i\n", NUM_SITES);

	printf("number of sweeps of the event table: %i\n", nsweeps[NUM_SPATIAL_CORR-1]);

	// check number of input arguments
	if (argc != 3) {
		fprintf(stderr, "syntax: %s <number of cycles> <number of samples per cycle>\n", argv[0]);
		return -1;
	}

	// number of cycles
	unsigned int ncycles = atoi(argv[1]);
	printf("number of cycles: %i\n", ncycles);

	// number of samples per cycle
	unsigned int nsamples = atoi(argv[2]);
	printf("number of samples per cycle: %i\n", nsamples);

	// enable run-time memory check for debug builds
	#if defined(_WIN32) & (defined(DEBUG) | defined(_DEBUG))
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	#endif

	// UNIX time
	unsigned int itime = (unsigned int)time(NULL);
	printf("itime: %i\n", itime);

	// trying to create output directory corresponding to 'itime'
	char path[1024];
	sprintf(path, "../output/fields/sim_%i", itime);
	while (makedir(path) < 0)
	{
		printf("cannot create output directory '%s', changing 'itime'...\n", path);
		#ifdef _WIN32
		Sleep(15000);
		#else
		sleep(15);
		#endif
		itime += (clock() % 16) + 15;
		sprintf(path, "../output/fields/sim_%i", itime);
	}
	printf("created output directory '%s'...\n", path);

	// random generator seed; multiplicative constant from Pierre L'Ecuyer's paper
	randseed_t seed;
	Random_SeedInit(1865811235122147685LL * (uint64_t)itime, &seed);

	// canonical ensemble parameters
	ensemble_params_t params;
	EnsembleParams_Fill(pressure, beta, &params);

	// lattice field
	field_t f;
	Field_Create(&f);

	// event table
	event_table_t tab;
	EventTable_Allocate(1.0/NUM_SLOTS, &tab);	// dt, table
	printf("event table number of slots: %i, slot interval dt: %g, events per slot: %i\n", NUM_SLOTS, tab.dt, EVENTS_PER_SLOT);
	// time period
	const double period = NUM_SLOTS * tab.dt;
	printf("event table time period: %g\n", period);

	printf("maximum simulation time: %g\n", nsweeps[NUM_SPATIAL_CORR-1] * period);

	// create subdirectories for saving files
	for (ir = 0; ir < NUM_SPATIAL_CORR; ir++)
	{
		sprintf(path, "../output/fields/sim_%i/t%i", itime, (int)(nsweeps[ir]*period));
		if (makedir(path) < 0) {
			fprintf(stderr, "'mkdir(%s)' failed.\n", path);
			return -1;
		}
	}

	// spatial correlation structure
	spatial_correlation_t scorr[NUM_SPATIAL_CORR];
	for (ir = 0; ir < NUM_SPATIAL_CORR; ir++) {
		SpatialCorrelation_Allocate(&scorr[ir]);
	}
	// lattice point data
	pointdata_t data_ref[NUM_SITES];
	pointdata_t data_cur[NUM_SITES];

	// start timer
	clock_t t_start = clock();

	for (ic = 0; ic < ncycles; ic++)
	{
		printf("cycle %i\n", ic + 1);

		for (is = 0; is < nsamples; is++)
		{
			// initialize elongations and momenta using single-site probability density, Eq. (2.11)
			EquilibrateCanonical(&params, &seed, &f);

			// initial energy
			double en0 = Field_Energy(&f);
			//printf("initial energy: %g\n", en0);

			// initial field: store elongation and momentum, and calculate energies of field variables
			for (ip = 0; ip < NUM_SITES; ip++)
			{
				const lattpoint_t *point = &f.pts[ip];
				assert(point->t == 0);
				data_ref[ip].r = point->r;					// elongation
				data_ref[ip].p = point->p;					// momentum
				data_ref[ip].e = LattPoint_Energy(point);	// energy
			}

			// collect initial collision events
			CollectEvents(&f, &tab);

			// run actual simulation
			for (ir = 0; ir < NUM_SPATIAL_CORR; ir++)
			{
				for (it = (ir == 0 ? 0 : nsweeps[ir-1]); it < nsweeps[ir]; it++)	// repeat several sweeps
				{
					// process events
					SweepTable(&f, &tab);

					// synchronize up to period of event table
					//Field_Synchronize(period, &f);

					// subtract 'period' from all timing events
					GlobalTimeshift(period, &f, &tab);
					// correspondingly add 'period' to time offset of event log
					#ifdef _DEBUG
					event_log.time_offset += period;
					#endif
				}

				// 'period' has already been subtracted
				Field_Synchronize(0, &f);

				// current field: store elongation and momentum, and calculate energies of field variables
				for (ip = 0; ip < NUM_SITES; ip++)
				{
					const lattpoint_t *point = &f.pts[ip];
					assert(point->t == 0);
					data_cur[ip].r = point->r;					// elongation
					data_cur[ip].p = point->p;					// momentum
					data_cur[ip].e = LattPoint_Energy(point);	// energy
				}

				// collect and accumulate spatial correlations (for time offset 'nsweeps[ir] * period')
				SpatialCorrelation_Collect(data_ref, data_cur, &scorr[ir]);

			}	// time point loop

			// final energy
			double en1 = Field_Energy(&f);
			//printf("final energy: %g\n", en1);
			//printf("energy difference: %g (should be zero)\n", en1 - en0);
			if (fabs(en1 - en0) > 1e-10) {
				fprintf(stderr, "warning: energy seems not to be conserved, difference: %g\n", fabs(en1 - en0));
			}

			// reset event table
			EventTable_Reset(&tab);

			#ifdef _DEBUG
			// reset event log
			EventLog_Delete(&event_log);
			#endif

		}	// sample loop

		for (ir = 0; ir < NUM_SPATIAL_CORR; ir++)
		{
			// divide by 'nsamples'
			SpatialCorrelation_ScalarMultiply(1.0 / nsamples, &scorr[ir]);

			// save to disk
			const int timepoint = (int)(nsweeps[ir]*period);
			printf("saving averages required for correlators at time %i to disk...\n", timepoint);
			sprintf(path, "../output/fields/sim_%i/t%i/sim_%i_t%i_ns%i_avr0_%04d.dat", itime, timepoint, itime, timepoint, nsamples, ic); WriteData(path, &scorr[ir].avr[0], sizeof(pointdata_t), 1, false);
			sprintf(path, "../output/fields/sim_%i/t%i/sim_%i_t%i_ns%i_avr1_%04d.dat", itime, timepoint, itime, timepoint, nsamples, ic); WriteData(path, &scorr[ir].avr[1], sizeof(pointdata_t), 1, false);
			sprintf(path, "../output/fields/sim_%i/t%i/sim_%i_t%i_ns%i_sqrs_%04d.dat", itime, timepoint, itime, timepoint, nsamples, ic); WriteData(path, scorr[ir].sqr, sizeof(cov_mat_t), NUM_SITES, false);

			// reset spatial correlation structure
			SpatialCorrelation_Reset(&scorr[ir]);
		}

	}	// cycle loop

	clock_t t_end = clock();
	double cpu_time = (double)(t_end - t_start) / CLOCKS_PER_SEC;
	printf("finished simulation, CPU time: %g, average CPU time per run: %g\n", cpu_time, cpu_time / (ncycles * nsamples));

	// clean up
	for (ir = 0; ir < NUM_SPATIAL_CORR; ir++) {
		SpatialCorrelation_Delete(&scorr[ir]);
	}
	EventTable_Delete(&tab);
	fftw_cleanup();

	return 0;
}
int main(int argc, const char* argv[])
{
	unsigned int ic, is, im, ip, it;

	const double pressure = 2.0;		// pressure
	const double beta = 0.5;			// inverse temperature

	const double mass[2] = { 1, 3 };	// alternating masses

	const double c_sound = 1.73205080756887729;		// speed of sound for these concrete pressure, beta and mass values: sqrt(3)

	const double ell_avr = AverageElongation(pressure, beta);
	const double  en_avr = AverageEnergy(beta);

	const double matR_0r = 0.8164965809277260327;	// the (0,r) entry of the R matrix (normal mode 0 and physical coordinate elongation 'r'): sqrt(2/3)
	const double matR_s6 = 0.408248290463863016;	// the (sigma,r), (0,e) and (sigma,e) entries of the R matrix (physical elongation 'r' or energy coordinate 'e'): 1/sqrt(6)
	const double matR_1p = 0.353553390593273762;	// the (1,p) entry of the R matrix (normal mode 1 and physical momentum coordinate 'p'): 1/(2*sqrt(2))

	// number of 'sweeps' of the event table, i.e., current is integrated up to t = nsweeps*period where 'period' is the event table time period
	const unsigned int nsweeps = 1024;

	// inverse bin width for time-integrated current
	const double inv_bin_width_J = 2;
	// number of bins for time-integrated current
	#define NUM_JINT_BINS 2048
	#define MASK_JINT_BIN (NUM_JINT_BINS - 1)

	printf("pressure: %g\n", pressure);
	printf("beta:     %g\n", beta);

	printf("average elongation: %g\n", ell_avr);
	printf("average energy:     %g\n",  en_avr);

	printf("N: %i\n", NUM_SITES);

	printf("maximum time in units of event table time period: %i\n", nsweeps);

	printf("bin width for time-integrated current: %g, number of bins: %i\n", 1/inv_bin_width_J, NUM_JINT_BINS);

	// check number of input arguments
	if (argc != 3) {
		fprintf(stderr, "syntax: %s <number of cycles> <number of samples per cycle>\n", argv[0]);
		return -1;
	}

	// number of cycles
	unsigned int ncycles = atoi(argv[1]);
	printf("number of cycles: %i\n", ncycles);

	// number of samples per cycle
	unsigned int nsamples = atoi(argv[2]);
	printf("number of samples per cycle: %i\n", nsamples);

	// enable run-time memory check for debug builds
	#if defined(_WIN32) & (defined(DEBUG) | defined(_DEBUG))
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	#endif

	// UNIX time
	unsigned int itime = (unsigned int)time(NULL);
	printf("itime: %i\n", itime);

	// trying to create output directory corresponding to 'itime'
	char path[1024];
	sprintf(path, "../output/current_Jsite/sim_%i", itime);
	while (makedir(path) < 0)
	{
		printf("cannot create output directory '%s', changing 'itime'...\n", path);
		#ifdef _WIN32
		Sleep(15000);
		#else
		sleep(15);
		#endif
		itime += (clock() % 16) + 15;
		sprintf(path, "../output/current_Jsite/sim_%i", itime);
	}
	printf("created output directory '%s'...\n", path);

	// random generator seed; multiplicative constant from Pierre L'Ecuyer's paper
	randseed_t seed;
	Random_SeedInit(1865811235122147685LL * (uint64_t)itime, &seed);

	// lattice field
	field_t f;
	Field_Create(mass, &f);

	// event table
	event_table_t tab;
	EventTable_Allocate(1.0/NUM_SLOTS, &tab);	// dt, table
	printf("event table number of slots: %i, slot interval dt: %g, events per slot: %i\n", NUM_SLOTS, tab.dt, EVENTS_PER_SLOT);
	// time period
	const double period = NUM_SLOTS * tab.dt;
	printf("event table time period: %g\n", period);

	const double t_max = nsweeps * period;
	printf("maximum simulation time: %g\n", t_max);

	// c_sound * t
	const double ct = c_sound * t_max;
	// rounded version
	const unsigned int cti = (unsigned int)round(ct);

	// spatial correlation structure
	spatial_correlation_t scorr;
	SpatialCorrelation_Allocate(&scorr);

	current_t *J_int = fftw_malloc(NUM_SITES * sizeof(current_t));
	currnrm_t *J_inr = fftw_malloc(NUM_SITES * sizeof(currnrm_t));
	current_t *F_int = fftw_malloc(NUM_SITES * sizeof(current_t));

	// start timer
	clock_t t_start = clock();

	for (ic = 0; ic < ncycles; ic++)
	{
		printf("cycle %i\n", ic + 1);

		// sort time-integrated current values transformed to normal modes into bins
		unsigned long long J_int_counts[3][NUM_JINT_BINS] = { 0 };

		for (is = 0; is < nsamples; is++)
		{
			// total time-integrated currents in physical coordinates for each lattice site
			memset(J_int, 0, NUM_SITES * sizeof(current_t));

			// initialize elongations and momenta using single-site probability density, Eq. (2.11)
			EquilibrateCanonical(pressure, beta, &seed, &f);

			// initial energy
			double en0 = Field_Energy(&f);
			//printf("initial energy: %g\n", en0);

			// spatial integrals over field variables with length c*t
			memset(F_int, 0, NUM_SITES * sizeof(current_t));
			for (ip = 0; ip < cti; ip++)
			{
				F_int[0].r +=                                   f.pts[(0 - ip) & SITE_MASK].r - ell_avr;
				F_int[0].p +=                  f.mass[ip & 1] * f.pts[(0 - ip) & SITE_MASK].v;
				F_int[0].e += LattPoint_Energy(f.mass[ip & 1], &f.pts[(0 - ip) & SITE_MASK])  -  en_avr;
			}
			for (ip = 1; ip < NUM_SITES; ip++)
			{
				F_int[ip].r = F_int[ip - 1].r +                                   f.pts[ip].r -                                           f.pts[(ip - cti) & SITE_MASK].r;
				F_int[ip].p = F_int[ip - 1].p +                  f.mass[ip & 1] * f.pts[ip].v -                  f.mass[(ip - cti) & 1] * f.pts[(ip - cti) & SITE_MASK].v;
				F_int[ip].e = F_int[ip - 1].e + LattPoint_Energy(f.mass[ip & 1], &f.pts[ip])  - LattPoint_Energy(f.mass[(ip - cti) & 1], &f.pts[(ip - cti) & SITE_MASK]);
			}

			// collect initial collision events
			CollectEvents(&f, &tab);

			// run actual simulation
			for (it = 0; it < nsweeps; it++)
			{
				// process events and record current
				current_t J[NUM_SITES];
				SweepTableJSite(&f, &tab, J);

				// integrate currents over time; subtract theoretical average value
				for (ip = 0; ip < NUM_SITES; ip++)
				{
					J_int[ip].r += J[ip].r;
					J_int[ip].p += J[ip].p - period*pressure;
					J_int[ip].e += J[ip].e;
				}

				// subtract 'period' from all timing events
				GlobalTimeshift(period, &f, &tab);
				// correspondingly add 'period' to time offset of event log
				#ifdef _DEBUG
				event_log.time_offset += period;
				#endif

			}	// time point loop

			// complete velocity integration for elongation current; 'period' has already been subtracted
			for (ip = 0; ip < NUM_SITES; ip++)
			{
				lattpoint_t *point = &f.pts[ip];
				J_int[ip].r -= (0 - point->t) * point->v;
			}

			// not required here
			// Field_Synchronize(0, &f);

			// transform integrated current values to normal modes
			for (ip = 0; ip < NUM_SITES; ip++)
			{
				// transform to normal modes -1, 0, 1
				J_inr[ip].m[0] = -matR_s6 * J_int[ip].r - matR_1p * J_int[ip].p + matR_s6 * J_int[ip].e;		// mode -1
				J_inr[ip].m[1] =  matR_0r * J_int[ip].r                         + matR_s6 * J_int[ip].e;		// mode  0
				J_inr[ip].m[2] = -matR_s6 * J_int[ip].r + matR_1p * J_int[ip].p + matR_s6 * J_int[ip].e;		// mode  1
			}

			// collect and accumulate spatial time-integrated current auto-correlations
			SpatialCorrelation_Collect((pointdata_t *)J_inr, (pointdata_t *)J_inr, &scorr);

			// subtract spatial integrals over field variables at t = 0 from sound modes and sort into bins
			for (ip = 0; ip < NUM_SITES; ip++)
			{
				// correspondingly transform integrals over field variables
				unsigned int iq = (ip + cti) & SITE_MASK;	// integrate "backwards"
				double Fm1 = -matR_s6 * F_int[iq].r - matR_1p * F_int[iq].p + matR_s6 * F_int[iq].e;
				double F_1 = -matR_s6 * F_int[ip].r + matR_1p * F_int[ip].p + matR_s6 * F_int[ip].e;

				// subtract spatial integrals over field variables at t = 0 from sound modes
				J_inr[ip].m[0] += Fm1;		// mode -1
				J_inr[ip].m[2] -= F_1;		// mode  1

				for (im = 0; im < 3; im++)	// for each mode...
				{
					// bit masking modulo operation works for negative integers also
					int ib = (int)floor(J_inr[ip].m[im] * inv_bin_width_J);
					if (-NUM_JINT_BINS/2 <= ib && ib < NUM_JINT_BINS/2)
					{
						J_int_counts[im][ib & MASK_JINT_BIN]++;
					}
				}
			}

			// final energy
			double en1 = Field_Energy(&f);
			//printf("final energy: %g\n", en1);
			//printf("energy difference: %g (should be zero)\n", en1 - en0);
			if (fabs(en1 - en0) > 1e-10) {
				fprintf(stderr, "warning: energy seems not to be conserved, difference: %g\n", fabs(en1 - en0));
			}

			// reset event table
			EventTable_Reset(&tab);

			#ifdef _DEBUG
			printf("total number of events: %i\n", event_log.num);
			printf("average time difference between events: %g\n", nsweeps * period / event_log.num);
			// reset event log
			EventLog_Delete(&event_log);
			#endif

		}	// sample loop

		// divide by 'nsamples'
		SpatialCorrelation_ScalarMultiply(1.0 / nsamples, &scorr);

		// save to disk
		printf("saving histograms and spatial correlations of time-integrated currents to disk...\n");
		for (im = 0; im < 3; im++)	// for each mode...
		{
			const char *mode_names[3] = { "N", "0", "1" };
			sprintf(path, "../output/current_Jsite/sim_%i/sim_%i_ns%i_J_int_mode%s_hist_%04d.dat", itime, itime, nsamples, mode_names[im], ic);
			WriteData(path, J_int_counts[im], sizeof(unsigned long long), NUM_JINT_BINS, false);
		}
		// scorr.avr[1] same as scorr.avr[0]
		sprintf(path, "../output/current_Jsite/sim_%i/sim_%i_ns%i_J_int_corr_avr_%04d.dat", itime, itime, nsamples, ic); WriteData(path, &scorr.avr[0], sizeof(pointdata_t), 1, false);
		sprintf(path, "../output/current_Jsite/sim_%i/sim_%i_ns%i_J_int_corr_sqr_%04d.dat", itime, itime, nsamples, ic); WriteData(path, scorr.sqr, sizeof(cov_mat_t), NUM_SITES, false);

		// reset spatial correlation structure
		SpatialCorrelation_Reset(&scorr);

	}	// cycle loop

	clock_t t_end = clock();
	double cpu_time = (double)(t_end - t_start) / CLOCKS_PER_SEC;
	printf("finished simulation, CPU time: %g, average CPU time per run: %g\n", cpu_time, cpu_time / (ncycles * nsamples));

	// clean up
	fftw_free(J_inr);
	fftw_free(F_int);
	fftw_free(J_int);
	SpatialCorrelation_Delete(&scorr);
	EventTable_Delete(&tab);
	fftw_cleanup();

	return 0;
}