#include #include #include #include #include #include "NanoCreator.h" // ---------------------------------- F U N C T I O N S ---------------------------------------------- // ================================= File functions ============================== #define LINE_SIZE 80 #define NDIM 3 /** Allocs memory and prints a message on fail. * \param *size size of alloc in bytes * \param *msg error msg * \return pointer to allocated memory */ void * Malloc (size_t size, const char *msg) { void *ptr = malloc(size); if (ptr == NULL) { if (msg == NULL) fprintf(stdout, "ERROR: Malloc\n"); else fprintf(stdout, "ERROR: Malloc - %s\n", msg); return NULL; } else { return ptr; } } /** Callocs memory and prints a message on fail. * \param *size size of alloc in bytes * \param *value pointer to initial value * \param *msg error msg * \return pointer to allocated memory */ void * Calloc (size_t size, double value, const char *msg) { void *ptr = calloc(size, value); if (ptr == NULL) { if (msg == NULL) fprintf(stdout, "ERROR: Calloc\n"); else fprintf(stdout, "ERROR: Calloc - %s\n", msg); return NULL; } else { return ptr; } } /** Frees memory only if ptr != NULL. * \param *ptr pointer to array * \param *msg */ void Free(void * ptr, const char *msg) { if (ptr != NULL) free(ptr); else { if (msg == NULL) fprintf(stdout, "ERROR: Free\n"); else fprintf(stdout, "ERROR: Free - %s\n", msg); } } /** Allocs memory and prints a message on fail. * \param **old_ptr pointer to old memory range * \param *newsize new size of alloc in bytes * \param *msg error msg * \return pointer to allocated memory */ void * Realloc (void *old_ptr, size_t newsize, const char *msg) { if (old_ptr == NULL) { fprintf(stdout, "ERROR: Realloc - old_ptr NULL\n"); exit(255); } void *ptr = realloc(old_ptr, newsize); if (ptr == NULL) { if (msg == NULL) fprintf(stdout, "ERROR: Realloc\n"); else fprintf(stdout, "ERROR: Realloc - %s\n", msg); return NULL; } else { return ptr; } } /** Reads a file's contents into a char buffer of appropiate size. * \param *filename name of file * \param pointer to integer holding read/allocated buffer length * \return pointer to allocated segment with contents */ char * ReadBuffer (char *filename, int *bufferlength) { if ((filename == NULL) || (bufferlength == NULL)) { fprintf(stderr, "ERROR: ReadBuffer - ptr to filename or bufferlength NULL\n"); exit(255); } char *buffer = Malloc(sizeof(char)*LINE_SIZE, "ReadBuffer: buffer"); int i = 0, number; FILE *file = fopen(filename, "r"); if (file == NULL) { fprintf(stderr, "File open error: %s", filename); exit(255); } while ((number = fread(&buffer[i], sizeof(char), LINE_SIZE, file)) == LINE_SIZE) { //fprintf(stdout, "%s", &buffer[i]); i+= LINE_SIZE; buffer = (char *) Realloc(buffer, i+LINE_SIZE, "ReadBuffer: buffer"); } fclose(file); fprintf(stdout, "Buffer length is %i\n", i); *bufferlength = i+(number); return buffer; } /** Extracts next line out of a buffer. * \param *buffer buffer to parse for newline * \param *line contains complete line on return * \return length of line, 0 if end of file */ int GetNextline(char *buffer, char *line) { if ((buffer == NULL) || (line == NULL)) { fprintf(stderr, "ERROR: GetNextline - ptr to buffer or line NULL\n"); exit(255); } int length; char *ptr = strchr(buffer, '\n'); //fprintf(stdout, "Newline at %p from %p\n", ptr, buffer); if (ptr == NULL) { // buffer ends return 0; } else { //fprintf(stdout, "length of line is %d\n", length); length = (int)(ptr - buffer)/sizeof(char); strncpy(line, buffer, length); line[length]='\0'; return length+1; } } /** Adds commentary stuff (needed for further stages) to Cell xyz files. * \param *filename file name * \param atomicnumner number of atoms in xyz * \param **Vector list of three unit cell vectors * \param **Recivector list of three reciprocal unit cell vectors * \param atomicnumber number of atoms in cell */ void AddAtomicNumber(char *filename, int atomicnumber, double **Vector, double **Recivector) { if ((filename == NULL) || (Vector == NULL) || (Recivector == NULL)) { fprintf(stdout, "ERROR: AddAtomicNumber - ptr to filename, Vector or Recivector NULL\n"); exit(255); } int bufferlength; char *buffer = ReadBuffer(filename, &bufferlength); FILE *file2 = fopen(filename, "w+"); if (file2 == NULL) { fprintf(stdout, "ERROR: AddAtomicNumber: %s can't open for writing\n", filename); exit(255); } double volume = Determinant(Vector); time_t now; now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time' // open for writing and prepend fprintf(file2,"%d\n", atomicnumber); // 2 fprintf(file2,"\tgenerated with Nanotube creator on %s", ctime(&now)); fwrite(buffer, sizeof(char), bufferlength, file2); // append buffer // Add primitive vectors as comment fprintf(file2,"\n****************************************\n\n"); fprintf(file2,"Primitive vectors\n"); fprintf(file2,"a(1) = %f\t%f\t%f\n", Vector[0][0], Vector[0][1], Vector[0][2]); fprintf(file2,"a(2) = %f\t%f\t%f\n", Vector[1][0], Vector[1][1], Vector[1][2]); fprintf(file2,"a(3) = %f\t%f\t%f\n", Vector[2][0], Vector[2][1], Vector[2][2]); fprintf(file2,"\nVolume = %f", volume); fprintf(file2,"\nReciprocal Vectors\n"); fprintf(file2,"b(1) = %f\t%f\t%f\n", Recivector[0][0], Recivector[0][1], Recivector[0][2]); fprintf(file2,"b(2) = %f\t%f\t%f\n", Recivector[1][0], Recivector[1][1], Recivector[1][2]); fprintf(file2,"b(3) = %f\t%f\t%f\n", Recivector[2][0], Recivector[2][1], Recivector[2][2]); fclose(file2); // close file Free(buffer, "AddAtomicNumber: buffer"); } /** Adds commentary stuff (needed for further stages) to Sheet xyz files. * \param *filename file name * \param *axis array with major, minor and no axis * \param *chiral pointer to array with both chiral values * \param *factors pointer to array with length and radius factor * \param seed random number seed * \param numbercell number of atoms in unit cell, needed as length of \a *randomness * \param *randomness for each atom in unit cell a factor between 0..1, giving its probability of appearance */ void AddSheetInfo(char *filename, int *axis, int *chiral, int *factors, int seed, int numbercell, double *randomness) { int i; if ((filename == NULL) || (axis == NULL) || (chiral == NULL) || (factors == NULL)) { fprintf(stdout, "ERROR: AddSheetInfo - ptr to filename, axis, chiral or factors NULL\n"); exit(255); } // open for writing and append FILE *file2 = fopen(filename,"a"); if (file2 == NULL) { fprintf(stderr, "ERROR: AddSheetInfo - can't open %s for appending\n", filename); exit(255); } // Add primitive vectors as comment fprintf(file2,"\n****************************************\n\n"); fprintf(file2,"Axis %d\t%d\t%d\n", axis[0], axis[1], axis[2]); fprintf(file2,"(n,m) %d\t%d\n", chiral[0], chiral[1]); fprintf(file2,"factors %d\t%d\n", factors[0], factors[1]); fprintf(file2,"seed %d\n", seed); fprintf(file2,"\nRandomness\n"); for (i=0; i MYEPSILON) ? 1 : 0; } else { flag = (fabs(tmp) > MYEPSILON) ? 1 : 0; } } } if (!flag) fprintf(stdout, "ok\n"); else fprintf(stdout, "false\n"); } /** Flips to double numbers in place. * \param *number1 pointer to first double * \param *number2 pointer to second double */ void flip(double *number1, double *number2) { if ((number1 == NULL) || (number2 == NULL)) { fprintf(stderr, "ERROR: flip: ptr to number1 or number2 NULL\n"); exit(255); } double tmp = *number1; *number1 = *number2; *number2 = tmp; } /** Transposes a matrix. * \param **matrix pointer to NDIMxNDIM-matrix array */ void Transpose(double **matrix) { if (matrix == NULL) { fprintf(stderr, "ERROR: Transpose: ptr to matrix NULL\n"); exit(255); } int i,j; for (i=0;i MYEPSILON) { biggest = 0; } else { biggest = 1; } diameter[0] = sqrt(diameter[0]); diameter[1] = sqrt(diameter[1]); fprintf(stdout, "\n\nMajor diameter of the sheet is %5.5f, minor diameter is %5.5f.\n",diameter[biggest],diameter[(biggest+1)%2]); return diameter[biggest]; } /** Determines the center of gravity of atoms in a buffer \a bufptr with given \a number * \param *bufptr pointer to char buffer with atoms in (name x y z)-manner * \param number number of atoms/lines to scan * \return NDIM vector (allocated doubles) pointing back to center of gravity */ double * CenterOfGravity(char *bufptr, int number) { if (bufptr == NULL) { fprintf(stderr, "ERROR: CenterOfGravity - bufptr NULL\n"); exit(255); } double *cog = calloc(sizeof(double)*NDIM, 0.); if (cog == NULL) { fprintf(stderr, "ERROR: CenterOfGravity - cog\n"); exit(255); } double *atom = Malloc(sizeof(double)*NDIM, "CenterOfGravity: atom"); char name[255], line[255]; int i,j; // Determine center of gravity for (i=0;i \n\tWhere specifies a file to start from or a basename\n\t is either None, Cell, Sheet, Tube, Torus and specifies where to start the rolling up from.\n\tNote: The .Aligned. files can't be used (rotation is essential).\n", argv[0]); exit(255); } else { // store variables filename = argv[1]; strncpy(stage, argv[2], 5); fprintf(stdout, "I will begin at stage %s.\n", stage); // build filenames char *ptr = strrchr(filename, '.'); int length = strlen(filename); if (ptr != NULL) { length = ((int)(ptr-filename) >= length-5) ? (int)(ptr-filename) : length; filename[length] = '\0'; // eventueller } fprintf(stdout, "I will use \'%s' as base for the filenames.\n\n", filename); CellFilename = Malloc(sizeof(char)*(length+10), "Main: CellFilename"); SheetFilename = Malloc(sizeof(char)*(length+11), "Main: SheetFilename"); TubeFilename = Malloc(sizeof(char)*(length+10), "Main: TubeFilename"); TorusFilename = Malloc(sizeof(char)*(length+11), "Main: TorusFilename"); SheetFilenameAligned = Malloc(sizeof(char)*(length+20), "Main: SheetFilenameAligned"); TubeFilenameAligned = Malloc(sizeof(char)*(length+19), "Main: TubeFilenameAligned"); sprintf(CellFilename, "%s.Cell.xyz", filename); sprintf(SheetFilename, "%s.Sheet.xyz", filename); sprintf(TubeFilename, "%s.Tube.xyz", filename); sprintf(TorusFilename, "%s.Torus.xyz", filename); sprintf(SheetFilenameAligned, "%s.Sheet.Aligned.xyz", filename); sprintf(TubeFilenameAligned, "%s.Tube.Aligned.xyz", filename); } // Allocating memory Debug ("Allocating memory\n"); atom = (double *) Malloc(sizeof(double)*NDIM, "Main: atom"); Vector = (double **) Malloc(sizeof(double *)*NDIM, "Main: *Vector"); Recivector = (double **) Malloc(sizeof(double *)*NDIM, "Main: *Recivector"); Tubevector = (double **) Malloc(sizeof(double *)*NDIM, "Main: *Tubevector"); TubevectorInverse = (double **) Malloc(sizeof(double *)*NDIM, "Main: *TubevectorInverse"); for (i=0; i MYEPSILON) { tmp = ceil(biggestdiameter/fabs(Vector[i][j])); } else { tmp = 0; } sheetnr[j] = sheetnr[j] > tmp ? sheetnr[j] : tmp; } } fprintf(stdout, "Maximum indices to regard: %d %d %d\n", sheetnr[0], sheetnr[1], sheetnr[2]); for (i=0;i? %lg\n", nr, percentage, randomness[nr]); if (percentage >= randomness[nr]) { // Create coordinates at atom site coord = VectorAdd(atombuffer[nr].x, offset); //fprintf(stdout, "Atom Nr. %i: ", (numbersheet+1)); //PrintVector(stdout, coord); // project down on major and minor Tubevectors and check for length if out of sheet tempvector = MatrixTrafoInverse(coord, TubevectorInverse); if (((tempvector[axis[0]] + MYEPSILON) >= 0) && ((factors[0] - tempvector[axis[0]]) > MYEPSILON) && ((tempvector[axis[1]] + MYEPSILON) >= 0) && ((factors[1] - tempvector[axis[1]]) > MYEPSILON) && ((tempvector[axis[2]] + MYEPSILON) >= 0) && ((factors[2] - tempvector[axis[2]]) > MYEPSILON)) { // check if within rotated cell numbersheet++; //if (nummer >= 2) strcpy(atombuffer[nr].name, "O"); //nummer++; fprintf(SheetFile, "%s\t%5.5lg\t%5.5lg\t%5.5lg\n", atombuffer[nr].name, coord[0], coord[1], coord[2]); // rotate to align the sheet in xy plane x1 = coord[0]*cos(-angle) + coord[1] * sin(-angle); x2 = coord[0]*(-sin(-angle)) + coord[1] * cos(-angle); x3 = coord[2]; fprintf(SheetFileAligned, "%s\t%5.5lg\t%5.5lg\t%5.5lg\n", atombuffer[nr].name, x1, x2, x3); //fprintf(SheetFile, "O\t%5.5lg\t%5.5lg\t%5.5lg\n", coord[0], coord[1], coord[2]); //fprintf(stdout, "%s/%d\t(%lg\t%lg\t%lg)\t", atombuffer[nr].name, numbersheet+1, coord[0], coord[1], coord[2]); //PrintVector(stdout, tempvector); numbersheet++; //fprintf(stdout, "%i,", nr); } //else { //numbersheet++; //fprintf(SheetFile, "B\t%lg\t%lg\t%lg\n", coord[0], coord[1], coord[2]); //fprintf(stdout, "O \t(%lg\t%lg\t%lg)\n", coord[0], coord[1], coord[2]); //fprintf(stdout, "!!%i!!, ", nr); //} Free(tempvector, "Main: At stage Sheet - tempvector"); Free(coord, "Main: At stage Sheet - coord"); } } Free(offset, "Main: At stage Sheet - offset"); } //fprintf(stdout, "\n"; } fclose(SheetFile); fclose(SheetFileAligned); AddAtomicNumber(SheetFilename,numbersheet, Vector, Recivector); // prepend atomic number and comment AddAtomicNumber(SheetFilenameAligned,numbersheet, Vector, Recivector); // prepend atomic number and comment AddSheetInfo(SheetFilename,axis,chiral, factors, seed, numbercell, randomness); fprintf(stdout, "\nThere are %i atoms in the created sheet.\n", numbersheet); strncpy(stage, "Sheet", 5); //} SheetBuffer = ReadBuffer(SheetFilename, &length); // ======================== STAGE: Tube ============================== // The tube starts with the rectangular (due to the orthogonalization) sheet // just created (or read). Along the minor axis it is rolled up, i.e. projected // from a 2d surface onto a cylindrical surface (x,y,z <-> r,alpha,z). The only // thing that's a bit complex is that the sheet it not aligned along the cartesian // axis but along major and minor. That's why we have to transform the atomic // cartesian coordinates into the orthogonal tubevector base, do the rolling up // there (and regard that minor and major axis must not necessarily be of equal // length) and afterwards transform back again (where we need the $halfaxis due to // the above possible inequality). FILE *TubeFile = NULL; FILE *TubeFileAligned = NULL; Debug ("STAGE: Tube\n"); if (!strncmp(stage, "Sheet", 4)) { TubeFile = fopen(TubeFilename, "w"); if (TubeFile == NULL) { fprintf(stderr, "ERROR: Main - can't open %s for writing\n", TubeFilename); exit(255); } TubeFileAligned = fopen(TubeFilenameAligned, "w"); if (TubeFile == NULL) { fprintf(stderr, "ERROR: Main - can't open %s for writing\n", TubeFilenameAligned); exit(255); } bufptr = SheetBuffer; bufptr += GetNextline(bufptr, line); // write numbers to file bufptr += GetNextline(bufptr, line); // write comment to file //cog = CenterOfGravity(bufptr, numbersheet); //cog_projected = MatrixTrafoInverse(cog, TubevectorInverse); //fprintf(stdout, "\nCenter of Gravity at (%5.5lg\t%5.5lg\t%5.5lg) and projected at (%5.5lg\t%5.5lg\t%5.5lg)\n", cog[0], cog[1], cog[2], cog_projected[0], cog_projected[1], cog_projected[2]); // restart bufptr = SheetBuffer; bufptr += GetNextline(bufptr, line); // write numbers to file bufptr += GetNextline(bufptr, line); // write numbers to file // determine half axis as tube vector not necessarily have the same length double halfaxis[NDIM]; for (i=0;i (cos(s)*(R+r*cos(t)), sin(s)*(R+rcos(t)), r*sin(t)). // Here t is the angle within the tube with radius r, s is the torus angle with // radius R. We get R from the tubelength (that's why we need lengthfactor to // make it long enough). And due to fact that we have it already upon a cylindrical // surface, r*cos(t) and r*sin(t) already reside in $minoraxis and $noaxis. FILE *TorusFile; Debug ("STAGE: Torus\n"); if (!strncmp(stage, "Tube", 4)) { TorusFile = fopen(TorusFilename, "w"); if (TorusFile == NULL) { fprintf(stderr, "ERROR: main - can't open %s for writing\n", TorusFilename); exit(255); } bufptr = TubeBuffer; bufptr += GetNextline(bufptr, line); // write numbers to file bufptr += GetNextline(bufptr, line); // write comment to file //cog = CenterOfGravity(bufptr, numbersheet); //cog_projected = MatrixTrafoInverse(cog, TubevectorInverse); //fprintf(stdout, "\nCenter of Gravity at (%5.5lg\t%5.5lg\t%5.5lg) and projected at (%5.5lg\t%5.5lg\t%5.5lg)\n", cog[0], cog[1], cog[2], cog_projected[0], cog_projected[1], cog_projected[2]); // determine half axis as tube vectors not necessarily have same length double halfaxis[NDIM]; for (i=0;i