ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/utils/nanoBuilder.cpp
Revision: 589
Committed: Thu Jul 10 19:53:50 2003 UTC (21 years ago) by chuckv
File size: 15076 byte(s)
Log Message:
Added nanoBuilder and a general Lattice builder.

File Contents

# User Rev Content
1 chuckv 589 #include <iostream>
2    
3     #include <cstdlib>
4     #include <cstring>
5     #include <cmath>
6     #include <vector>
7    
8     #include "simError.h"
9     #include "SimInfo.hpp"
10     #include "ReadWrite.hpp"
11    
12     #include "latticeBuilder.hpp"
13     #include "MoLocator.hpp"
14     #include "sysBuild.hpp"
15     #include "nanoBuilder.hpp"
16    
17    
18    
19     nanoBuilder::nanoBuilder(int thisIsRandom, int thisHasVacancies,
20     int thisLatticeType, double thisParticleRadius,
21     double thisCoreRadius, double thisVacancyFraction,
22     double thisVacancyRadius,
23     double thisLatticeSpacing,
24     double solute_X,
25     int &hasError){
26     int Errors;
27     int foundCore,foundShell;
28     int i;
29    
30     //Zero variables
31     particleRadius = 0.0;
32     coreRadius = 0.0;
33     vacancyFraction = 0.0;
34     vacancyRadius = 0.0;
35     shellRadius = 0.0;
36     latticeSpacing = 0.0;
37    
38     buildNmol = 0;
39    
40     nCoreMolecules = 0;
41     nShellMolecules = 0;
42    
43     atomCount = 0;
44     coreAtomCount = 0;
45     shellAtomCount = 0;
46    
47    
48    
49     moleculeCount = 0;
50     foundCore = 0;
51     foundShell = 0;
52     totalMolecules = 0;
53     coreHasOrientation = 0;
54     shellHasOrientation = 0;
55     nInterface = 0;
56     nMol = 0;
57    
58     hasError = 0;
59     Errors = 0;
60    
61    
62     isRandom = thisIsRandom;
63     hasVacancies = thisHasVacancies;
64     latticeType = thisLatticeType;
65     particleRadius = thisParticleRadius;
66     coreRadius = thisCoreRadius;
67     vacancyFraction = thisVacancyFraction;
68     latticeSpacing = thisLatticeSpacing;
69     soluteX = solute_X; //Mole fraction for random particle.
70    
71    
72    
73    
74    
75     for (i=0;bsInfo.nComponents;i++){
76     if( !strcmp( bsInfo.compStamps[i]->getID(),bsInfo.coreName )){
77     foundCore = 1;
78     coreStamp = bsInfo.compStamps[i];
79     nCoreMolecules = bsInfo.componentsNmol[i];
80     }
81     if( !strcmp( bsInfo.compStamps[i]->getID(),bsInfo.shellName)){
82     foundShell = 1;
83     shellStamp = bsInfo.compStamps[i];
84     nShellMolecules = bsInfo.componentsNmol[i];
85    
86     }
87    
88     }
89    
90    
91    
92     if( !foundCore ){
93     hasError = 1;
94     return;
95     }
96     if( !foundShell ){
97     hasError = 1;
98     return;
99     }
100    
101    
102    
103     Errors = sanityCheck();
104    
105     if (Errors){
106     hasError = 1;
107     return;
108     }
109    
110    
111    
112    
113    
114    
115    
116     nCoreModelAtoms = coreStamp->getNAtoms();
117     nShellModelAtoms = shellStamp->getNAtoms();
118    
119    
120     // We assume that if the core or shell model has more then one atom
121     // the model has an orientational component...
122     if (nCoreModelAtoms > 1) coreHasOrientation = 1;
123     if (nShellModelAtoms > 1) shellHasOrientation = 1;
124    
125     maxModelNatoms = std::max(nCoreModelAtoms,nShellModelAtoms);
126    
127     /* If we specify a number of atoms in bass, we will try to build a nanopartice
128     with that number.
129     */
130    
131    
132     if ((nShellMolecules != 0) && (nCoreMolecules != 0)){
133     totalMolecules = nShellMolecules + nCoreMolecules;
134     nCells = ceil(pow((double)totalMolecules/4.0, 1/3));
135     buildNmol = 1;
136     }
137     else {
138     nCells = 2.0 * particleRadius/latticeSpacing;
139     shellRadius = particleRadius - coreRadius;
140     }
141    
142    
143    
144    
145     // Initialize random seed
146     srand48( RAND_SEED );
147    
148    
149     }
150    
151    
152     nanoBuilder::~nanoBuilder(){
153     }
154    
155    
156     // Checks to make sure we aren't doing something the builder can't do.
157     int nanoBuilder::sanityCheck(void){
158    
159     // Right now we only do bimetallic nanoparticles
160     if (bsInfo.nComponents > 2) return 1;
161    
162     //Check for vacancies and random
163     if (hasVacancies && isRandom) return 1;
164    
165     // make sure we aren't trying to build a core larger then the total particle size
166     if ((coreRadius >= particleRadius) && (particleRadius != 0)) return 1;
167    
168     // we initialize the lattice spacing to be 0.0, if the lattice spacing is still 0.0
169     // we have a problem
170     if (latticeSpacing == 0.0) return 1;
171    
172     // Check to see if we are specifing the number of atoms in the particle correctly.
173     if ((nShellMolecules == 0) && (nCoreMolecules != 0)){
174     cerr << "nShellParticles is zero and nCoreParticles != 0" << "\n";
175     return 1;
176     }
177     // Make sure there are more then two components if we are building a randomly mixed particle.
178     if ((bsInfo.nComponents < 2) && (isRandom)){
179     cerr << "Two Components are needed to build a random particle." << "\n";
180     }
181     // Make sure both the core and shell models specify a target nmol.
182     if ((nShellMolecules != 0) && (nCoreMolecules == 0)){
183     cerr << "nCoreParticles is zero and nShellParticles != 0" << "\n";
184     return 1;
185     }
186    
187     return 0;
188    
189     }
190    
191    
192    
193     int nanoBuilder::buildNanoParticle( void ){
194    
195     int ix;
196     int iy;
197     int iz;
198     double *rx;
199     double *ry;
200     double *rz;
201     double pos[3];
202     double A[3][3];
203     double HmatI[9];
204    
205     int nCellSites;
206     int iref;
207     int appNMols;
208     int latticeCount = 0;
209    
210     int nAtoms;
211     int nCoreAtomCounter = 0;
212     int nShellAtomCounter = 0;
213     int hasError;
214    
215     int i;
216    
217     int interfaceIndex = 0;
218     double dist;
219     double distsq;
220     int latticeNpoints;
221     int shesActualSizetoMe = 0;
222    
223     DumpWriter* writer;
224     SimInfo* simnfo;
225    
226     Lattice::Lattice *myLattice;
227     MoLocator::MoLocator *coreLocate;
228     MoLocator::MoLocator *shellLocate;
229    
230    
231     Atom** atoms;
232    
233     hasError = 0;
234    
235     myLattice = new Lattice(FCC_LATTICE_TYPE,latticeSpacing);
236     /*
237     latticeNpoints = myLattice.getNpoints();
238    
239     // Initializd atom vector to approximate size.
240     switch (buildType){
241    
242     case BUILD_NMOL_PARTICLE:
243    
244     break;
245     case BUILD_CORE_SHELL_VACANCY:
246     // Make space in the vector for all atoms except the last full cells
247     // We will have to add at most (latticeNpoints-1)^3 to vector
248     appNMols = latticeNPoints * pow((double)(nCells - 1),3);
249     moleculeVector.pushBack();
250    
251     default:
252     // Make space in the vector for all atoms except the last full cells
253     // We will have to add at most (latticeNpoints-1)^3 to vector
254     appNMols = latticeNPoints * pow((double)(nCells - 1),3);
255    
256     }
257     */
258    
259    
260    
261    
262     // Create molocator and atom arrays.
263     coreLocate = new MoLocator(coreStamp);
264     shellLocate = new MoLocator(shellStamp);
265    
266    
267    
268    
269    
270    
271     for(iz=-nCells;iz < nCells;iz++){
272     for(iy=-nCells;iy<nCells;iy++){
273     for(ix=-nCells;ix<nCells;ix++){
274     nCellSites = myLattice->getLatticePoints(&rx,&ry,&rz,
275     ix,iy,iz);
276     for (iref=1;iref<nCellSites;iref++){
277     latticeCount++;
278    
279     pos[0] = rx[iref];
280     pos[1] = ry[iref];
281     pos[2] = rz[iref];
282    
283     distsq = rx[iref]*rx[iref] + ry[iref]*ry[iref] +rz[iref]*rz[iref];
284     dist = sqrt(distsq);
285    
286     switch(buildType){
287    
288     case BUILD_CORE_SHELL:
289     nanoBuilder::buildWithCoreShell(dist,pos);
290     break;
291     case BUILD_CORE_SHELL_VACANCY:
292     nanoBuilder::buildWithVacancies(dist,pos);
293     break;
294    
295     case BUILD_RANDOM_PARTICLE:
296     nanoBuilder::buildRandomlyMixed(dist,pos);
297     break;
298     case BUILD_NMOL_PARTICLE:
299     nanoBuilder::buildNmolParticle(dist,pos);
300     }
301     }
302     }
303     }
304     }
305    
306    
307    
308     // Create vacancies
309     if (hasVacancies) buildVacancies();
310    
311     // Find the size of the atom vector not including Null atoms
312     for (i=0;i<moleculeVector.size();i++){
313     if (! moleculeVector[i].isVacancy){
314     shesActualSizetoMe++;
315     nAtoms = moleculeVector[i].myStamp->getNAtoms();
316     }
317     }
318    
319     // Make a random particle.
320     if (isRandom){
321     placeRandom(shesActualSizetoMe);
322    
323     // Loop back thru and count natoms since they may have changed
324     for (i=0;i<moleculeVector.size();i++){
325     if (! moleculeVector[i].isVacancy){
326     shesActualSizetoMe++;
327     nAtoms = moleculeVector[i].myStamp->getNAtoms();
328     }
329     }
330     }
331    
332    
333     Atom::createArrays( nAtoms );
334     atoms = new Atom*[nAtoms];
335    
336    
337    
338     shesActualSizetoMe = 0;
339     /* Use the information from the molecule vector to place the atoms.
340     */
341     for (i= 0;i<moleculeVector.size();i++){
342     if (! moleculeVector[i].isVacancy) {
343     orientationMunger( A );
344     if( moleculeVector[i].isCore){
345     nCoreAtomCounter =+ nCoreModelAtoms;
346     coreLocate->placeMol(moleculeVector[i].pos,A,atoms,nShellAtomCounter);
347     }
348     else {
349     nShellAtomCounter =+ nShellModelAtoms;
350     shellLocate->placeMol(moleculeVector[i].pos,A,atoms,nCoreAtomCounter);
351     }
352     shesActualSizetoMe++;
353     }
354     }
355    
356    
357     // shellLocate.placeMol(pos, A, moleculeVector,shellAtomCount);
358    
359     for (i=0;i<9;i++) simnfo->Hmat[i] = 0;
360     simnfo->Hmat[0] = 1;
361     simnfo->Hmat[4] = 1;
362     simnfo->Hmat[8] = 1;
363    
364     // set up the SimInfo object
365     simnfo = new SimInfo();
366     simnfo->n_atoms = nAtoms;
367    
368    
369     sprintf( simnfo->sampleName, "%s.dump", bsInfo.outPrefix );
370     sprintf( simnfo->finalName, "%s.init", bsInfo.outPrefix );
371    
372     simnfo->atoms = atoms;
373    
374     // set up the writer and write out
375    
376     writer = new DumpWriter( simnfo );
377     writer->writeFinal(0.0);
378    
379     // clean up
380    
381     delete[] myLattice;
382    
383     return hasError;
384     }
385    
386     // Begin Builder routines------------------------------->
387    
388     /* Builds a standard core-shell nanoparticle.
389     */
390     void nanoBuilder::buildWithCoreShell(double dist, double pos[3]){
391    
392    
393     if ( dist <= particleRadius ){
394     moleculeVector.push_back(myMol);
395    
396     if (dist <= coreRadius){
397     coreAtomCount =+ nCoreModelAtoms;
398     moleculeVector[moleculeCount].pos[0] = pos[0];
399     moleculeVector[moleculeCount].pos[1] = pos[1];
400     moleculeVector[moleculeCount].pos[2] = pos[2];
401     moleculeVector[moleculeCount].myStamp = coreStamp;
402     moleculeVector[moleculeCount].isCore = 1;
403     moleculeVector[moleculeCount].isShell = 0;
404    
405     }
406     // Place shell
407     else{
408     shellAtomCount =+ nShellModelAtoms;
409     moleculeVector[moleculeCount].pos[0] = pos[0];
410     moleculeVector[moleculeCount].pos[1] = pos[1];
411     moleculeVector[moleculeCount].pos[2] = pos[2];
412     moleculeVector[moleculeCount].myStamp = shellStamp;
413     moleculeVector[moleculeCount].isCore = 0;
414     moleculeVector[moleculeCount].isShell = 1;
415    
416     }
417     moleculeCount++;
418     }
419    
420     }
421     /*
422     Builds a core-shell nanoparticle and tracks the number of molecules at the
423     interface between the core-shell. These are recorded in vacancyInterface which is just
424     an integer vector.
425     */
426     void nanoBuilder::buildWithVacancies(double dist, double pos[3]){
427     if ( dist <= particleRadius ){
428    
429     moleculeVector.push_back(myMol);
430     if (dist <= coreRadius){
431    
432     coreAtomCount =+ nCoreModelAtoms;
433     moleculeVector[moleculeCount].pos[0] = pos[0];
434     moleculeVector[moleculeCount].pos[1] = pos[1];
435     moleculeVector[moleculeCount].pos[2] = pos[2];
436     moleculeVector[moleculeCount].myStamp = coreStamp;
437     moleculeVector[moleculeCount].isCore = 1;
438     moleculeVector[moleculeCount].isShell = 0;
439    
440     if ((dist >= coreRadius - vacancyRadius/2.0) &&
441     (dist <= coreRadius + vacancyRadius/2.0)){
442    
443     vacancyInterface.push_back(moleculeCount);
444     nInterface++;
445     }
446     } else {
447     // Place shell
448     shellAtomCount =+ nShellModelAtoms;
449     moleculeVector[moleculeCount].pos[0] = pos[0];
450     moleculeVector[moleculeCount].pos[1] = pos[1];
451     moleculeVector[moleculeCount].pos[2] = pos[2];
452     moleculeVector[moleculeCount].myStamp = shellStamp;
453     moleculeVector[moleculeCount].isCore = 0;
454     moleculeVector[moleculeCount].isShell = 1;
455    
456     }
457     moleculeCount++;
458     }
459    
460    
461    
462     }
463    
464     /* Builds a core-shell nanoparticle where the number of core and shell
465     molecules is known.
466     */
467     void nanoBuilder::buildNmolParticle(double dist, double pos[3]){
468     static int nMolCounter = 0;
469     static int nCoreMolCounter = 0;
470    
471    
472     if (nMolCounter < totalMolecules){
473     moleculeVector.push_back(myMol);
474     if (nCoreMolCounter < nCoreMolecules){
475    
476     coreAtomCount =+ nCoreModelAtoms;
477     moleculeVector[moleculeCount].pos[0] = pos[0];
478     moleculeVector[moleculeCount].pos[1] = pos[1];
479     moleculeVector[moleculeCount].pos[2] = pos[2];
480     moleculeVector[moleculeCount].myStamp = coreStamp;
481     moleculeVector[moleculeCount].isCore = 1;
482     moleculeVector[moleculeCount].isShell = 0;
483    
484    
485     } else {
486     shellAtomCount =+ nShellModelAtoms;
487     moleculeVector[moleculeCount].pos[0] = pos[0];
488     moleculeVector[moleculeCount].pos[1] = pos[1];
489     moleculeVector[moleculeCount].pos[2] = pos[2];
490     moleculeVector[moleculeCount].myStamp = shellStamp;
491     moleculeVector[moleculeCount].isCore = 0;
492     moleculeVector[moleculeCount].isShell = 1;
493    
494    
495     }
496    
497     }
498     }
499    
500    
501     /* Builds a randomly mixed nanoparticle. We build the particle to be
502     entirely the core model, then randomly switch identities after the particle is built.
503     */
504     void nanoBuilder::buildRandomlyMixed(double dist, double pos[3]){
505    
506    
507     if ( dist <= particleRadius ){
508     moleculeCount++;
509    
510    
511     moleculeVector[moleculeCount].pos[0] = pos[0];
512     moleculeVector[moleculeCount].pos[1] = pos[1];
513     moleculeVector[moleculeCount].pos[2] = pos[2];
514     moleculeVector[moleculeCount].myStamp = coreStamp;
515     moleculeVector[moleculeCount].isCore = 1;
516     moleculeVector[moleculeCount].isShell = 0;
517    
518     }
519    
520    
521    
522     }
523    
524    
525     // -----------------------END Builder routines.
526    
527    
528    
529     //------------------------Begin Helper routines.
530     void nanoBuilder::placeRandom(int totalMol){
531     int nSolute;
532     int nSolvent;
533     int i;
534     int notfound;
535     double solute_x;
536     double solvent_x;
537    
538     int tester;
539    
540     nSolute = floor(soluteX * (double)totalMolecules); //CHECK ME
541     nSolvent = totalMolecules - nSolute;
542    
543     solute_x = (double)nSolute/(double)totalMolecules;
544     solvent_x = 1.0 - solute_x;
545    
546    
547    
548    
549     for(i=0;nSolute-1;i++){
550     notfound = 1;
551    
552     while(notfound){
553    
554     tester = floor((double)totalMolecules * drand48()); //Pick a molecule
555    
556     if (moleculeVector[tester].isCore){ // Make sure we select a core atom to change
557    
558     moleculeVector[tester].isCore = 0;
559     moleculeVector[tester].isShell = 1;
560     moleculeVector[tester].myStamp = shellStamp;
561     notfound = 0; //set notfound = false.
562     }
563    
564     }
565    
566     }
567     }
568    
569    
570     void nanoBuilder::buildVacancies(void){
571     int i;
572     int* VacancyList; //logical nInterface long.
573     int notfound;
574     int index = 0;
575     int nVacancies;
576     int tester;
577    
578     if (nInterface != 0){
579     nVacancies = floor((double)nInterface * vacancyFraction);
580    
581     VacancyList = new int[nInterface];
582    
583     // make vacancy list all false
584     for(i=0;i<nInterface-1;i++){
585     VacancyList[i] = 0;
586     }
587    
588     // Build a vacancy list....
589     for(i=0;nVacancies-1;i++){
590     notfound = 1;
591     while(notfound){
592    
593     tester = floor((double)nInterface * drand48());
594    
595     if(! VacancyList[tester]){
596     VacancyList[tester] = 1;
597     notfound = 0;
598     }
599    
600     }
601     }
602     }
603     // Loop through and kill the vacancies from atom vector.
604    
605     for (i=0;i<nInterface;i++){
606     if (VacancyList[i]){
607     moleculeVector[vacancyInterface[i]].isVacancy = 1;
608     } // End Vacancy List
609     } // for nInterface
610    
611    
612     delete[] VacancyList;
613     }
614    
615    
616    
617    
618     void nanoBuilder::orientationMunger(double rot[3][3]){
619    
620     double theta, phi, psi;
621     double cosTheta;
622    
623     // select random phi, psi, and cosTheta
624    
625     phi = 2.0 * M_PI * drand48();
626     psi = 2.0 * M_PI * drand48();
627     cosTheta = (2.0 * drand48()) - 1.0; // sample cos -1 to 1
628    
629     theta = acos( cosTheta );
630    
631     rot[0][0] = (cos(phi) * cos(psi)) - (sin(phi) * cos(theta) * sin(psi));
632     rot[0][1] = (sin(phi) * cos(psi)) + (cos(phi) * cos(theta) * sin(psi));
633     rot[0][2] = sin(theta) * sin(psi);
634    
635     rot[1][0] = -(cos(phi) * sin(psi)) - (sin(phi) * cos(theta) * cos(psi));
636     rot[1][1] = -(sin(phi) * sin(psi)) + (cos(phi) * cos(theta) * cos(psi));
637     rot[1][2] = sin(theta) * cos(psi);
638    
639     rot[2][0] = sin(phi) * sin(theta);
640     rot[2][1] = -cos(phi) * sin(theta);
641     rot[2][2] = cos(theta);
642    
643     }
644    
645    
646    
647    
648    
649    
650