/*
DFT++ is a density functional package developed by the research group
of Professor Tomas Arias
Copyright 1996-2003 Sohrab Ismail-Beigi
This file is part of DFT++.
DFT++ is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
DFT++ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DFT++; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Please see the file CREDITS for a list of authors.
For academic users, we request that publications using results obtained with
this software reference
"New algebraic formulation of density functional calculation," by Sohrab Ismail-Beigi
and T.A. Arias, Computer Physics Communications 128:1-2, 1-45 (June 2000).
and, if using the wavelet basis, further reference
"Multiresolution analysis of electronic structure: semicardinal and wavelet bases,"
T.A. Arias, Reviews of Modern Physics 71:1, 267-311 (January 1999).
and
"Robust ab initio calculation of condensed matter: transparent convergence through
semicardinal multiresolution analysis,'' I.P. Daykov, T.A. Arias, and
Torkel D. Engeness, Physical Review Letters, 90:21, 216402 (May 2003).
For your convenience, preprints of the above articles may be obtained from
http://arXiv.org/abs/cond-mat/9909130, 9805262, and 0204411, respectively.
*/
/*
* Tairan Wang January 8, 1998
*
* System.c -- provide MPI setup.
*
*
*/
/* $Id: System.cpp,v 1.16.2.13 2003/05/29 18:54:06 ivan Exp $ */
#include "header.h"
#include "parallel.h" // include MPI related info.
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
///////////////////////////////
// //
// Define Static Data Member //
// //
///////////////////////////////
Output * System::global_log = NULL;
int System::N_Procs = 0;
int System::My_procID = 0;
// memory manager stuff
void ** System::scratch_pointers = NULL;
int * System::scratch_locks = NULL;
int * System::scratch_lengths = NULL;
int * System::scratch_sizes = NULL;
int System::num_scratch = 0;
#ifdef DFT_THREAD
// default number of threads
int System::N_threads = 1;
#endif
//////////////////////////////////////////////
/* *
* Static Member Function. Initialize *
* system configuration info. *
* *
* Must be called before any object of the *
* class is actually created *
* */
//////////////////////////////////////////////
void
System::GlobalInit(int* argc, char*** argv)
{
#ifdef DFT_MPI
int id, num_procs;
MPI_Init(argc, argv);
MPI_Comm_rank(MPI_COMM_WORLD, &id);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
System::N_Procs = num_procs;
System::My_procID = id;
#else // DFT_MPI
System::N_Procs = 1;
System::My_procID = 0;
#endif // DFT_MPI
}
void
System::GlobalFinalize()
{
#ifdef DFT_MPI
MPI_Finalize();
#endif // DFT_MPI
}
// platform-dependent timer
double
System::get_time(void)
{
#ifdef DFT_MPI
return MPI_Wtime();
#elif defined _WIN32
static LARGE_INTEGER freq;
static LARGE_INTEGER t;
static int first=1;
if(first) {
QueryPerformanceFrequency(&freq);
first=0;
}
QueryPerformanceCounter(&t);
return (double)t.QuadPart/(double)freq.QuadPart;
#else
// more sensitive timer
struct timeval t;
gettimeofday(&t,NULL);
return t.tv_sec + 1.e-6*t.tv_usec;
#endif
}
// Seed the random number generator with the current timer.
// flag==0 means all procs get the same seed
// flag==1 means different seeds on different procs
void System::seed_with_time(int flag)
{
if (flag!=0 && flag!=1)
die("flag is not 0 or 1 in System::seed_with_time(flag)\n\n");
unsigned int seed = (unsigned int)System::get_time();
#ifdef DFT_MPI
if (flag == 0)
// Same seed on all processors
MPI_Bcast(&seed,1,MPI_INT,System::Get_IOprocID(),MPI_COMM_WORLD);
else
// Processor dependent seed
seed = seed+System::Get_procID() + (1000*seed)/(System::Get_procID()+1);
#endif
srand(seed);
}
// Bite the dust with some last words
void die(const char *last_words, ...)
{
// variable argument list
va_list ap;
va_start(ap, last_words);
System::global_log->vprintf(DFT_SILENCE, last_words, ap);
System::global_log->flush();
#ifdef DFT_MPI
MPI_Abort(MPI_COMM_WORLD, 1);
#endif // DFT_MPI
exit(1);
}
/**********************************************************************
* *
* scratch space manager *
* *
**********************************************************************/
// at the beginning of the program, we set up a number of scratch spaces;
// this function can be called more than once, with different arguments.
void
System::setup_scratch(int howmany, int length, int datasize)
{
// make sure none of the scratch spaces are in use while we
// do setup.
dft_log("Setting up %d scratch spaces of length %d.\n", howmany, length);
int i;
for(i = 0; i < System::num_scratch; i++)
if(System::scratch_locks[i] == TRUE)
die("You tried to call System::setup_scratch() while some scratch spaces were in use. How naughty! Anyways, ciao...\n");
System::scratch_pointers = (void **) myrealloc(System::scratch_pointers,
(System::num_scratch + howmany)*sizeof(void *),
"scratch_pointers", "System::setup_scratch");
System::scratch_locks = (int *) myrealloc(System::scratch_locks,
(System::num_scratch + howmany)*sizeof(int),
"lock_scratch", "System::setup_scratch");
System::scratch_lengths = (int *) myrealloc(System::scratch_lengths,
(System::num_scratch + howmany)*sizeof(int),
"scratch_lengths", "System::setup_scratch");
System::scratch_sizes = (int *) myrealloc(System::scratch_sizes,
(System::num_scratch + howmany)*sizeof(int),
"scratch_sizes", "System::setup_scratch");
// allocate the newly requested scratchspaces
for(i = 0; i < howmany; i++){
System::scratch_pointers[System::num_scratch+i] =
(void *) mymalloc(length*datasize,
"scratch space", "System::setup_scratch()");
System::scratch_locks[System::num_scratch+i] = FALSE;
System::scratch_lengths[System::num_scratch+i] = length;
System::scratch_sizes[System::num_scratch+i] = datasize;
}
System::num_scratch += howmany;
}
// call this function to request a scratch space pointer.
void*
System::gimme_scratch(int length, int datasize)
{
int i;
int found_larger = -1;
// search for an unlocked scratch
for(i = 0; i < System::num_scratch; i++)
if(System::scratch_sizes[i] == datasize &&
System::scratch_locks[i] == FALSE)
if(System::scratch_lengths[i] == length){
// found an unlocked scratch, so lock it and return it
System::scratch_locks[i] = TRUE;
return System::scratch_pointers[i];
}else if(System::scratch_lengths[i] > length){
found_larger = i;
}
if(found_larger > -1){
System::scratch_locks[found_larger] = TRUE;
return System::scratch_pointers[found_larger];
}
// if we got here, there are no more scratches available,
// so die. we do this, to force the developers to think
// about how much scratch space they need ahead of time
die("System::gimme_scratch(%d, %d) failed, not enough scratch space\n",
length, datasize);
return NULL;
}
// when you are done, you have to release the scratch space
void
System::release_scratch(void *ptr)
{
int i;
// find which scratch is being released
for(i = 0; i < System::num_scratch; i++)
if(System::scratch_pointers[i] == ptr){
// gotcha. release it
System::scratch_locks[i] = FALSE;
return;
}
// if we got here, then the pointer passed in was not
// a valid scratch.
die("Invalid scratch pointer in System::release_scratch()\n");
}
syntax highlighted by Code2HTML, v. 0.9.1