Skip to content
Snippets Groups Projects
Configuration.cpp 50.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • cmaffeo2's avatar
    cmaffeo2 committed
    #include "Configuration.h"
    
    
    cmaffeo2's avatar
    cmaffeo2 committed
    #define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
    inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true) {
       if (code != cudaSuccess) {
          fprintf(stderr,"CUDA Error: %s %s %d\n", cudaGetErrorString(code), __FILE__, line);
          if (abort) exit(code);
       }
    }
    
    Configuration::Configuration(const char* config_file, int simNum, bool debug) :
    		simNum(simNum) {
    	// Read the parameters.
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	kTGrid_d = NULL;
    
    	//bonds_d = NULL;
    	//bondMap_d = NULL;
    	//excludes_d = NULL;
    	//excludeMap_d = NULL;
    	//angles_d = NULL;
    	//dihedrals_d = NULL;
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	setDefaults();
    	readParameters(config_file);
    
    	printf("\nCounting particles specified in the ");
    	if (restartCoordinates.length() > 0) {
    
    		printf("restart file.\n");
    		num = countRestart(restartCoordinates.val());
    
      } else {
        if (readPartsFromFile) readAtoms();
        if (numPartsFromFile > 0) {
          // Determine number of particles from input file (PDB-style)
          printf("input file.\n");
          num = numPartsFromFile;
        } else {
          // Sum up all particles in config file
          printf("configuration file.\n");
          //int num0 = 0;
          num = 0;
          for (int i = 0; i < numParts; i++) num += part[i].num;
          //num = num0;
        }
      } // end result: variable "num" is set
    
    
    	// Set the number capacity
    	printf("\nInitial particles: %d\n", num);
    
    	if (numCap <= 0) numCap = numCapFactor*num; // max number of particles
    	if (numCap <= 0) numCap = 20;
    
    
    	// Allocate particle variables.
    	pos = new Vector3[num * simNum];
    	type = new int[num * simNum];
    	serial = new int[num * simNum];
    	posLast = new Vector3[num * simNum];
    	name = new String[num * simNum];
    	currSerial = 0;
    
    
      // Now, load the coordinates
    	loadedCoordinates = false;
    
     // If we have a restart file - use it
    	if (restartCoordinates.length() > 0) {
    		loadRestart(restartCoordinates.val());
    		printf("Loaded %d restart coordinates from `%s'.\n", num, restartCoordinates.val());
    		printf("Particle numbers specified in the configuration file will be ignored.\n");
    		loadedCoordinates = true;
    	} else {
    		// Load coordinates from a file?
    		if (numPartsFromFile > 0) {
    			loadedCoordinates = true;
    			for (int i = 0; i < num; i++) {
    				int numTokens = partsFromFile[i].tokenCount();
    
    				// Break the line down into pieces (tokens) so we can process them individually
    				String* tokenList = new String[numTokens];
    				partsFromFile[i].tokenize(tokenList);
    
    				int currType = 0;
    				for (int j = 0; j < numParts; j++)
    					if (tokenList[2] == part[j].name)
    						currType = j;
    
    				for (int s = 0; s < simNum; ++s)
    					type[i + s*num] = currType;
    
    				serial[i] = currSerial++;
    
    				pos[i] = Vector3(atof(tokenList[3].val()),
    												 atof(tokenList[4].val()),
    												 atof(tokenList[5].val()));
    			}
    			delete[] partsFromFile;
    			partsFromFile = NULL;
    		} else {
    			// Not loading coordinates from a file
    			populate();
    			if (inputCoordinates.length() > 0) {
    				printf("Loading coordinates from %s ... ", inputCoordinates.val());
    				loadedCoordinates = loadCoordinates(inputCoordinates.val());
    				if (loadedCoordinates)
    					printf("done!\n");
    			}
    		}
    	}
    
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	if (readBondsFromFile) readBonds();
    	if (readExcludesFromFile) readExcludes();
    	if (readAnglesFromFile) readAngles();
    	if (readDihedralsFromFile) readDihedrals();
    	/*
    	if (kTGridFile.length() != 0) {
    		printf("\nFound kT grid file: %s\n", kTGridFile.val());
    		kTGrid = new BaseGrid(kTGridFile.val());
    		printf("Loaded `%s'.\n", kTGridFile.val());
    		printf("System size %s.\n", kTGrid->getExtent().toString().val());
    	}
    	*/
    	if (temperatureGrid.length() != 0) {
    		printf("\nFound temperature grid file: %s\n", temperatureGrid.val());
    		tGrid = new BaseGrid(temperatureGrid.val());
    		printf("Loaded `%s'.\n", temperatureGrid.val());
    		printf("System size %s.\n", tGrid->getExtent().toString().val());
    
    
    		float ToSo = 1.0f / (295.0f * 4.634248239f); // 1 / (To * sigma(To))
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		sigmaT = new BaseGrid(temperatureGrid.val());
    		sigmaT->shift(-122.8305f);
    		sigmaT->scale(0.0269167f);
    		sigmaT->mult(*tGrid);
    		sigmaT->scale(ToSo);
    		kTGrid = new BaseGrid(temperatureGrid.val());
    		float factor = kT/295.0f;
    		kTGrid->scale(factor);
    		// char outFile[256];
    		// char comment[256]; sprintf(comment,"KTGrid");
    		// sprintf(outFile,"kTGrid.dx");
    		// kTGrid->write(outFile, comment);
    	}
    
    	printf("\nFound %d particle types.\n", numParts);
    	// Load the potential grids.
    	printf("Loading the potential grids...\n");
    	for (int i = 0; i < numParts; i++) {
    		// Decide which type of grid is given.
    		String map = partGridFile[i];
    		int len = map.length();
    		if (len >= 3 && map[len-3]=='.' && map[len-2]=='d' && map[len-1]=='x') {
    			// A dx file. Load the old-fashioned way.
    			part[i].pmf = new BaseGrid(map.val());
    			part[i].meanPmf = part[i].pmf->mean();
    			printf("Loaded dx grid `%s'.\n", map.val());
    			printf("System size %s.\n", part[i].pmf->getExtent().toString().val());
    		} else if  (len >= 4 && map[len-4]=='.' && map[len-3]=='d' && map[len-2]=='e' && map[len-1]=='f') {
    			// A system definition file.
    			String rootGrid = OverlordGrid::readDefFirst(map);
    			OverlordGrid* over = new OverlordGrid(rootGrid.val());
    			int count = over->readDef(map);
    			printf("Loaded system def file `%s'.\n", map.val());
    			printf("Found %d unique grids.\n", over->getUniqueGridNum());
    			printf("Linked %d subgrids.\n", count);
    
    			part[i].pmf = static_cast<BaseGrid*>(over);
    			part[i].meanPmf = part[i].pmf->mean();
    		} else {
    			printf("WARNING: Unrecognized gridFile extension. Must be *.def or *.dx.\n");
    			exit(-1);
    		}
    
    		if (partForceXGridFile[i].length() != 0) {
    			part[i].forceXGrid = new BaseGrid(partForceXGridFile[i].val());
    			printf("Loaded `%s'.\n", partForceXGridFile[i].val());
    			printf("System size %s.\n", part[i].forceXGrid->getExtent().toString().val());
    		}
    
    		if (partForceYGridFile[i].length() != 0) {
    			part[i].forceYGrid = new BaseGrid(partForceYGridFile[i].val());
    			printf("Loaded `%s'.\n", partForceYGridFile[i].val());
    			printf("System size %s.\n", part[i].forceYGrid->getExtent().toString().val());
    
    cmaffeo2's avatar
    cmaffeo2 committed
    
    		if (partForceZGridFile[i].length() != 0) {
    			part[i].forceZGrid = new BaseGrid(partForceZGridFile[i].val());
    			printf("Loaded `%s'.\n", partForceZGridFile[i].val());
    			printf("System size %s.\n", part[i].forceZGrid->getExtent().toString().val());
    		}
    
    		if (partDiffusionGridFile[i].length() != 0) {
    			part[i].diffusionGrid = new BaseGrid(partDiffusionGridFile[i].val());
    			printf("Loaded `%s'.\n", partDiffusionGridFile[i].val());
    			printf("System size %s.\n", part[i].diffusionGrid->getExtent().toString().val());
    		}
    
    		if (temperatureGrid.length() != 0) {
    			if (partDiffusionGridFile[i].length() != 0) {
    				part[i].diffusionGrid->mult(*sigmaT);
    			} else {
    				part[i].diffusionGrid = new BaseGrid(*sigmaT);
    				part[i].diffusionGrid->scale(part[i].diffusion);
    				// char outFile[256];
    				// char comment[256]; sprintf(comment,"Diffusion for particle type %d", i);
    				// sprintf(outFile,"diffusion%d.dx",i);
    				// part[i].diffusionGrid->write(outFile, comment);
    			}
    		}
    
    	}
    
        // Load reservoir files if any
        for (int i = 0; i < numParts; i++) {
            if (partReservoirFile[i].length() != 0) {
                printf("\nLoading the reservoirs for %s... \n", part[i].name.val());
                part[i].reservoir = new Reservoir(partReservoirFile[i].val());
                int nRes = part[i].reservoir->length();
                printf("\t -> %d reservoir(s) found in `%s'.\n", nRes, partReservoirFile[i].val());
            }
        }
    
        // Get the system dimensions
        // from the dimensions of supplied 3D potential maps
    	sys = part[0].pmf;
    	sysDim = part[0].pmf->getExtent();
    
    
    cmaffeo2's avatar
    cmaffeo2 committed
    // RBTODO: clean this mess up
    	/* // RigidBodies... */
    	/* if (numRigidTypes > 0) { */
    	/* 	printf("\nCounting rigid bodies specified in the configuration file.\n"); */
    	/* 	numRB = 0; */
    
    	/* 	// grow list of rbs */
    	/* 	for (int i = 0; i < numRigidTypes; i++) {			 */
    	/* 		numRB += rigidBody[i].num; */
    
    	/* 		std::vector<RigidBody> tmp; */
    	/* 		for (int j = 0; j < rigidBody[i].num; j++) { */
    	/* 			tmp.push_back( new RigidBody( this, rigidBody[i] ) ); */
    	/* 		} */
    
    	/* 		rbs.push_back(tmp); */
    	/* 	} */
    
    		// // state data
    		// rbPos = new Vector3[numRB * simNum];
    		// type = new int[numRB * simNum];
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	/* } */
    	/* printf("Initial RigidBodies: %d\n", numRB); */
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	// Create exclusions from the exclude rule, if it was specified in the config file
    	if (excludeRule != String("")) {
    		int oldNumExcludes = numExcludes;
    		Exclude* newExcludes = makeExcludes(bonds, bondMap, num, numBonds, excludeRule, numExcludes);
    		if (excludes == NULL) {
    
    			excludes = new Exclude[numExcludes];
    		} else if (numExcludes >= excludeCapacity) {
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			Exclude* tempExcludes = excludes;
    			excludes = new Exclude[numExcludes];
    			for (int i = 0; i < oldNumExcludes; i++)
    				excludes[i] = tempExcludes[i];
    			delete tempExcludes;
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		for (int i = oldNumExcludes; i < numExcludes; i++)
    			excludes[i] = newExcludes[i - oldNumExcludes];
    		printf("Built %d exclusions.\n",numExcludes);
    
    		// Call compareExcludeIndex with qsort to sort the excludes by BOTH ind1 AND ind2
    		std::sort(excludes, excludes + numExcludes, compare());
    
    		/* Each particle may have a varying number of excludes
    		 * excludeMap is an array with one element for each particle
    		 * which keeps track of where a particle's excludes are stored
    		 * in the excludes array.
    		 * excludeMap[i].x is the index in the excludes array where the ith particle's excludes begin
    		 * excludeMap[i].y is the index in the excludes array where the ith particle's excludes end
    		 */
    		excludeMap = new int2[numPartsFromFile];
    
    		for (int i = 0; i < numPartsFromFile; i++) {
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			excludeMap[i].x = -1;
    			excludeMap[i].y = -1;
    		}
    		int currPart = -1;
    		int lastPart = -1;
    		for (int i = 0; i < numExcludes; i++) {
    			if (excludes[i].ind1 != currPart) {
    				currPart = excludes[i].ind1;
    				excludeMap[currPart].x = i;
    				if (lastPart >= 0)
    					excludeMap[lastPart].y = i;
    				lastPart = currPart;
    			}
    		}
    	}
    
    	// Some geometric stuff that should be gotten rid of.
    	Vector3 buffer = (sys->getCenter() + 2.0f*sys->getOrigin())/3.0f;
    	initialZ = buffer.z;
    
    	// Set the initial conditions.
    	// Do the initial conditions come from restart coordinates?
    	// inputCoordinates are ignored if restartCoordinates exist.
    	/*
    	if (restartCoordinates.length() > 0) {
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		printf("Loaded %d restart coordinates from `%s'.\n", num, restartCoordinates.val());
    		printf("Particle numbers specified in the configuration file will be ignored.\n");
    	} else {
    		// Set the particle types.
    
    		// Load coordinates from a file?
    		if (numPartsFromFile > 0) {
    
    cmaffeo2's avatar
    cmaffeo2 committed
    				int numTokens = partsFromFile[i].tokenCount();
    
    cmaffeo2's avatar
    cmaffeo2 committed
    				// Break the line down into pieces (tokens) so we can process them individually
    				String* tokenList = new String[numTokens];
    				partsFromFile[i].tokenize(tokenList);
    				int currType = 0;
    				for (int j = 0; j < numParts; j++)
    					if (tokenList[2] == part[j].name)
    						currType = j;
    				type[i] = currType;
    				serial[i] = currSerial;
    				currSerial++;
    
    				pos[i] = Vector3(atof(tokenList[3].val()), atof(tokenList[4].val()), atof(tokenList[5].val()));
    			}
    			if (partsFromFile != NULL) {
    				delete[] partsFromFile;
    				partsFromFile = NULL;
    			}
    		} else if (inputCoordinates.length() > 0) {
    			populate();
    			printf("Loading coordinates from %s.\n", inputCoordinates.val());
    			bool loaded = loadCoordinates(inputCoordinates.val());
    			if (loaded) 
    				printf("Loaded initial coordinates from %s.\n", inputCoordinates.val());
    		}
    	}
    	*/
    	
    
    	// Get the maximum particle radius.
    	minimumSep = 0.0f;
    	for (int i = 0; i < numParts; ++i)
    		minimumSep = std::max(minimumSep, part[i].radius);
    	minimumSep *= 2.5f; // Make it a little bigger.
    
    	// Default outputEnergyPeriod
    	if (outputEnergyPeriod < 0)
    		outputEnergyPeriod = 10 * outputPeriod;
    	
    	// If we are running with debug ON, ask the user which force computation to use
    	if (debug)
    		getDebugForce();
    
    	printf("\n");
    	switchStart = cutoff - switchLen;
    	if (fullLongRange == 0)
    		printf("Cutting off the potential from %.10g to %.10g.\n", switchStart, switchStart+switchLen);
    	
    	if (fullLongRange != 0)
    		printf("No cell decomposition created.\n");
    }
    
    Configuration::~Configuration() {
    	// System state
    	delete[] pos;
    	delete[] posLast;
    	delete[] type;
    	delete[] name;
    	
    	// Particle parameters
    	delete[] part;
    	delete[] partGridFile;
    	delete[] partForceXGridFile;
    	delete[] partForceYGridFile;
    	delete[] partForceZGridFile;
    	delete[] partDiffusionGridFile;
    	delete[] partReservoirFile;
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	if (partsFromFile != NULL) delete[] partsFromFile;
    	if (bonds != NULL) delete[] bonds;
    	if (bondMap != NULL) delete[] bondMap;
    	if (excludes != NULL) delete[] excludes;
    	if (excludeMap != NULL) delete[] excludeMap;
    	if (angles != NULL) delete[] angles;
    	if (dihedrals != NULL) delete[] dihedrals;
    
    	// Table parameters
    	delete[] partTableFile;
    	delete[] partTableIndex0;
    	delete[] partTableIndex1;
    
    	delete[] bondTableFile;
    
    	delete[] angleTableFile;
    
    	delete[] dihedralTableFile;
    
    
    	//if (type_d != NULL) {
    		//gpuErrchk(cudaFree(type_d));
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		gpuErrchk(cudaFree(sys_d));
    		gpuErrchk(cudaFree(kTGrid_d));
    		gpuErrchk(cudaFree(part_d));
    
    		//gpuErrchk(cudaFree(bonds_d));
    		//gpuErrchk(cudaFree(bondMap_d));
    		//gpuErrchk(cudaFree(excludes_d));
    		//gpuErrchk(cudaFree(excludeMap_d));
    		//gpuErrchk(cudaFree(angles_d));
    		//gpuErrchk(cudaFree(dihedrals_d));
    	//}
    
    cmaffeo2's avatar
    cmaffeo2 committed
    }
    
    void Configuration::copyToCUDA() {
    	printf("Copying to GPU %d\n", GPUManager::current());
    
    	BrownianParticleType **part_addr = new BrownianParticleType*[numParts];
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	// Copy the BaseGrid objects and their member variables/objects
    	gpuErrchk(cudaMalloc(&part_d, sizeof(BrownianParticleType*) * numParts));
    	// TODO: The above line fails when there is not enough memory. If it fails, stop.
    	
    	for (int i = 0; i < numParts; i++) {
    		BaseGrid *pmf = NULL, *diffusionGrid = NULL;
    		BrownianParticleType *b = new BrownianParticleType(part[i]);
    		// Copy PMF
    		if (part[i].pmf != NULL) {
    			float *val = NULL;
    			size_t sz = sizeof(float) * part[i].pmf->getSize();
    		  gpuErrchk(cudaMalloc(&pmf, sizeof(BaseGrid)));
    		  gpuErrchk(cudaMalloc(&val, sz));
    		  gpuErrchk(cudaMemcpyAsync(val, part[i].pmf->val, sz, cudaMemcpyHostToDevice));
    		  BaseGrid *pmf_h = new BaseGrid(*part[i].pmf);
    			pmf_h->val = val;
    			gpuErrchk(cudaMemcpy(pmf, pmf_h, sizeof(BaseGrid), cudaMemcpyHostToDevice));
    			pmf_h->val = NULL;
    		}
    		
    		// Copy the diffusion grid
    		if (part[i].diffusionGrid != NULL) {
    			float *val = NULL;
    			size_t sz = sizeof(float) * part[i].diffusionGrid->getSize();
    		  BaseGrid *diffusionGrid_h = new BaseGrid(*part[i].diffusionGrid);
    		  gpuErrchk(cudaMalloc(&diffusionGrid, sizeof(BaseGrid)));
    		  gpuErrchk(cudaMalloc(&val, sz));
    			diffusionGrid_h->val = val;
    			gpuErrchk(cudaMemcpyAsync(diffusionGrid, diffusionGrid_h, sizeof(BaseGrid),
    					cudaMemcpyHostToDevice));
    		  gpuErrchk(cudaMemcpy(val, part[i].diffusionGrid->val, sz, cudaMemcpyHostToDevice));
    			diffusionGrid_h->val = NULL;
    		}
    		
    		b->pmf = pmf;
    		b->diffusionGrid = diffusionGrid;
    		gpuErrchk(cudaMalloc(&part_addr[i], sizeof(BrownianParticleType)));
    		gpuErrchk(cudaMemcpyAsync(part_addr[i], b, sizeof(BrownianParticleType),
    				cudaMemcpyHostToDevice));
    	}
    
    	// RBTODO: moved this out of preceding loop; was that correct?
    	gpuErrchk(cudaMemcpyAsync(part_d, part_addr, sizeof(BrownianParticleType*) * numParts,
    				cudaMemcpyHostToDevice));
    
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	// kTGrid_d
    	kTGrid_d = NULL;
    	if (temperatureGrid.length() > 0) {
    		gpuErrchk(cudaMalloc(&kTGrid_d, sizeof(BaseGrid)));
    		gpuErrchk(cudaMemcpyAsync(kTGrid_d, kTGrid, sizeof(BaseGrid), cudaMemcpyHostToDevice));
    	}
    
    	// type_d and sys_d
    	gpuErrchk(cudaMalloc(&sys_d, sizeof(BaseGrid)));
    	gpuErrchk(cudaMemcpyAsync(sys_d, sys, sizeof(BaseGrid), cudaMemcpyHostToDevice));
    
    	/*gpuErrchk(cudaMalloc(&type_d, sizeof(int) * num * simNum));
    	gpuErrchk(cudaMemcpyAsync(type_d, type, sizeof(int) * num * simNum, cudaMemcpyHostToDevice));
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	
    	if (numBonds > 0) {
    		// bonds_d
    		gpuErrchk(cudaMalloc(&bonds_d, sizeof(Bond) * numBonds));
    		gpuErrchk(cudaMemcpyAsync(bonds_d, bonds, sizeof(Bond) * numBonds, cudaMemcpyHostToDevice));
    		
    		// bondMap_d
    		gpuErrchk(cudaMalloc(&bondMap_d, sizeof(int2) * num));
    		gpuErrchk(cudaMemcpyAsync(bondMap_d, bondMap, sizeof(int2) * num, cudaMemcpyHostToDevice));
    	}
    
    	if (numExcludes > 0) {
    		// excludes_d
    		gpuErrchk(cudaMalloc(&excludes_d, sizeof(Exclude) * numExcludes));
    		gpuErrchk(cudaMemcpyAsync(excludes_d, excludes, sizeof(Exclude) * numExcludes,
    				cudaMemcpyHostToDevice));
    		
    		// excludeMap_d
    		gpuErrchk(cudaMalloc(&excludeMap_d, sizeof(int2) * num));
    		gpuErrchk(cudaMemcpyAsync(excludeMap_d, excludeMap, sizeof(int2) * num,
    				cudaMemcpyHostToDevice));
    	}
    
    	if (numAngles > 0) {
    		// angles_d
    		gpuErrchk(cudaMalloc(&angles_d, sizeof(Angle) * numAngles));
    		gpuErrchk(cudaMemcpyAsync(angles_d, angles, sizeof(Angle) * numAngles,
    				cudaMemcpyHostToDevice));
    	}
    
    	if (numDihedrals > 0) {
    		// dihedrals_d
    		gpuErrchk(cudaMalloc(&dihedrals_d, sizeof(Dihedral) * numDihedrals));
    		gpuErrchk(cudaMemcpyAsync(dihedrals_d, dihedrals,
    												 		  sizeof(Dihedral) * numDihedrals,
    														 	cudaMemcpyHostToDevice));
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	gpuErrchk(cudaDeviceSynchronize());
    }
    
    void Configuration::setDefaults() {
    	// System parameters
    	outputName = "out";
    	timestep = 1e-5f;
    	steps = 100;
    	seed = 0;
    	inputCoordinates = "";
    	restartCoordinates = "";
    	numberFluct = 0;
    	numberFluctPeriod = 200;
    	interparticleForce = 1;
    	tabulatedPotential = 0;
    	fullLongRange = 1;
    	kT = 1.0f;
    	//	kTGridFile = ""; // Commented out for an unknown reason
    	temperatureGrid = "";
    	coulombConst = 566.440698f/92.0f;
    	electricField = 0.0f;
    	cutoff = 10.0f;
    	switchLen = 2.0f;
    	outputPeriod = 200;
    	outputEnergyPeriod = -1;
    	outputFormat = TrajectoryWriter::formatDcd;
    	currentSegmentZ = -1.0f;
    	numCap = 0;
    	decompPeriod = 10;
    	readPartsFromFile = 0;
    	numPartsFromFile = 0;
    	partsFromFile = NULL;
    	readBondsFromFile = false;
    	numBonds = 0;
    	bonds = NULL;
    	bondMap = NULL;
    	numTabBondFiles = 0;
    	readExcludesFromFile = false;
    	numExcludes = 0;
    	excludeCapacity = 256;
    	excludes = NULL;
    	excludeMap = NULL;
    	excludeRule = "";
    	readAnglesFromFile = false;
    	numAngles = 0;
    	angles = NULL;
    	numTabAngleFiles = 0;
    	readDihedralsFromFile = false;
    	numDihedrals = 0;
    	dihedrals = NULL;
    	numTabDihedralFiles = 0;
    
    	// Hidden parameters
    	// Might be parameters later
    	numCapFactor = 5;
    }
    
    int Configuration::readParameters(const char * config_file) {
    	Reader config(config_file);
    	printf("Read config file %s\n", config_file);
    
    	// Get the number of particles.
    	const int numParams = config.length();
    	numParts = config.countParameter("particle");
    
    	numRigidTypes = config.countParameter("rigidBody");
    
    cmaffeo2's avatar
    cmaffeo2 committed
    
    	// Allocate the particle variables.
    	part = new BrownianParticleType[numParts];
    	partGridFile = new String[numParts];
    	partForceXGridFile = new String[numParts];
    	partForceYGridFile = new String[numParts];
    	partForceZGridFile = new String[numParts];
    	partDiffusionGridFile = new String[numParts];
    	partReservoirFile = new String[numParts];
    
    	// Allocate the table variables.
    	partTableFile = new String[numParts*numParts];
    	partTableIndex0 = new int[numParts*numParts];
    	partTableIndex1 = new int[numParts*numParts];
    
    
      // Allocate rigid body types
    
    	rigidBody = new RigidBodyType[numRigidTypes];
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	
    	int btfcap = 10;
    	bondTableFile = new String[btfcap];
    
    	int atfcap = 10;
    	angleTableFile = new String[atfcap];
    
    	int dtfcap = 10;
    	dihedralTableFile = new String[dtfcap];
    
    	int currPart = -1;
    	int currTab = -1;
    	int currBond = -1;
    	int currAngle = -1;
    	int currDihedral = -1;
    
    	int currRB = -1;
    
    	int partClassPart =  0;
    	int partClassRB   =  1;
    	int currPartClass = -1;				// 0 => particle, 1 => rigidBody
    	
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	for (int i = 0; i < numParams; i++) {
    		String param = config.getParameter(i);
    		String value = config.getValue(i);
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		if (param == String("outputName"))
    			outputName = value;
    		else if (param == String("timestep"))
    			timestep = (float) strtod(value.val(), NULL);
    		else if (param == String("steps"))
    			steps = atol(value.val());
    		else if (param == String("seed"))
    			seed = atoi(value.val());
    		else if (param == String("inputCoordinates"))
    			inputCoordinates = value;
    		else if (param == String("restartCoordinates"))
    			restartCoordinates = value;
    		else if (param == String("kT"))
    			kT = (float) strtod(value.val(), NULL);
    		// else if (param == String("kTGridFile")) kTGridFile = value;
    		else if (param == String("temperatureGrid"))
    			temperatureGrid = value;
    		else if (param == String("numberFluct"))
    			numberFluct = atoi(value.val());
    		else if (param == String("numberFluctPeriod"))
    			numberFluctPeriod = atoi(value.val());
    		else if (param == String("interparticleForce"))
    			interparticleForce = atoi(value.val());
    		else if (param == String("fullLongRange") || param == String("fullElect") )
    			fullLongRange = atoi(value.val());
    		else if (param == String("coulombConst"))
    			coulombConst = (float) strtod(value.val(), NULL);
    		else if (param == String("electricField"))
    			electricField = (float) strtod(value.val(), NULL);
    		else if (param == String("cutoff"))
    			cutoff = (float) strtod(value.val(), NULL);
    		else if (param == String("switchLen"))
    			switchLen = (float) strtod(value.val(), NULL);
    		else if (param == String("outputPeriod"))
    			outputPeriod = atoi(value.val());
    		else if (param == String("outputEnergyPeriod"))
    			outputEnergyPeriod = atoi(value.val());
    		else if (param == String("outputFormat"))
    			outputFormat = TrajectoryWriter::getFormatCode(value);
    		else if (param == String("currentSegmentZ"))
    			currentSegmentZ = (float) strtod(value.val(), NULL);
    		else if (param == String("numCap"))
    			numCap = atoi(value.val());
    		else if (param == String("decompPeriod"))
    			decompPeriod = atoi(value.val());
    
    		// PARTICLES
    		else if (param == String("particle")) {
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			part[++currPart] = BrownianParticleType(value);
    
    			currPartClass = partClassPart;
    		}
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		else if (param == String("forceXGridFile"))
    			partForceXGridFile[currPart] = value;
    		else if (param == String("forceYGridFile"))
    			partForceYGridFile[currPart] = value;
    		else if (param == String("forceZGridFile"))
    			partForceZGridFile[currPart] = value;
    		else if (param == String("diffusionGridFile"))
    			partDiffusionGridFile[currPart] = value;
    		else if (param == String("diffusion"))
    			part[currPart].diffusion = (float) strtod(value.val(), NULL);
    		else if (param == String("charge"))
    			part[currPart].charge = (float) strtod(value.val(), NULL);
    		else if (param == String("radius"))
    			part[currPart].radius = (float) strtod(value.val(), NULL);
    		else if (param == String("eps"))
    			part[currPart].eps = (float) strtod(value.val(), NULL);
    		else if (param == String("reservoirFile"))
    			partReservoirFile[currPart] = value;
    		else if (param == String("tabulatedPotential"))
    			tabulatedPotential = atoi(value.val());
    		else if (param == String("tabulatedFile"))
    			readTableFile(value, ++currTab);
    		else if (param == String("tabulatedBondFile")) {
    			if (numTabBondFiles >= btfcap) {
    				String* temp = bondTableFile;
    				btfcap *= 2;	
    				bondTableFile = new String[btfcap];
    				for (int j = 0; j < numTabBondFiles; j++)
    					bondTableFile[i] = temp[i];
    				delete[] temp;
    			}
    			if (readBondFile(value, ++currBond))
    				numTabBondFiles++;
    		} else if (param == String("inputParticles")) {
    			if (readPartsFromFile) {
    				printf("WARNING: More than one particle file specified. Discarding new file.\n");
    			} else {
    				partFile = value;
    				readPartsFromFile = true;
    				loadedCoordinates = true;
    			}
    		} else if (param == String("inputBonds")) {
    			if (readBondsFromFile) {
    				printf("WARNING: More than one bond file specified. Discarding new bond file.\n");
    			} else {
    				bondFile = value;				
    				readBondsFromFile = true;
    			}
    		} else if (param == String("inputExcludes")) {
    			if (readExcludesFromFile) {
    				printf("WARNING: More than one exclude file specified. Discarding new exclude file.\n");
    			} else {
    				excludeFile = value;				
    				readExcludesFromFile = true;
    			}
    		} else if (param == String("exclude") or param == String("exclusion")) {
    			excludeRule = value; 
    		} else if (param == String("inputAngles")) {
    			if (readAnglesFromFile) {
    				printf("WARNING: More than one angle file specified. Discarding new angle file.\n");
    			} else {
    				angleFile = value;
    				readAnglesFromFile = true;
    			}
    		} else if (param == String("tabulatedAngleFile")) {
    			if (numTabAngleFiles >= atfcap) {
    				String* temp = angleTableFile;
    				atfcap *= 2;	
    				angleTableFile = new String[atfcap];
    				for (int j = 0; j < numTabAngleFiles; j++)
    					angleTableFile[i] = temp[i];
    				delete[] temp;
    			}
    			if (readAngleFile(value, ++currAngle))
    				numTabAngleFiles++;
    		} else if (param == String("inputDihedrals")) {
    			if (readDihedralsFromFile) {
    				printf("WARNING: More than one dihedral file specified. Discarding new dihedral file.\n");
    			} else {
    				dihedralFile = value;
    				readDihedralsFromFile = true;
    			}
    		} else if (param == String("tabulatedDihedralFile")) {
    			if (numTabDihedralFiles >= dtfcap) {
    				String * temp = dihedralTableFile;
    				dtfcap *= 2;
    				dihedralTableFile = new String[dtfcap];
    				for (int j = 0; j < numTabDihedralFiles; j++)
    					dihedralTableFile[i] = temp[i];
    				delete[] temp;
    			}
    			if (readDihedralFile(value, ++currDihedral))
    				numTabDihedralFiles++;
    
    		} 
    		// RIGID BODY
    		else if (param == String("rigidBody")) {
    
    			// part[++currPart] = BrownianParticleType(value);
    
    			rigidBody[++currRB] = RigidBodyType(value);
    			currPartClass = partClassRB;
    		}
    		else if (param == String("mass"))
    			rigidBody[currRB].mass = (float) strtod(value.val(), NULL);
    		else if (param == String("inertia"))
    			rigidBody[currRB].inertia = stringToVector3( value );
    		else if (param == String("transDamping"))
    			rigidBody[currRB].transDamping = stringToVector3( value );
    		else if (param == String("rotDamping"))
    			rigidBody[currRB].rotDamping = stringToVector3( value );
    
    
    		else if (param == String("densityGrid"))
    			rigidBody[currRB].addDensityGrid(value);
    
    		else if (param == String("potentialGrid"))
    			rigidBody[currRB].addPotentialGrid(value);
    
    		else if (param == String("densityGridScale"))
    			rigidBody[currRB].scaleDensityGrid(value);
    		else if (param == String("potentialGridScale"))
    			rigidBody[currRB].scalePotentialGrid(value);
    		else if (param == String("pmfScale"))
    			rigidBody[currRB].scalePMF(value);
    		else if (param == String("position"))
    			rigidBody[currRB].initPos = stringToVector3( value );
    		else if (param == String("orientation"))
    			rigidBody[currRB].initRot = stringToMatrix3( value );
    		
    
    		// COMMON
    		else if (param == String("num")) {
    			if (currPartClass == partClassPart)
    				part[currPart].num = atoi(value.val());
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			else if (currPartClass == partClassRB) 
    
    				rigidBody[currRB].num = atoi(value.val());
    		}
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		else if (param == String("gridFile")) {
    			if (currPartClass == partClassPart)
    				partGridFile[currPart] = value;
    			else if (currPartClass == partClassRB)
    				rigidBody[currRB].addPMF(value);
    		}
    
    		// UNKNOWN
    		else {
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			printf("WARNING: Unrecognized keyword `%s'.\n", param.val());
    		}
    	}
    
    
    	// extra configuration for RB types
    	for (int i = 0; i < numRigidTypes; i++)
    		rigidBody[i].setDampingCoeffs(timestep);
    	
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	return numParams;
    }
    
    Vector3 Configuration::stringToVector3(String s) {
    	// tokenize and return
    	int numTokens = s.tokenCount();
    	if (numTokens != 3) {
    		printf("ERROR: could not convert input to Vector3.\n"); // TODO improve this message
    		exit(1);
    	}
    	String* token = new String[numTokens];
    	s.tokenize(token);
    	Vector3 v( (float) strtod(token[0], NULL),
    						 (float) strtod(token[1], NULL),
    						 (float) strtod(token[2], NULL) );
    	return v;
    }
    
    Matrix3 Configuration::stringToMatrix3(String s) {
    	// tokenize and return
    	int numTokens = s.tokenCount();
    	if (numTokens != 9) {
    		printf("ERROR: could not convert input to Matrix3.\n"); // TODO improve this message
    		exit(1);
    	}
    	String* token = new String[numTokens];
    	s.tokenize(token);
    	Matrix3 m( (float) strtod(token[0], NULL),
    						 (float) strtod(token[1], NULL),
    						 (float) strtod(token[2], NULL),
    						 (float) strtod(token[3], NULL),
    						 (float) strtod(token[4], NULL),
    						 (float) strtod(token[5], NULL),
    						 (float) strtod(token[6], NULL),
    						 (float) strtod(token[7], NULL),
    						 (float) strtod(token[8], NULL) );
    	return m;
    }
    
    cmaffeo2's avatar
    cmaffeo2 committed
    
    void Configuration::readAtoms() {
    	// Open the file
    	FILE* inp = fopen(partFile.val(), "r");
    	char line[256];
    
    	// If the particle file cannot be found, exit the program
    	if (inp == NULL) {
    		printf("ERROR: Could not open `%s'.\n", partFile.val());
    		bool found = true;
    		for (int i = 0; i < numParts; i++)
    			if (part[i].num == 0)
    				found = false;
    		if (!found) {
    			printf("ERROR: Number of particles not specified in config file.\n");
    			exit(1);
    		}
    		printf("Using default coordinates file\n");
    		return;
    	}
    
    	// Our particle array has a starting capacity of 256
    	// We will expand this later if we need to.
    	int capacity = 256;
    	numPartsFromFile = 0;
    	partsFromFile = new String[capacity];
    	indices = new int[capacity];
    	indices[0] = 0;
    
    	// Get and process all lines of input
    	while (fgets(line, 256, inp) != NULL) {
    		// Lines in the particle file that begin with # are comments
    		if (line[0] == '#') continue;
    		      
    		String s(line);
    		int numTokens = s.tokenCount();
    		      
    		// Break the line down into pieces (tokens) so we can process them individually
    		String* tokenList = new String[numTokens];
    		s.tokenize(tokenList);
    
    		// Legitimate ATOM input lines have 6 tokens: 
    		// ATOM | Index | Name | X-coord | Y-coord | Z-coord
    		// A line without exactly six tokens should be discarded.
    		if (numTokens != 6) {
    			printf("Warning: Invalid particle file line: %s\n", line);
    			return;
    		}
    
    		// Ensure that this particle's type was defined in the config file.
    		// If not, discard this line.
    		bool found;
    		for (int j = 0; j < numParts; j++) {
    			// If this particle type exists, add a new one to the list
    			if (part[j].name == tokenList[2]) {
    				found = true;
    				part[j].num++;
    			}
    		}
    
    		// If the particle's type does not exist according to the config file, discard it.
    		if (!found) {
    			printf("WARNING Unknown particle type %s found and discarded.\n", tokenList[2].val());
    			continue;
    		}
    
    		// If we don't have enough room in our particle array, we need to expand it.
    		if (numPartsFromFile >= capacity) {
    			// Temporary pointers to the old arrays
    			String* temp = partsFromFile;	
    			int* temp2 = indices;
    
    			// Double the capacity
    			capacity *= 2;
    
    			// Create pointers to new arrays which are twice the size of the old ones
    			partsFromFile = new String[capacity];
    			indices = new int[capacity];
    		
    			// Copy the old values into the new arrays
    			for (int j = 0; j < numPartsFromFile; j++) {
    				partsFromFile[j] = temp[j];
    				indices[j] = temp2[j];
    			}
    
    			// delete the old arrays
    			delete[] temp;
    			delete[] temp2;
    		}
    		// Make sure the index of this particle is unique.
    		// NOTE: The particle list is sorted by index. 
    		bool uniqueID = true;		
    		int key = atoi(tokenList[1].val());
    		int mid = 0;
    
    		// If the index is greater than the last index in the list, 
    		// this particle belongs at the end of the list. Since the 
    		// list is kept sorted, we know this is okay.
    		if (numPartsFromFile == 0 || key > indices[numPartsFromFile - 1]) {
    			indices[numPartsFromFile] = key;
    			partsFromFile[numPartsFromFile++] = line;
    		}
    		// We need to do a binary search to figure out if
    		// the index already exists in the list. 
    		// The assumption is that input files SHOULD have their indices sorted in 
    		// ascending order, so we shouldn't actually use the binary search 
    		// or the sort (which is pretty time consuming) very often.
    		else {
    			int low = 0, high = numPartsFromFile - 1;
    			
    			while (low <= high) {
    				mid = (int)((high - low) / 2 + low);
    				int curr = indices[mid];
    				if (curr < key) {
    					low = mid + 1;
    				} else if (curr > key) {
    					high = mid - 1;
    				} else {
    					// For now, particles with non-unique IDs are simply not added to the array
    					// Other possible approaches which are not yet implemented:
    					// 1: Keep track of these particles and assign them new IDs after you have
    					//    already added all of the other particles. 	
    					// 2: Get rid of ALL particles with that ID, even the ones that have already 
    					//    been added.
    					printf("WARNING: Non-unique ID found: %s\n", line);
    					uniqueID = false;
    					break;
    				}
    			}
    			if (uniqueID) {
    				// Add the particle to the end of the array, then sort it. 
    				indices[numPartsFromFile] = key;
    				partsFromFile[numPartsFromFile++] = line;
    				std::sort(indices, indices + numPartsFromFile);
    				std::sort(partsFromFile, partsFromFile + numPartsFromFile, compare());		
    			}
    		}
    	}
    }
    
    void Configuration::readBonds() {
    	// Open the file
    	FILE* inp = fopen(bondFile.val(), "r");
    	char line[256];