#include "Configuration.h" #include "Angle.h" #include "Dihedral.h" #include "Restraint.h" #include "ProductPotential.h" #include <cmath> #include <cassert> #include <stdlib.h> /* srand, rand */ #include <time.h> /* time */ #include <string> #include <iostream> using namespace std; #ifndef gpuErrchk #define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); } inline void gpuAssert(cudaError_t code, const 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); } } #endif namespace { template<class T> void convertString(const String& token, void* data) { exit(1); } template<> void convertString<float>(const String& token, void* data) { float* tmp = (float*)data; *tmp = atof(token); } template<> void convertString<String>(const String& token, void* data) { String* tmp = (String*)data; *tmp = token; } template<class T> void stringToArray(String* str, int& size, T** array) { register int num; String *token; num = str->tokenCount(); size = num; *array = new T[num]; token = new String[num]; str->tokenize(token); for(int i = 0; i < num; ++i) convertString<T>(token[i], (*array)+i); delete [] token; } } Configuration::Configuration(const char* config_file, int simNum, bool debug) : simNum(simNum) { // Read the parameters. //type_d = NULL; kTGrid_d = NULL; //bonds_d = NULL; //bondMap_d = NULL; //excludes_d = NULL; //excludeMap_d = NULL; //angles_d = NULL; //dihedrals_d = NULL; setDefaults(); readParameters(config_file); // Get the number of particles // printf("\nCounting particles specified in the "); if (restartCoordinates.length() > 0) { // Read them from the restart file. // printf("restart file.\n"); num = countRestart(restartCoordinates.val()); if (copyReplicaCoordinates <= 0) { num /= simNum; } } 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 // Count particles associated with rigid bodies num_rb_attached_particles = 0; if (numRigidTypes > 0) { // grow list of rbs for (int i = 0; i < numRigidTypes; i++) { RigidBodyType &rbt = rigidBody[i]; rbt.attach_particles(); num_rb_attached_particles += rbt.num * rbt.num_attached_particles(); } } assert( num_rb_attached_particles == 0 || simNum == 1 ); // replicas not yet implemented // num = num+num_rb_attached_particles; // Set the number capacity printf("\n%d particles\n", num); printf("%d particles attached to RBs\n", num_rb_attached_particles); if (numCap <= 0) numCap = numCapFactor*num; // max number of particles if (numCap <= 0) numCap = 20; if (readGroupSitesFromFile) readGroups(); printf("%d groups\n", numGroupSites); // Allocate particle variables. // Each replica works with num+num_rb_attached_particles in array pos = new Vector3[ (num+num_rb_attached_particles) * simNum]; //Han-Yi Chou if (ParticleDynamicType == String("Langevin") || ParticleDynamicType == String("NoseHooverLangevin")) momentum = new Vector3[(num+num_rb_attached_particles) * simNum]; type = new int[(num+num_rb_attached_particles) * simNum]; serial = new int[(num+num_rb_attached_particles) * simNum]; posLast = new Vector3[(num+num_rb_attached_particles) * simNum]; { for (size_t replica = 0; replica < simNum; ++replica) { int pidx = 0; for (int i = 0; i < numRigidTypes; i++) { // Loop over RB types RigidBodyType &rbt = rigidBody[i]; for (int j = 0; j < rbt.num; ++j) { // Loop over RBs for (const int& t: rbt.get_attached_particle_types()) { size_t _idx = num+pidx+replica*(num+num_rb_attached_particles); type[_idx] = t; serial[_idx] = num+pidx; pidx++; } } } } } //Han-Yi Chou if(ParticleDynamicType == String("Langevin") || ParticleDynamicType == String("NoseHooverLangevin")) momLast = new Vector3[(num+num_rb_attached_particles) * simNum]; name = new String[(num+num_rb_attached_particles) * simNum]; currSerial = 0; // Now, load the coordinates loadedCoordinates = false; loadedMomentum = false; //Han-Yi Chou //I need kT here Han-Yi Chou kT = temperature * 0.0019872065f; // `units "k K" "kcal_mol"` //kT = temperature * 0.593f; // 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"); // Copy restart data to replicas for (size_t replica = 1; replica < simNum; ++replica) { for (size_t i = 0; i < num; ++i) { size_t _idx = i+replica*(num+num_rb_attached_particles); type[_idx] = type[i]; serial[_idx] = serial[i]; pos[_idx] = pos[i]; } } loadedCoordinates = true; //Han-Yi Chou Langevin dynamic if (ParticleDynamicType == String("Langevin") || ParticleDynamicType == String("NoseHooverLangevin")) { if (restartMomentum.length() > 0) { loadRestartMomentum(restartMomentum.val()); printf("Loaded %d restart momentum from `%s'.\n", num, restartMomentum.val()); printf("Particle numbers specified in the configuration file will be ignored.\n"); loadedMomentum = true; } else { printf("Warning: There is no restart momentum file when using restart coordinates in Langevin Dynamics\n"); printf("Initialize with Boltzmann distribution\n"); loadedMomentum = Boltzmann(COM_Velocity, num * simNum); } } } 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 = find_particle_type(tokenList[2]); if (currType == -1) { printf("Error: Unable to find particle type %s\n", tokenList[2].val()); exit(1); } 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+num_rb_attached_particles)] = currType; serial[i] = currSerial++; pos[i] = Vector3(atof(tokenList[3].val()), atof(tokenList[4].val()), atof(tokenList[5].val())); //Han-Yi Chou if (ParticleDynamicType == String("Langevin") || ParticleDynamicType == String("NoseHooverLangevin")) { loadedMomentum = true; if(numTokens == 9) momentum[i] = Vector3(atof(tokenList[6].val()), atof(tokenList[7].val()), atof(tokenList[8].val())); else { printf("Error occurs in %s at line %d. Please specify momentum\n", __FILE__, __LINE__); assert(1==2); } } } delete[] partsFromFile; partsFromFile = NULL; //Han-Yi Chou for(int i = 1; i < simNum; ++i) for(int j = 0; j < num; ++j) serial[j + num * i] = currSerial++; } 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"); } if(ParticleDynamicType == String("Langevin") || ParticleDynamicType == String("NoseHooverLangevin")) { if (inputMomentum.length() > 0) { printf("Loading momentum from %s ... ", inputMomentum.val()); loadedMomentum = loadMomentum(inputMomentum.val()); if (loadedMomentum) printf("done!\n"); } else loadedMomentum = Boltzmann(COM_Velocity, (num * simNum)); } } } //Check initialize momentum //if(ParticleDynamicType == String("Langevin")) //PrintMomentum(); /* Initialize exclusions */ excludeCapacity = 256; numExcludes = 0; excludes = new Exclude[excludeCapacity]; if (readExcludesFromFile) readExcludes(); if (readBondsFromFile) readBonds(); if (readAnglesFromFile) readAngles(); if (readDihedralsFromFile) readDihedrals(); if (readRestraintsFromFile) readRestraints(); if (readBondAnglesFromFile) readBondAngles(); if (readProductPotentialsFromFile) readProductPotentials(); if (temperatureGridFile.length() != 0) { printf("\nFound temperature grid file: %s\n", temperatureGridFile.val()); tGrid = new BaseGrid(temperatureGridFile.val()); printf("Loaded `%s'.\n", temperatureGridFile.val()); printf("Grid size %s.\n", tGrid->getExtent().toString().val()); // TODO: ask Max Belkin what this is about and how to remove hard-coded temps float ToSo = 1.0f / (295.0f * 4.634248239f); // 1 / (To * sigma(To)) sigmaT = new BaseGrid(*tGrid); sigmaT->shift(-122.8305f); sigmaT->scale(0.0269167f); sigmaT->mult(*tGrid); sigmaT->scale(ToSo); kTGrid = new BaseGrid(*tGrid); float factor = 0.0019872065f; // `units "k K" "kcal_mol"` 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); printf("Loading the potential grids...\n"); // First load a single copy of each grid for (int i = 0; i < numParts; i++) { for(int j = 0; j < part[i].numPartGridFiles; ++j) { std::string fname(partGridFile[i][j].val(), partGridFile[i][j].length()); if (part_grid_dictionary.count( fname ) == 0) { int len = fname.length(); if (len >= 3 && fname[len-3]=='.' && fname[len-2]=='d' && fname[len-1]=='x') { part_grid_dictionary.insert({fname, BaseGrid(fname.c_str())}); } else if (len >= 4 && fname[len-4]=='.' && fname[len-3]=='d' && fname[len-2]=='e' && fname[len-1]=='f') { assert(1==2); // Throw exception because this implementation needs to be revisited /* OverlordGrid* over = new OverlordGrid[part[i].numPartGridFiles]; part[i].meanPmf = new float[part[i].numPartGridFiles]; for(int j = 0; j < part[i].numPartGridFiles; ++j) { map = partGridFile[i][j]; len = map.length(); if (!(len >= 4 && map[len-4]=='.' && map[len-3]=='d' && map[len-2]=='e' && map[len-1]=='f')) { cout << "currently do not support different format " << endl; exit(1); } String rootGrid = OverlordGrid::readDefFirst(map); over[j] = 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].meanPmf[j] = part[i].pmf[j].mean(); } part[i].pmf = static_cast<BaseGrid*>(over); */ } else { printf("WARNING: Unrecognized gridFile extension. Must be *.def or *.dx.\n"); exit(-1); } } } } std::map<std::string,float> grid_mean_dict; for (const auto& pair : part_grid_dictionary) { grid_mean_dict.insert({pair.first, pair.second.mean()}); } // Then assign grid addresses to particles for (int i = 0; i < numParts; i++) { part[i].pmf = new BaseGrid*[part[i].numPartGridFiles]; part[i].pmf_scale = new float[part[i].numPartGridFiles]; part[i].meanPmf = new float[part[i].numPartGridFiles]; for(int j = 0; j < part[i].numPartGridFiles; ++j) { part[i].pmf[j] = &(part_grid_dictionary.find( std::string(partGridFile[i][j]) )->second); part[i].pmf_scale[j] = partGridFileScale[i][j]; part[i].meanPmf[j] = grid_mean_dict.find( std::string(partGridFile[i][j]) )->second * part[i].pmf_scale[j]; } if (partForceXGridFile[i].length() != 0) { part[i].forceXGrid = new BaseGrid(partForceXGridFile[i].val()); if (partForceGridScale[i] != nullptr) part[i].forceXGrid->scale( partForceGridScale[i][0] ); printf("Loaded `%s'.\n", partForceXGridFile[i].val()); printf("Grid size %s.\n", part[i].forceXGrid->getExtent().toString().val()); } if (partForceYGridFile[i].length() != 0) { part[i].forceYGrid = new BaseGrid(partForceYGridFile[i].val()); if (partForceGridScale[i] != nullptr) part[i].forceYGrid->scale( partForceGridScale[i][1] ); printf("Loaded `%s'.\n", partForceYGridFile[i].val()); printf("Grid size %s.\n", part[i].forceYGrid->getExtent().toString().val()); } if (partForceZGridFile[i].length() != 0) { part[i].forceZGrid = new BaseGrid(partForceZGridFile[i].val()); printf("Loaded `%s'.\n", partForceZGridFile[i].val()); printf("Grid size %s.\n", part[i].forceZGrid->getExtent().toString().val()); if (partForceGridScale[i] != nullptr) { printf("Scaling forceGridZ `%s' by %f.\n", partForceZGridFile[i].val(), partForceGridScale[i][2] ); part[i].forceZGrid->scale( partForceGridScale[i][2] ); } } if (partDiffusionGridFile[i].length() != 0) { part[i].diffusionGrid = new BaseGrid(partDiffusionGridFile[i].val()); printf("Loaded `%s'.\n", partDiffusionGridFile[i].val()); printf("Grid size %s.\n", part[i].diffusionGrid->getExtent().toString().val()); } if (temperatureGridFile.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 if (size.length2() > 0) { // use size if it's defined if (basis1.length2() > 0 || basis2.length2() > 0 || basis3.length2() > 0) printf("WARNING: both 'size' and 'basis' were specified... using 'size'\n"); basis1 = Vector3(size.x,0,0); basis2 = Vector3(0,size.y,0); basis3 = Vector3(0,0,size.z); } if (basis1.length2() > 0 && basis2.length2() > 0 && basis3.length2() > 0) { sys = new BaseGrid( Matrix3(basis1,basis2,basis3), origin, 1, 1, 1 ); } else { // TODO: use largest system in x,y,z sys = *part[0].pmf; } sysDim = sys->getExtent(); // 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]; /* } */ /* printf("Initial RigidBodies: %d\n", numRB); */ // 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) { Exclude* tempExcludes = excludes; excludes = new Exclude[numExcludes]; for (int i = 0; i < oldNumExcludes; i++) excludes[i] = tempExcludes[i]; delete [] tempExcludes; } for (int i = oldNumExcludes; i < numExcludes; i++) excludes[i] = newExcludes[i - oldNumExcludes]; printf("Built %d exclusions.\n",numExcludes); } { // Add exclusions for RB attached particles std::vector<Exclude> ex; int start = num; for (int i = 0; i < numRigidTypes; i++) { // Loop over RB types RigidBodyType &rbt = rigidBody[i]; const int nap = rbt.num_attached_particles(); for (int j = 0; j < rbt.num; ++j) { // Loop over RBs for (int ai = 0; ai < nap-1; ++ai) { for (int aj = ai+1; aj < nap; ++aj) { ex.push_back( Exclude( ai+start, aj+start ) ); } } start += nap; } } // copy int oldNumExcludes = numExcludes; numExcludes = numExcludes + ex.size(); if (excludes == NULL) { excludes = new Exclude[numExcludes]; } else if (numExcludes >= excludeCapacity) { Exclude* tempExcludes = excludes; excludes = new Exclude[numExcludes]; for (int i = 0; i < oldNumExcludes; i++) excludes[i] = tempExcludes[i]; delete [] tempExcludes; } for (int i = oldNumExcludes; i < numExcludes; i++) excludes[i] = ex[i - oldNumExcludes]; } printf("Built %d exclusions.\n",numExcludes); buildExcludeMap(); // Count number of particles of each type numPartsOfType = new int[numParts]; for (int i = 0; i < numParts; ++i) { numPartsOfType[i] = 0; } for (int i = 0; i < num+num_rb_attached_particles; ++i) { ++numPartsOfType[type[i]]; } // 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) { 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"); } else { // Set the particle types. // Load coordinates from a file? if (numPartsFromFile > 0) { 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; 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; //Han-Yi Chou if (ParticleDynamicType == String("Langevin") || ParticleDynamicType == String("NoseHooverLangevin")) delete[] momentum; delete[] posLast; //Han-Yi Chou if (ParticleDynamicType == String("Langevin") || ParticleDynamicType == String("NoseHooverLangevin")) delete[] momLast; delete[] type; delete[] name; // Particle parameters delete[] part; //delete[] partGridFile; //delete[] partGridFileScale; for(int i = 0; i < numParts; ++i) { if(partGridFile[i] != NULL) { delete[] partGridFile[i]; partGridFile[i] = NULL; } if(partGridFileScale[i] != NULL) { delete[] partGridFileScale[i]; partGridFileScale[i] = NULL; } } delete [] partGridFile; delete [] partGridFileScale; //delete numPartGridFiles; delete[] partForceXGridFile; delete[] partForceYGridFile; delete[] partForceZGridFile; delete[] partDiffusionGridFile; delete[] partReservoirFile; partRigidBodyGrid.clear(); // TODO: plug memory leaks 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; if (bondAngles != NULL) delete[] bondAngles; if (productPotentials != NULL) delete[] productPotentials; delete[] numPartsOfType; // Table parameters delete[] partTableFile; delete[] partTableIndex0; delete[] partTableIndex1; delete[] bondTableFile; delete[] angleTableFile; delete[] dihedralTableFile; //if (type_d != NULL) { //gpuErrchk(cudaFree(type_d)); 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)); //} } void Configuration::copyToCUDA() { printf("Copying particle grids to GPU %d\n", GPUManager::current()); for (const auto& pair : part_grid_dictionary) { // Copy PMF const BaseGrid& g = pair.second; BaseGrid *g_d = g.copy_to_cuda(); part_grid_dictionary_d.insert({pair.first, g_d}); // printf("Assigning grid for %s to %p (originally %p)\n", pair.first.c_str(), (void *) part_grid_dictionary_d[pair.first], (void *) g_d); } printf("Copying particle data to GPU %d\n", GPUManager::current()); BrownianParticleType **part_addr = new BrownianParticleType*[numParts]; // 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++) { BrownianParticleType *b = new BrownianParticleType(part[i]); // Copy PMF pointers if (part[i].pmf != NULL) { { BaseGrid** tmp_d = new BaseGrid*[part[i].numPartGridFiles]; BaseGrid** tmp = new BaseGrid*[part[i].numPartGridFiles]; for(int j = 0; j < part[i].numPartGridFiles; ++j) { // printf("Retrieving grid for %s (at %p)\n", partGridFile[i][j].val(), (void *) part_grid_dictionary_d[std::string(partGridFile[i][j])]); tmp[j] = part_grid_dictionary_d[std::string(partGridFile[i][j])]; } gpuErrchk(cudaMalloc(&tmp_d, sizeof(BaseGrid*)*part[i].numPartGridFiles)); gpuErrchk(cudaMemcpy(tmp_d, tmp, sizeof(BaseGrid*)*part[i].numPartGridFiles, cudaMemcpyHostToDevice)); b->pmf = tmp_d; } { float *tmp; gpuErrchk(cudaMalloc(&tmp, sizeof(float)*part[i].numPartGridFiles)); gpuErrchk(cudaMemcpy(tmp, part[i].pmf_scale, sizeof(float)*part[i].numPartGridFiles, cudaMemcpyHostToDevice)); b->pmf_scale = tmp; } { float *tmp; gpuErrchk(cudaMalloc(&tmp, sizeof(float)*part[i].numPartGridFiles)); gpuErrchk(cudaMemcpy(tmp, part[i].meanPmf, sizeof(float)*part[i].numPartGridFiles, cudaMemcpyHostToDevice)); b->meanPmf = tmp; } { BoundaryCondition *tmp; size_t s = sizeof(BoundaryCondition)*part[i].numPartGridFiles; gpuErrchk(cudaMalloc(&tmp, s)); gpuErrchk(cudaMemcpy(tmp, part[i].pmf_boundary_conditions, s, cudaMemcpyHostToDevice)); b->pmf_boundary_conditions = tmp; } } // Copy the diffusion grid if (part[i].diffusionGrid != NULL) { b->diffusionGrid = part[i].diffusionGrid->copy_to_cuda(); } else { b->diffusionGrid = NULL; } // Copy the diffusion grid if (part[i].forceXGrid != nullptr) { b->forceXGrid = part[i].forceXGrid->copy_to_cuda(); } if (part[i].forceYGrid != nullptr) { b->forceYGrid = part[i].forceYGrid->copy_to_cuda(); } if (part[i].forceZGrid != nullptr) { b->forceZGrid = part[i].forceZGrid->copy_to_cuda(); } //b->pmf = pmf; 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)); // kTGrid_d kTGrid_d = NULL; if (temperatureGridFile.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_rb_attached_particles) * num * simNum, cudaMemcpyHostToDevice)); 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)); }*/ gpuErrchk(cudaDeviceSynchronize()); } void Configuration::setDefaults() { // System parameters outputName = "out"; timestep = 1e-5f; rigidBodyGridGridPeriod = 1; steps = 100; unsigned long int r0 = clock(); for (int i = 0; i < 4; i++) r0 *= r0 + 1; seed = time(NULL) + r0; origin = Vector3(0,0,0); size = Vector3(0,0,0); basis1 = Vector3(0,0,0); basis2 = Vector3(0,0,0); basis3 = Vector3(0,0,0); inputCoordinates = ""; restartCoordinates = ""; //Han-Yi Chou inputMomentum = ""; restartMomentum = ""; copyReplicaCoordinates = 1; numberFluct = 0; numberFluctPeriod = 200; interparticleForce = 1; tabulatedPotential = 0; fullLongRange = 0; // kTGridFile = ""; // Commented out for an unknown reason temperature = 295.0f; temperatureGridFile = ""; coulombConst = 566.440698f/92.0f; electricField = 0.0f; cutoff = 10.0f; switchLen = 2.0f; pairlistDistance = 2.0f; imdForceScale = 1.0f; outputPeriod = 200; outputEnergyPeriod = -1; outputFormat = TrajectoryWriter::formatDcd; currentSegmentZ = -1.0f; numCap = 0; decompPeriod = 10; readPartsFromFile = 0; numPartsFromFile = 0; partsFromFile = NULL; readBondsFromFile = false; numGroupSites = 0; readGroupSitesFromFile = 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; readBondAnglesFromFile = false; numBondAngles = 0; bondAngles = NULL; readProductPotentialsFromFile = false; numProductPotentials = 0; productPotentials = NULL; simple_potential_ids = XpotMap(); simple_potentials = std::vector<SimplePotential>(); readRestraintsFromFile = false; numRestraints = 0; restraints = NULL; //Han-Yi Chou default values ParticleDynamicType = String("Brown"); RigidBodyDynamicType = String("Brown"); COM_Velocity = Vector3(0.f,0.f,0.f); ParticleLangevinIntegrator = String("BAOAB"); //The default is BAOAB // Hidden parameters // Might be parameters later numCapFactor = 5; ParticleInterpolationType = 0; RigidBodyInterpolationType = 0; } 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"); // Allocate the particle variables. part = new BrownianParticleType[numParts]; //partGridFile = new String[numParts]; //partGridFileScale = new float[numParts]; partGridFile = new String*[numParts]; //partGridFileScale = new float[numParts]; partGridFileScale = new float*[numParts]; //int numPartGridFiles = new int[numParts]; partForceXGridFile = new String[numParts]; partForceYGridFile = new String[numParts]; partForceZGridFile = new String[numParts]; partForceGridScale = new float*[numParts]; partDiffusionGridFile = new String[numParts]; partReservoirFile = new String[numParts]; partRigidBodyGrid.resize(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]; // Set a default /* for (int i = 0; i < numParts; ++i) { partGridFileScale[i] = 1.0f; }*/ for(int i = 0; i < numParts; ++i) { partGridFile[i] = NULL; partGridFileScale[i] = NULL; partForceGridScale[i] = nullptr; //part[i].numPartGridFiles = -1; } //for(int i = 0; i < numParts; ++i) // cout << part[i].numPartGridFiles << endl; 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 for (int i = 0; i < numParams; i++) { String param = config.getParameter(i); String value = config.getValue(i); // printf("Parsing %s: %s\n", param.val(), value.val()); if (param == String("outputName")) outputName = value; else if (param == String("timestep")) timestep = (float) strtod(value.val(), NULL); else if (param == String("rigidBodyGridGridPeriod")) rigidBodyGridGridPeriod = atoi(value.val()); else if (param == String("steps")) steps = atol(value.val()); else if (param == String("seed")) seed = atoi(value.val()); else if (param == String("origin")) origin = stringToVector3( value ); else if (param == String("systemSize")) size = stringToVector3( value ); else if (param == String("basis1")) basis1 = stringToVector3( value ); else if (param == String("basis2")) basis2 = stringToVector3( value ); else if (param == String("basis3")) basis3 = stringToVector3( value ); else if (param == String("inputCoordinates")) inputCoordinates = value; else if (param == String("restartCoordinates")) restartCoordinates = value; //Han-Yi Chou else if (param == String("inputMomentum")) inputMomentum = value; else if (param == String("restartMomentum")) restartMomentum = value; else if (param == String("copyReplicaCoordinates")) copyReplicaCoordinates = atoi(value.val()); else if (param == String("temperature")) temperature = (float) strtod(value.val(),NULL); else if (param == String("temperatureGrid")) temperatureGridFile = 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("pairlistDistance")) pairlistDistance = (float) strtod(value.val(), NULL); else if (param == String("scaleIMDForce")) imdForceScale = (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()); //Han-Yi Chou else if (param == String("ParticleDynamicType")) ParticleDynamicType = value; else if (param == String("RigidBodyDynamicType")) RigidBodyDynamicType = value; else if (param == String("ParticleLangevinIntegrator")) ParticleLangevinIntegrator = value; else if (param == String("ParticleInterpolationType")) ParticleInterpolationType = atoi(value.val()); else if (param == String("RigidBodyInterpolationType")) RigidBodyInterpolationType = atoi(value.val()); // PARTICLES else if (param == String("particle")) { part[++currPart] = BrownianParticleType(value); currPartClass = partClassPart; } else if (param == String("mu")) { // for Nose-Hoover Langevin if (currPart < 0) exit(1); part[currPart].mu = (float) strtod(value.val(), NULL); } else if (param == String("forceXGridFile")) { if (currPart < 0) exit(1); partForceXGridFile[currPart] = value; } else if (param == String("forceYGridFile")) { if (currPart < 0) exit(1); partForceYGridFile[currPart] = value; } else if (param == String("forceZGridFile")) { if (currPart < 0) exit(1); partForceZGridFile[currPart] = value; } else if (param == String("forceGridScale")) { if (currPart < 0) exit(1); int tmp; stringToArray<float>(&value, tmp, &partForceGridScale[currPart]); if (tmp != 3) { printf("ERROR: Expected three floating point scale values for x,y,z, but got `%s'.\n", param.val()); exit(1); } } else if (param == String("diffusionGridFile")) { if (currPart < 0) exit(1); partDiffusionGridFile[currPart] = value; } else if (param == String("diffusion")) { if (currPart < 0) exit(1); part[currPart].diffusion = (float) strtod(value.val(), NULL); } else if (param == String("charge")) { if (currPart < 0) exit(1); part[currPart].charge = (float) strtod(value.val(), NULL); } else if (param == String("radius")) { if (currPart < 0) exit(1); part[currPart].radius = (float) strtod(value.val(), NULL); } else if (param == String("eps")) { if (currPart < 0) exit(1); part[currPart].eps = (float) strtod(value.val(), NULL); } else if (param == String("reservoirFile")) { if (currPart < 0) exit(1); 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[j] = temp[j]; delete[] temp; } if (readBondFile(value, ++currBond)) numTabBondFiles++; } else if (param == String("inputParticles")) { if (readPartsFromFile) { printf("WARNING: More than one particle file specified. Ignoring new file.\n"); } else { partFile = value; readPartsFromFile = true; loadedCoordinates = true; } } else if (param == String("inputGroups")) { if (readGroupSitesFromFile) { printf("WARNING: More than one group file specified. Ignoring new file.\n"); } else { groupSiteFile = value; readGroupSitesFromFile = true; } } else if (param == String("inputBonds")) { if (readBondsFromFile) { printf("WARNING: More than one bond file specified. Ignoring new bond file.\n"); } else { bondFile = value; readBondsFromFile = true; } } else if (param == String("inputExcludes")) { if (readExcludesFromFile) { printf("WARNING: More than one exclude file specified. Ignoring new exclude file.\n"); } else { printf("inputExclude %s\n", value.val()); 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. Ignoring new angle file.\n"); } else { angleFile = value; readAnglesFromFile = true; } } else if (param == String("inputBondAngles")) { if (readBondAnglesFromFile) { printf("WARNING: More than one bondangle file specified. Ignoring new bondangle file.\n"); } else { bondAngleFile = value; readBondAnglesFromFile = true; } } else if (param == String("inputProductPotentials")) { if (readBondAnglesFromFile) { printf("WARNING: More than one product potential file specified. Ignoring new file.\n"); } else { productPotentialFile = value; readProductPotentialsFromFile = 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[j] = temp[j]; delete[] temp; } if (readAngleFile(value, ++currAngle)) numTabAngleFiles++; } else if (param == String("inputDihedrals")) { if (readDihedralsFromFile) { printf("WARNING: More than one dihedral file specified. Ignoring 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[j] = temp[j]; delete[] temp; } if (readDihedralFile(value, ++currDihedral)) numTabDihedralFiles++; } else if (param == String("inputRestraints")) { if (readRestraintsFromFile) { printf("WARNING: More than one restraint file specified. Ignoring new restraint file.\n"); } else { restraintFile = value; readRestraintsFromFile = true; } } else if (param == String("gridFileScale")) { if (currPart < 0) exit(1); //partGridFileScale[currPart] = (float) strtod(value.val(), NULL); stringToArray<float>(&value, part[currPart].numPartGridFiles, &partGridFileScale[currPart]); } else if (param == String("gridFileBoundaryConditions")) { if (currPart < 0) exit(1); register size_t num = value.tokenCount(); if (num > 0) { String *tokens = new String[num]; BoundaryCondition *data = new BoundaryCondition[num]; value.tokenize(tokens); for(size_t i = 0; i < num; ++i) { tokens[i].lower(); if (tokens[i] == "dirichlet") data[i] = dirichlet; else if (tokens[i] == "neumann") data[i] = neumann; else if (tokens[i] == "periodic") data[i] = periodic; else { fprintf(stderr,"WARNING: Unrecognized gridFile boundary condition \"%s\". Using Dirichlet.\n", tokens[i].val() ); data[i] = dirichlet; } } delete[] tokens; part[currPart].set_boundary_conditions(num, data); delete[] data; } } else if (param == String("rigidBodyPotential")) { if (currPart < 0) exit(1); partRigidBodyGrid[currPart].push_back(value); } //Han-Yi Chou initial COM velocity for total particles else if (param == String("COM_Velocity")) COM_Velocity = stringToVector3(value); // RIGID BODY else if (param == String("rigidBody")) { // part[++currPart] = BrownianParticleType(value); rigidBody[++currRB] = RigidBodyType(value, this); currPartClass = partClassRB; } else if (param == String("inertia")) { if (currRB < 0) exit(1); rigidBody[currRB].inertia = stringToVector3( value ); } else if (param == String("rotDamping")) { if (currRB < 0) exit(1); rigidBody[currRB].rotDamping = stringToVector3( value ); } else if (param == String("attachedParticles")) { rigidBody[currRB].append_attached_particle_file(value); } else if (param == String("densityGrid")) { if (currRB < 0) exit(1); rigidBody[currRB].addDensityGrid(value); } else if (param == String("potentialGrid")) { if (currRB < 0) exit(1); rigidBody[currRB].addPotentialGrid(value); } else if (param == String("densityGridScale")) { if (currRB < 0) exit(1); rigidBody[currRB].scaleDensityGrid(value); } else if (param == String("potentialGridScale")) { if (currRB < 0) exit(1); rigidBody[currRB].scalePotentialGrid(value); } else if (param == String("pmfScale")) { if (currRB < 0) exit(1); rigidBody[currRB].scalePMF(value); } else if (param == String("position")) { if (currRB < 0) exit(1); rigidBody[currRB].initPos = stringToVector3( value ); } else if (param == String("orientation")) { if (currRB < 0) exit(1); rigidBody[currRB].initRot = stringToMatrix3( value ); } else if (param == String("momentum")) { rigidBody[currRB].initMomentum = stringToVector3(value); } else if (param == String("angularMomentum")) { if (currRB < 0) exit(1); rigidBody[currRB].initAngularMomentum = stringToVector3(value); } else if (param == String("inputRBCoordinates")) inputRBCoordinates = value; else if (param == String("restartRBCoordinates")) restartRBCoordinates = value; // COMMON else if (param == String("num")) { if (currPartClass == partClassPart) { if (currPart < 0) exit(1); part[currPart].num = atoi(value.val()); } else if (currPartClass == partClassRB) { if (currRB < 0) exit(1); rigidBody[currRB].num = atoi(value.val()); } } //set mass here Han-Yi Chou else if (param == String("mass")) { if (currPartClass == partClassPart) { if (currPart < 0) exit(1); part[currPart].mass = (float) strtod(value.val(),NULL); } else if (currPartClass == partClassRB) { if (currRB < 0) exit(1); rigidBody[currRB].mass = (float) strtod(value.val(),NULL); } } //set damping here, using anisotropic damping, i.e. data type Vector3 Han-Yi Chou else if (param == String("transDamping")) { if (currPartClass == partClassPart) { if (currPart < 0) exit(1); part[currPart].transDamping = stringToVector3(value); } else if (currPartClass == partClassRB) { if (currRB < 0) exit(1); rigidBody[currRB].transDamping = stringToVector3(value); } } else if (param == String("gridFile")) { if (currPartClass == partClassPart) { if (currPart < 0) exit(1); printf("Applying grid file '%s'\n", value.val()); stringToArray<String>(&value, part[currPart].numPartGridFiles, &partGridFile[currPart]); const int& num = part[currPart].numPartGridFiles; partGridFileScale[currPart] = new float[num]; for(int i = 0; i < num; ++i) { // printf("%s ", partGridFile[currPart]->val()); partGridFileScale[currPart][i] = 1.0f; } // Set default boundary conditions for grids BoundaryCondition *bc = part[currPart].pmf_boundary_conditions; if (bc == NULL) { bc = new BoundaryCondition[num]; for(int i = 0; i < num; ++i) { bc[i] = dirichlet; } part[currPart].pmf_boundary_conditions = bc; } } else if (currPartClass == partClassRB) { if (currRB < 0) exit(1); rigidBody[currRB].addPMF(value); } } // UNKNOWN else { printf("ERROR: Unrecognized keyword `%s'.\n", param.val()); exit(1); } } // extra configuration for RB types for (int i = 0; i < numRigidTypes; i++) rigidBody[i].setDampingCoeffs(timestep); //For debugging purpose Han-Yi Chou //Print(); return numParams; } //Han-Yi Chou void Configuration::Print() { printf("The dynamic type for particle is %s \n", ParticleDynamicType.val()); for(int i = 0; i < numParts; ++i) { printf("The type %d has mass %f \n", i,part[i].mass); printf("The diffusion coefficient is %f \n", part[i].diffusion); printf("The translational damping is %f %f %f \n", part[i].transDamping.x, part[i].transDamping.y, part[i].transDamping.z); } printf("Done with check for Langevin"); //assert(1==2); } void Configuration::PrintMomentum() { for(int i = 0; i < num; ++i) { printf("%f %f %f\n", momentum[i].x, momentum[i].y, momentum[i].z); } //assert(1==2); } 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; } 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; // assert(false); // TODO probably relax constraint that particle must be found; could just be in RB 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 (ParticleDynamicType == String("Langevin") || ParticleDynamicType == String("NoseHooverLangevin")) { if (numTokens != 9) { printf("Error: Invalid particle file line: %s\n", line); exit(-1); } } else { if (numTokens != 6) { printf("Error: Invalid particle file line: %s\n", line); exit(-1); } } // 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::readGroups() { // Open the file const size_t line_char = 16384; FILE* inp = fopen(groupSiteFile.val(), "r"); char line[line_char]; // If the particle file cannot be found, exit the program if (inp == NULL) { printf("ERROR: Could not open `%s'.\n", partFile.val()); exit(1); } // Our particle array has a starting capacity of 256 // We will expand this later if we need to. // int capacity = 256; numGroupSites = 0; // partsFromFile = new String[capacity]; // indices = new int[capacity]; // indices[0] = 0; // Get and process all lines of input while (fgets(line, line_char, 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 GROUP input lines have at least 3 tokens: // GROUP | Atom_1_idx | Atom_2_idx | ... // A line without exactly six tokens should be discarded. if (numTokens < 3) { printf("Error: Invalid group file line: %s\n", line); exit(-1); } // Make sure the index of this particle is unique. // NOTE: The particle list is sorted by index. std::vector<int> tmp; for (int i=1; i < numTokens; ++i) { const int ai = atoi(tokenList[i].val()); if (ai >= num+num_rb_attached_particles) { printf("Error: Attempted to include invalid particle in group: %s\n", line); exit(-1); } else if (ai >= num) { printf("WARNING: including RB particles in group with line: %s\n", line); } tmp.push_back( ai ); } groupSiteData.push_back(tmp); numGroupSites++; } } 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; } if (ind1 < 0 || ind1 >= num+num_rb_attached_particles+numGroupSites || ind2 < 0 || ind2 >= num+num_rb_attached_particles+numGroupSites) { printf("ERROR: Bond file line '%s' includes invalid index\n", line); exit(1); } // 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 // 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 == "REPLACE") addExclusion(ind1, ind2); 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+num_rb_attached_particles+numGroupSites]; for (int i = 0; i < num+num_rb_attached_particles+numGroupSites; i++) { 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; } // 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()); addExclusion(ind1, ind2); delete[] tokenList; } } void Configuration::addExclusion(int ind1, int ind2) { if (ind1 >= num+num_rb_attached_particles || ind2 >= num+num_rb_attached_particles) { printf("WARNING: Attempted to add an exclusion for an out-of-range particle index (%d or %d >= %d).\n", ind1, ind2, num+num_rb_attached_particles); return; } // 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 ex1(ind1, ind2); excludes[numExcludes++] = ex1; Exclude ex2(ind2, ind1); excludes[numExcludes++] = ex2; } void Configuration::buildExcludeMap() { // 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+num_rb_attached_particles]; for (int i = 0; i < num+num_rb_attached_particles; i++) { 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; assert(currPart < num+num_rb_attached_particles); excludeMap[currPart].x = i; if (lastPart >= 0) excludeMap[lastPart].y = i; lastPart = currPart; } } if (excludeMap[lastPart].x > 0) excludeMap[lastPart].y = numExcludes; } 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+num_rb_attached_particles+numGroupSites or ind2 >= num+num_rb_attached_particles+numGroupSites or ind3 >= num+num_rb_attached_particles+numGroupSites) 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(); } 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+num_rb_attached_particles+numGroupSites or ind2 >= num+num_rb_attached_particles+numGroupSites or ind3 >= num+num_rb_attached_particles+numGroupSites or ind4 >= num+num_rb_attached_particles+numGroupSites) 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(); } void Configuration::readBondAngles() { FILE* inp = fopen(bondAngleFile.val(), "r"); char line[256]; int capacity = 256; numBondAngles = 0; bondAngles = new BondAngle[capacity]; // If the angle file cannot be found, exit the program if (inp == NULL) { printf("WARNING: Could not open `%s'.\n", bondAngleFile.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 BONDANGLE inputs have 8 tokens // BONDANGLE | INDEX1 | INDEX2 | INDEX3 | INDEX4 | ANGLE_FILENAME | BOND_FILENAME1 | BOND_FILENAME2 if (numTokens != 8) { printf("WARNING: Invalid bond_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()); int ind4 = atoi(tokenList[4].val()); String file_name1 = tokenList[5]; String file_name2 = tokenList[6]; String file_name3 = tokenList[7]; //printf("file_name %s\n", file_name.val()); if (ind1 >= num or ind2 >= num or ind3 >= num or ind4 >= num) continue; if (numBondAngles >= capacity) { BondAngle* temp = bondAngles; capacity *= 2; bondAngles = new BondAngle[capacity]; for (int i = 0; i < numBondAngles; i++) bondAngles[i] = temp[i]; delete[] temp; } BondAngle a(ind1, ind2, ind3, ind4, file_name1, file_name2, file_name3); bondAngles[numBondAngles++] = a; delete[] tokenList; } std::sort(bondAngles, bondAngles + numBondAngles, compare()); // for(int i = 0; i < numAngles; i++) // angles[i].print(); } void Configuration::readProductPotentials() { FILE* inp = fopen(productPotentialFile.val(), "r"); char line[256]; int capacity = 256; numProductPotentials = 0; productPotentials = new ProductPotentialConf[capacity]; // If the angle file cannot be found, exit the program if (inp == NULL) { printf("WARNING: Could not open `%s'.\n", productPotentialFile.val()); printf("This simulation will not use product potentials.\n"); return; } printf("DEBUG: READING PRODUCT POTENTAL FILE\n"); std::vector<std::vector<int>> indices; std::vector<int> tmp; std::vector<String> pot_names; while(fgets(line, 256, inp)) { if (line[0] == '#') continue; String s(line); int numTokens = s.tokenCount(); String* tokenList = new String[numTokens]; s.tokenize(tokenList); indices.clear(); tmp.clear(); pot_names.clear(); printf("\rDEBUG: reading line %d",numProductPotentials+1); // Legitimate ProductPotential inputs have at least 7 tokens // BONDANGLE | INDEX1 | INDEX2 | INDEX3 | [TYPE1] | POT_FILENAME1 | INDEX4 | INDEX5 | [TYPE2] POT_FILENAME2 ... if (numTokens < 5) { printf("WARNING: Invalid product potential input line (too few tokens %d): %s\n", numTokens, line); continue; } // Discard any empty line if (tokenList == NULL) continue; SimplePotentialType type = BOND; // initialize to suppress warning bool type_specified = false; for (int i = 1; i < numTokens; ++i) { char *end; // printf("DEBUG: Working on token %d '%s'\n", i, tokenList[i].val()); // Try to convert token to integer int index = (int) strtol(tokenList[i].val(), &end, 10); if (tokenList[i].val() == end || *end != '\0' || errno == ERANGE) { // Failed to convert token to integer; therefore it must be a potential name or type // Try to match a type String n = tokenList[i]; n.lower(); if (n == "bond") { type = ΒΟΝD; type_specified = true; } else if (n == "angle") { type = ANGLE; type_specified = true; } else if (n == "dihedral") { type = DIHEDRAL; type_specified = true; } else if (n == "vecangle") { type = VECANGLE; type_specified = true; } else { // Not a type, therefore a path to a potential n = tokenList[i]; indices.push_back(tmp); pot_names.push_back( n ); // TODO: Key should be tuple of (type,n) std::string n_str = std::string(n.val()); if ( simple_potential_ids.find(n_str) == simple_potential_ids.end() ) { // Could not find fileName in dictionary, so read and add it unsigned int s = tmp.size(); if (s < 2 || s > 4) { printf("WARNING: Invalid product potential input line (indices of potential %d == %d): %s\n", i, s, line); continue; } simple_potential_ids[ n_str ] = simple_potentials.size(); if (not type_specified) type = s==2? BOND: s==3? ANGLE: DIHEDRAL; simple_potentials.push_back( SimplePotential(n.val(), type) ); } tmp.clear(); type_specified = false; } } else { if (index >= num) { continue; } tmp.push_back(index); } } if (numProductPotentials >= capacity) { ProductPotentialConf* temp = productPotentials; capacity *= 2; productPotentials = new ProductPotentialConf[capacity]; for (int i = 0; i < numProductPotentials; i++) productPotentials[i] = temp[i]; delete[] temp; } ProductPotentialConf a(indices, pot_names); productPotentials[numProductPotentials++] = a; delete[] tokenList; } printf("\nDEBUG: Sorting\n"); std::sort(productPotentials, productPotentials + numProductPotentials, compare()); // for(int i = 0; i < numAngles; i++) // angles[i].print(); } void Configuration::readRestraints() { FILE* inp = fopen(restraintFile.val(), "r"); char line[256]; int capacity = 16; numRestraints = 0; restraints = new Restraint[capacity]; // If the restraint file cannot be found, exit the program if (inp == NULL) { printf("WARNING: Could not open `%s'.\n", restraintFile.val()); printf(" This simulation will not use restraints.\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); // inputs have 6 tokens // RESTRAINT | INDEX1 | k | x0 | y0 | z0 if (numTokens != 6) { printf("WARNING: Invalid restraint input line: %s\n", line); continue; } // Discard any empty line if (tokenList == NULL) continue; int id = atoi(tokenList[1].val()); float k = (float) strtod(tokenList[2].val(), NULL); float x0 = (float) strtod(tokenList[3].val(), NULL); float y0 = (float) strtod(tokenList[4].val(), NULL); float z0 = (float) strtod(tokenList[5].val(), NULL); if (id >= num + num_rb_attached_particles + numGroupSites) continue; if (numRestraints >= capacity) { Restraint* temp = restraints; capacity *= 2; restraints = new Restraint[capacity]; for (int i = 0; i < numRestraints; ++i) restraints[i] = temp[i]; delete[] temp; } Restraint tmp(id, Vector3(x0,y0,z0), k); restraints[numRestraints++] = tmp; delete[] tokenList; } // std::sort(restraints, restraints + numRestraints, compare()); } //populate the type list and serial list void Configuration::populate() { for (int repID = 0; repID < simNum; ++repID) { const int offset = repID * (num+num_rb_attached_particles); int pn = 0; int p = 0; for (int i = 0; i < num; ++i) { type[i + offset] = p; serial[i + offset] = 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() ); 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() ); 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() ); return true; } //Load the restart coordiantes only 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); } //Han-Yi Chou //First the resart coordinates should be loaded void Configuration::loadRestartMomentum(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); } if(!loadedCoordinates) { printf("First load the restart coordinates\n"); assert(1==2); } 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 momentum file line: %s\n", line); fclose(inp); exit(-1); } String* tokenList = new String[numTokens]; s.tokenize(tokenList); if (tokenList == NULL) { printf("GrandBrownTown:loadRestart Invalid momentum 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); if (typ < 0 || typ >= numParts) { printf("GrandBrownTown:countRestart Invalid particle type : %d\n", typ); fclose(inp); exit(-1); } if(typ != type[count]) { printf("Inconsistent in momentum file with the position file\n"); fclose(inp); exit(-1); } momentum[count] = Vector3(x,y,z); ++count; delete[] tokenList; } fclose(inp); } bool Configuration::loadCoordinates(const char* file_name) { char line[STRLEN]; FILE* inp = fopen(file_name, "r"); if (inp == NULL) { printf("ERROR: Could not open file for reading: %s\n", file_name); exit(-1); 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*simNum) { 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; } //Han-Yi Chou The function populate should be called before entering this function bool Configuration::loadMomentum(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 momentum file line: %s\n", line); fclose(inp); return false; } String* tokenList = new String[numTokens]; s.tokenize(tokenList); if (tokenList == NULL) { printf("ERROR: Invalid momentum file line: %s\n", line); fclose(inp); return false; } if (count >= num) { printf("WARNING: Too many momentum in momentum file %s.\n", file_name); fclose(inp); return false; } float x = (float) strtod(tokenList[0],NULL); float y = (float) strtod(tokenList[1],NULL); float z = (float) strtod(tokenList[2],NULL); momentum[count] = Vector3(x,y,z); ++count; delete[] tokenList; } fclose(inp); if (count < num) { printf("ERROR: Too few momentum in momentum 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; } if (currTab >= numParts*numParts) { printf("ERROR: Number of tabulatedFile entries exceeded %d*%d particle types.\n", numParts,numParts); exit(1); } 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() ); 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"); } //Han-Yi Chou setting boltzman distribution of momentum with a given center of mass velocity //Before using this code, make sure the array type list and serial list are both already initialized bool Configuration::Boltzmann(const Vector3& v_com, int N) { int count = 0; Vector3 total_momentum = Vector3(0.); RandomCPU random = RandomCPU(seed + 2); /* +2 to avoid using same seed elsewhere */ for(int i = 0; i < N; ++i) { int typ = type[i]; double M = part[typ].mass; double sigma = sqrt(kT * M) * 2.046167337e4; Vector3 tmp = random.gaussian_vector() * sigma; tmp = tmp * 1e-4; total_momentum += tmp; momentum[(size_t)count] = tmp; ++count; } if(N > 1) { total_momentum = total_momentum / (double)N; for(int i = 0; i < N; ++i) { int typ = type[i]; double M = part[typ].mass; momentum[i] = momentum[i] - total_momentum + M * v_com; } } return true; } ////////////////////////// // 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; } bool Configuration::compare::operator()(const BondAngle& lhs, const BondAngle& 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; } bool Configuration::compare::operator()(const ProductPotentialConf& lhs, const ProductPotentialConf& rhs) { int diff = rhs.indices.size() - lhs.indices.size(); if (diff != 0) return diff > 0; for (unsigned int i = 0; i < lhs.indices.size(); ++i) { diff = rhs.indices[i].size() - lhs.indices[i].size(); if (diff != 0) return diff > 0; } for (unsigned int i = 0; i < lhs.indices.size(); ++i) { for (unsigned int j = 0; j < lhs.indices[i].size(); ++j) { diff = rhs.indices[i][j] - lhs.indices[i][j]; if (diff != 0) return diff > 0; } } return true; }