/* 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 #else #include #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"); }