Skip to content
Snippets Groups Projects
Configuration.cpp 52.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • cmaffeo2's avatar
    cmaffeo2 committed
    			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];
    
    	// If the particle file cannot be found, exit the program
    	if (inp == NULL) {
    		printf("WARNING: Could not open `%s'.\n", bondFile.val());
    		printf("         This simulation will not use particle bonds.\n");
    		return;
    	}
    
    	// Our particle array has a starting capacity of 256
    	// We will expand this later if we need to.
    	int capacity = 256;
    	numBonds = 0;
    	bonds = new Bond[capacity];
    
    	// 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 BOND input lines have 4 tokens: 
    		// BOND | OPERATION_FLAG | INDEX1 | INDEX2 | FILENAME 
    		// A line without exactly five tokens should be discarded.
    		if (numTokens != 5) {
    			printf("WARNING: Invalid bond file line: %s\n", line);
    			continue;
    		}
    
    		String op = tokenList[1];
    		int ind1 = atoi(tokenList[2].val());
    		int ind2 = atoi(tokenList[3].val());
    		String file_name = tokenList[4];
    
    
    		if (ind1 == ind2) {
    			printf("WARNING: Invalid bond file line: %s\n", line);
    			continue;
    		}
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		
    		// If we don't have enough room in our bond array, we need to expand it.
    
    		if (numBonds+1 >= capacity) { // "numBonds+1" because we are adding two bonds to array
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			// Temporary pointer to the old array
    			Bond* temp = bonds;	
    
    			// Double the capacity
    			capacity *= 2;
    
    			// Create pointer to new array which is twice the size of the old one
    			bonds = new Bond[capacity];
    		
    			// Copy the old values into the new array
    			for (int j = 0; j < numBonds; j++)
    				bonds[j] = temp[j];
    
    			// delete the old array
    			delete[] temp;
    		}
    		// Add the bond to the bond array
    		// We must add it twice: Once for (ind1, ind2) and once for (ind2, ind1)
    
    		
    		// RBTODO: add ind1/2 to exclusion list here iff op == REPLACE
    		/*if (op == Bond::REPLACE)
    		if( (int)(op) == 1)
    		{
    			printf("WARNING: Bond exclusions not implemented\n");
    			continue;
    		}*/
    
    
    		if (ind1 < 0 || ind1 >= num || ind2 < 0 || ind2 >=num) {
    			printf("ERROR: Bond file line '%s' includes invalid index\n", line);
    			exit(1);
    		}
    
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		Bond* b = new Bond(op, ind1, ind2, file_name);
    		bonds[numBonds++] = *b;
    		b = new Bond(op, ind2, ind1, file_name);
    		bonds[numBonds++] = *b;
    		delete[] tokenList;
    	}	
    	// Call compareBondIndex with qsort to sort the bonds by BOTH ind1 AND ind2
    	std::sort(bonds, bonds + numBonds, compare());
    
    	/* Each particle may have a varying number of bonds
    	 * bondMap is an array with one element for each particle
    	 * which keeps track of where a particle's bonds are stored
    	 * in the bonds array.
    	 * bondMap[i].x is the index in the bonds array where the ith particle's bonds begin
    	 * bondMap[i].y is the index in the bonds array where the ith particle's bonds end
    	 */
    
    	bondMap = new int2[num];
    	for (int i = 0; i < num; i++) {	
    
    cmaffeo2's avatar
    cmaffeo2 committed
    		bondMap[i].x = -1;
    		bondMap[i].y = -1;
    	}
    	int currPart = -1;
    	int lastPart = -1;
    	for (int i = 0; i < numBonds; i++) {
    		if (bonds[i].ind1 != currPart) {
    			currPart = bonds[i].ind1;
    			bondMap[currPart].x = i;
    			if (lastPart >= 0) bondMap[lastPart].y = i;
    			lastPart = currPart;
    		}
    	}
    	if (bondMap[lastPart].x > 0)
    		bondMap[lastPart].y = numBonds;
    }
    
    void Configuration::readExcludes()
    {
    	// Open the file
    	FILE* inp = fopen(excludeFile.val(), "r");
    	char line[256];
    
    	// If the exclusion file cannot be found, exit the program
    	if (inp == NULL) {
    		printf("WARNING: Could not open `%s'.\n", excludeFile.val());
    		printf("This simulation will not use exclusions.\n");
    		return;
    	}
    
    	// Our particle array has a starting capacity of 256
    	// We will expand this later if we need to.
    	excludeCapacity = 256;
    	numExcludes = 0;
    	excludes = new Exclude[excludeCapacity];
    
    	// 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 EXCLUDE input lines have 3 tokens: 
    		// BOND | INDEX1 | INDEX2
    		// A line without exactly three tokens should be discarded.
    		if (numTokens != 3) {
    			printf("WARNING: Invalid exclude file line: %s\n", line);
    			continue;
    		}
    		int ind1 = atoi(tokenList[1].val());
    		int ind2 = atoi(tokenList[2].val());
    
    		if (ind1 >= num || ind2 >= num) 
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			continue;
    		
    		// If we don't have enough room in our bond array, we need to expand it.
    		if (numExcludes >= excludeCapacity) {
    			// Temporary pointer to the old array
    			Exclude* temp = excludes;	
    
    			// Double the capacity
    			excludeCapacity *= 2;
    
    			// Create pointer to new array which is twice the size of the old one
    			excludes = new Exclude[excludeCapacity];
    		
    			// Copy the old values into the new array
    			for (int j = 0; j < numExcludes; j++)
    				excludes[j] = temp[j];
    
    			// delete the old array
    			delete[] temp;
    		}
    		// Add the bond to the exclude array
    		// We must add it twice: Once for (ind1, ind2) and once for (ind2, ind1)
    		Exclude ex(ind1, ind2);
    		excludes[numExcludes++] = ex;
    		Exclude ex2(ind2, ind1);
    		excludes[numExcludes++] = ex2;
    		delete[] tokenList;
    	}	
    	// 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[num];
    	for (int i = 0; i < num; 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;
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			assert(currPart < num);
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			excludeMap[currPart].x = i;
    			if (lastPart >= 0)
    			    excludeMap[lastPart].y = i;
    			lastPart = currPart;
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	if (excludeMap[lastPart].x > 0)
    	    excludeMap[lastPart].y = numExcludes;
    
    
    cmaffeo2's avatar
    cmaffeo2 committed
    }
    
    void Configuration::readAngles() {
    	FILE* inp = fopen(angleFile.val(), "r");
    	char line[256];
    	int capacity = 256;
    	numAngles = 0;
    	angles = new Angle[capacity];
    
    	// If the angle file cannot be found, exit the program
    	if (inp == NULL) {
    		printf("WARNING: Could not open `%s'.\n", angleFile.val());
    		printf("This simulation will not use angles.\n");
    		return;
    	}
    
    	while(fgets(line, 256, inp)) {
    		if (line[0] == '#') continue;
    		String s(line);
    		int numTokens = s.tokenCount();
    		String* tokenList = new String[numTokens];
    		s.tokenize(tokenList);
    		
    		// Legitimate ANGLE inputs have 5 tokens
    		// ANGLE | INDEX1 | INDEX2 | INDEX3 | FILENAME
    		// Any angle input line without exactly 5 tokens should be discarded
    		if (numTokens != 5) {
    			printf("WARNING: Invalid angle input line: %s\n", line);
    			continue;
    		}		
    		
    		// Discard any empty line
    		if (tokenList == NULL) 
    			continue;
    		
    		int ind1 = atoi(tokenList[1].val());
    		int ind2 = atoi(tokenList[2].val());
    		int ind3 = atoi(tokenList[3].val());
    		String file_name = tokenList[4];
    		//printf("file_name %s\n", file_name.val());
    
    		if (ind1 >= num or ind2 >= num or ind3 >= num)
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			continue;
    
    		if (numAngles >= capacity) {
    			Angle* temp = angles;
    			capacity *= 2;
    			angles = new Angle[capacity];
    			for (int i = 0; i < numAngles; i++)
    				angles[i] = temp[i];
    			delete[] temp;
    		}
    
    		Angle a(ind1, ind2, ind3, file_name);
    		angles[numAngles++] = a;
    		delete[] tokenList;
    	}
    	std::sort(angles, angles + numAngles, compare());	
    
    
    	// for(int i = 0; i < numAngles; i++)
    	// 	angles[i].print();
    
    cmaffeo2's avatar
    cmaffeo2 committed
    }
    
    void Configuration::readDihedrals() {
    	FILE* inp = fopen(dihedralFile.val(), "r");
    	char line[256];
    	int capacity = 256;
    	numDihedrals = 0;
    	dihedrals = new Dihedral[capacity];
    
    	// If the dihedral file cannot be found, exit the program
    	if (inp == NULL) {
    		printf("WARNING: Could not open `%s'.\n", dihedralFile.val());
    		printf("This simulation will not use dihedrals.\n");
    		return;
    	}
    
    	while(fgets(line, 256, inp)) {
    		if (line[0] == '#') continue;
    		String s(line);
    		int numTokens = s.tokenCount();
    		String* tokenList = new String[numTokens];
    		s.tokenize(tokenList);
    		
    		// Legitimate DIHEDRAL inputs have 6 tokens
    		// DIHEDRAL | INDEX1 | INDEX2 | INDEX3 | INDEX4 | FILENAME
    		// Any angle input line without exactly 6 tokens should be discarded
    		if (numTokens != 6) {
    			printf("WARNING: Invalid dihedral input line: %s\n", line);
    			continue;
    		}		
    		
    		// Discard any empty line
    		if (tokenList == NULL) 
    			continue;
    		
    		int ind1 = atoi(tokenList[1].val());
    		int ind2 = atoi(tokenList[2].val());
    		int ind3 = atoi(tokenList[3].val());
    		int ind4 = atoi(tokenList[4].val());
    		String file_name = tokenList[5];
    		//printf("file_name %s\n", file_name.val());
    
    		if (ind1 >= num or ind2 >= num
    				or ind3 >= num or ind4 >= num)
    
    cmaffeo2's avatar
    cmaffeo2 committed
    			continue;
    
    		if (numDihedrals >= capacity) {
    			Dihedral* temp = dihedrals;
    			capacity *= 2;
    			dihedrals = new Dihedral[capacity];
    			for (int i = 0; i < numDihedrals; ++i)
    				dihedrals[i] = temp[i];
    			delete[] temp;
    		}
    
    		Dihedral d(ind1, ind2, ind3, ind4, file_name);
    		dihedrals[numDihedrals++] = d;
    		delete[] tokenList;
    	}
    	std::sort(dihedrals, dihedrals + numDihedrals, compare());	
    
    
    	// for(int i = 0; i < numDihedrals; i++)
    	// 	dihedrals[i].print();
    
    cmaffeo2's avatar
    cmaffeo2 committed
    }
    
    void Configuration::populate() {
    	int pn = 0;
    	int p = 0;
    
    	for (int i = 0; i < num; i++) {
    		for (int s = 0; s < simNum; ++s)
    			type[i + s*num] = p;
    		serial[i] = currSerial++;
    		if (++pn >= part[p].num) {
    			p++;
    			pn = 0;
    		}
    	}
    }
    
    bool Configuration::readBondFile(const String& value, int currBond) {
    	int numTokens = value.tokenCount();
    	if (numTokens != 1) {
    		printf("ERROR: Invalid tabulatedBondFile: %s, numTokens = %d\n", value.val(), numTokens);
    		return false;
    	}
    
    	String* tokenList = new String[numTokens];
    	value.tokenize(tokenList);
    	if (tokenList == NULL) {
    		printf("ERROR: Invalid tabulatedBondFile: %s; tokenList is NULL\n", value.val());
    		return false;
    	}
    
    	bondTableFile[currBond] = tokenList[0];
    
    
    	// printf("Tabulated Bond Potential: %s\n", bondTableFile[currBond].val() );
    
    cmaffeo2's avatar
    cmaffeo2 committed
    
    	return true;
    }
    
    bool Configuration::readAngleFile(const String& value, int currAngle) {
    	int numTokens = value.tokenCount();
    	if (numTokens != 1) {
    		printf("ERROR: Invalid tabulatedAngleFile: %s, numTokens = %d\n", value.val(), numTokens);
    		return false;
    	}
    
    	String* tokenList = new String[numTokens];
    	value.tokenize(tokenList);
    	if (tokenList == NULL) {
    		printf("ERROR: Invalid tabulatedAngleFile: %s; tokenList is NULL\n", value.val());
    		return false;
    	}
    
    	angleTableFile[currAngle] = tokenList[0];
    
    
    	// printf("Tabulated Angle Potential: %s\n", angleTableFile[currAngle].val() );
    
    cmaffeo2's avatar
    cmaffeo2 committed
    
    	return true;
    }
    
    bool Configuration::readDihedralFile(const String& value, int currDihedral) {
    	int numTokens = value.tokenCount();
    	if (numTokens != 1) {
    		printf("ERROR: Invalid tabulatedDihedralFile: %s, numTokens = %d\n", value.val(), numTokens);
    		return false;
    	}
    
    	String* tokenList = new String[numTokens];
    	value.tokenize(tokenList);
    	if (tokenList == NULL) {
    		printf("ERROR: Invalid tabulatedDihedralFile: %s; tokenList is NULL\n", value.val());
    		return false;
    	}
    
    	dihedralTableFile[currDihedral] = tokenList[0];
    
    
    	// printf("Tabulated Dihedral Potential: %s\n", dihedralTableFile[currDihedral].val() );
    
    cmaffeo2's avatar
    cmaffeo2 committed
    
    	return true;
    }
    
    void Configuration::loadRestart(const char* file_name) {
    	char line[STRLEN];
    	FILE* inp = fopen(file_name, "r");
    
    	if (inp == NULL) {
    		printf("GrandBrownTown:loadRestart File `%s' does not exist\n", file_name);
    		exit(-1);
    	}
    
    	int count = 0;
    	while (fgets(line, STRLEN, inp) != NULL) {
    		// Ignore comments.
    		int len = strlen(line);
    		if (line[0] == '#') continue;
    		if (len < 2) continue;
    
    		String s(line);
    		int numTokens = s.tokenCount();
    		if (numTokens != 4) {
    			printf("GrandBrownTown:loadRestart Invalid coordinate file line: %s\n", line);
    			fclose(inp);	
    			exit(-1);
    		}
    
    		String* tokenList = new String[numTokens];
    		s.tokenize(tokenList);
    		if (tokenList == NULL) {
    			printf("GrandBrownTown:loadRestart Invalid coordinate file line: %s\n", line);
    			fclose(inp);
    			exit(-1);
    		}
    
    		int typ = atoi(tokenList[0]);
    		float x = (float) strtod(tokenList[1],NULL);
    		float y = (float) strtod(tokenList[2],NULL);
    		float z = (float) strtod(tokenList[3],NULL);
    
    		pos[count] = Vector3(x,y,z);
    		type[count] = typ;
    		serial[count] = currSerial;
    		currSerial++;
    		if (typ < 0 || typ >= numParts) {
    			printf("GrandBrownTown:countRestart Invalid particle type: %d\n", typ);
    			fclose(inp);
    			exit(-1);
    		}
    
    		count++;
    		delete[] tokenList;
    	}
    
    	fclose(inp);    
    }
    
    bool Configuration::loadCoordinates(const char* file_name) {
    	char line[STRLEN];
    	FILE* inp = fopen(file_name, "r");
    
    	if (inp == NULL) return false;
    
    	int count = 0;
    	while (fgets(line, STRLEN, inp) != NULL) {
    		// Ignore comments.
    		int len = strlen(line);
    		if (line[0] == '#') continue;
    		if (len < 2) continue;
    
    		String s(line);
    		int numTokens = s.tokenCount();
    		if (numTokens != 3) {
    			printf("ERROR: Invalid coordinate file line: %s\n", line);
    			fclose(inp);	
    			return false;
    		}
    
    		String* tokenList = new String[numTokens];
    		s.tokenize(tokenList);
    		if (tokenList == NULL) {
    			printf("ERROR: Invalid coordinate file line: %s\n", line);
    			fclose(inp);
    			return false;
    		}
    
    		if (count >= num) {
    			printf("WARNING: Too many coordinates in coordinate file %s.\n", file_name);
    			fclose(inp);
    			return true;
    		}
    
    		float x = (float) strtod(tokenList[0],NULL);
    		float y = (float) strtod(tokenList[1],NULL);
    		float z = (float) strtod(tokenList[2],NULL);
    		pos[count] = Vector3(x,y,z);
    		count++;
    
    		delete[] tokenList;
    	}
    	fclose(inp);
    
    	if (count < num) {
    		printf("ERROR: Too few coordinates in coordinate file.\n");
    		return false;
    	}
    	return true;
    }
    
    // Count the number of atoms in the restart file.
    int Configuration::countRestart(const char* file_name) {
    	char line[STRLEN];
    	FILE* inp = fopen(file_name, "r");
    
    	if (inp == NULL) {
    		printf("ERROR: countRestart File `%s' does not exist\n", file_name);
    		exit(-1);
    	}
    
    	int count = 0;
    	while (fgets(line, STRLEN, inp) != NULL) {
    		int len = strlen(line);
    		// Ignore comments.
    		if (line[0] == '#') continue;
    		if (len < 2) continue;
    
    		String s(line);
    		int numTokens = s.tokenCount();
    		if (numTokens != 4) {
    			printf("ERROR: countRestart Invalid coordinate file line: %s\n", line);
    			fclose(inp);	
    			exit(-1);
    		}
    
    		String* tokenList = new String[numTokens];
    		s.tokenize(tokenList);
    		if (tokenList == NULL) {
    			printf("ERROR: countRestart Invalid coordinate file line: %s\n", line);
    			fclose(inp);
    			exit(-1);
    		}
    
    		int typ = atoi(tokenList[0]);
    		// float x = strtod(tokenList[1],NULL);
    		// float y = strtod(tokenList[2],NULL);
    		// float z = strtod(tokenList[3],NULL);
    		if (typ < 0 || typ >= numParts) {
    			printf("ERROR: countRestart Invalid particle type: %d\n", typ);
    			fclose(inp);
    			exit(-1);
    		}
    
    		count++;
    		delete[] tokenList;
    	}
    
    	fclose(inp);    
    	return count;
    }
    
    bool Configuration::readTableFile(const String& value, int currTab) {
    	int numTokens = value.tokenCount('@');
    	if (numTokens != 3) {
    		printf("ERROR: Invalid tabulatedFile: %s\n", value.val());
    		return false;
    	}
    
    	String* tokenList = new String[numTokens];
    	value.tokenize(tokenList, '@');
    	if (tokenList == NULL) {
    		printf("ERROR: Invalid tabulatedFile: %s\n", value.val());
    		return false;
    	}
    
    	partTableIndex0[currTab] = atoi(tokenList[0]);
    	partTableIndex1[currTab] = atoi(tokenList[1]);
    	partTableFile[currTab] = tokenList[2];
    
    
    	// printf("Tabulated Potential: %d %d %s\n", partTableIndex0[currTab],
    	// 		partTableIndex1[currTab], partTableFile[currTab].val() );
    
    cmaffeo2's avatar
    cmaffeo2 committed
    	delete[] tokenList;
    	return true;
    }
    
    void Configuration::getDebugForce() {
    	// Allow the user to choose which force computation to use
    	printf("\n");
    	printf("(1) ComputeFull [Default]          (2) ComputeSoftcoreFull\n");
    	printf("(3) ComputeElecFull                (4) Compute (Decomposed)\n");
    	printf("(5) ComputeTabulated (Decomposed)  (6) ComputeTabulatedFull\n");
    
    	printf("WARNING: ");
    	if (tabulatedPotential) {
    		if (fullLongRange) printf("(6) was specified by config file\n");
    		else printf("(5) was specified by config file\n");
    	} else {
    		if (fullLongRange != 0) printf("(%d) was specified by config file\n", fullLongRange);
    		else printf("(4) was specified by config file\n");
    	}
    
    	char buffer[256];
    	int choice;
    	while (true) {
    		printf("Choose a force computation (1 - 6): ");
    		fgets(buffer, 256, stdin);
    		bool good = sscanf(buffer, "%d", &choice) && (choice >= 1 && choice <= 6);
    		if (good)
    			break;
    	}
    	switch(choice) {
    		case 1:
    			tabulatedPotential = 0;
    			fullLongRange = 1;
    			break;
    		case 2:
    			tabulatedPotential = 0;
    			fullLongRange = 2;
    			break;
    		case 3:
    			tabulatedPotential = 0;
    			fullLongRange = 3;
    			break;
    		case 4:
    			tabulatedPotential = 0;
    			fullLongRange = 0;
    			break;
    		case 5:
    			tabulatedPotential = 1;
    			fullLongRange = 0;
    			break;
    		case 6:
    			tabulatedPotential = 1;
    			fullLongRange = 1;
    			break;
    		default:
    			tabulatedPotential = 0;
    			fullLongRange = 1;
    			break;
    	}
    	printf("\n");
    }
    
    //////////////////////////
    // Comparison operators //
    //////////////////////////
    bool Configuration::compare::operator()(const String& lhs, const String& rhs) {
    	String* list_lhs = new String[lhs.tokenCount()];
    	String* list_rhs = new String[rhs.tokenCount()];
    	lhs.tokenize(list_lhs);
    	rhs.tokenize(list_rhs);
    	int key_lhs = atoi(list_lhs[1].val());
    	int key_rhs = atoi(list_rhs[1].val());
    	delete[] list_lhs;
    	delete[] list_rhs;
    	return key_lhs < key_rhs;
    }
    
    bool Configuration::compare::operator()(const Bond& lhs, const Bond& rhs) {
    	int diff = lhs.ind1 - rhs.ind1;
    	if (diff != 0)
    		return lhs.ind1 < rhs.ind1;
    	return lhs.ind2 < rhs.ind2;
    }
    
    bool Configuration::compare::operator()(const Exclude& lhs, const Exclude& rhs) {
    	int diff = lhs.ind1 - rhs.ind1;
    	if (diff != 0)
    		return lhs.ind1 < rhs.ind1;
    	return lhs.ind2 < rhs.ind2;
    }
    
    bool Configuration::compare::operator()(const Angle& lhs, const Angle& rhs) {
    	int diff = lhs.ind1 - rhs.ind1;
    	if (diff != 0)
    		return lhs.ind1 < rhs.ind1;
    	diff = lhs.ind2 - rhs.ind2;
    	if (diff != 0)
    		return lhs.ind2 < rhs.ind2;
    	return lhs.ind3 < rhs.ind3;
    }
    
    bool Configuration::compare::operator()(const Dihedral& lhs, const Dihedral& rhs) {
    	int diff = lhs.ind1 - rhs.ind1;
    	if (diff != 0) 
    		return lhs.ind1 < rhs.ind1;
    	diff = lhs.ind2 - rhs.ind2;
    	if (diff != 0) 
    		return lhs.ind2 < rhs.ind2;
    	diff = lhs.ind3 - rhs.ind3;
    	if (diff != 0) 
    		return lhs.ind3 < rhs.ind3;
    	return lhs.ind4 < rhs.ind4;
    }