// Set flags for this material being rigid and for if it ignores cracks // Not that ignoring cracks only works for multimaterial mode. Rigid contact // materials default to ignoring cracks while non rigid default to see them int MaterialBase::GetMVFFlags(int matfld) { // check number errors if(matfld>=(int)fieldMatIDs.size()) return 0; MaterialBase *matID = theMaterials[fieldMatIDs[matfld]]; int flags = matID->Rigid() ? RIGID_FIELD_BIT : 0 ; return flags; }
// Archive the results if it is time void ArchiveData::ArchiveHistoryFile(double atime,vector< int > quantity) { char fname[300],fline[600],subline[100]; // get relative path name to the file sprintf(fname,"%s%s_History_%d.txt",outputDir,archiveRoot,fmobj->mstep); // open the file ofstream afile; afile.open(fname, ios::out); if(!afile.is_open()) FileError("Cannot open a particle history archive file",fname,"ArchiveData::ArchiveHistoryFile"); // header line afile << "Particle History Data File" << endl; // title sprintf(fline,"step:%d time:%15.7e ms",fmobj->mstep,1000.*atime); afile << fline << endl; strcpy(fline,"#\tx\ty"); if(threeD) strcat(fline,"\tz"); unsigned int q; for(q=0;q<quantity.size();q++) { sprintf(subline,"\t%d",quantity[q]); strcat(fline,subline); } afile << fline << endl; // each particle int p; for(p=0;p<nmpms;p++) { // number and position afile << p+1 << "\t" << mpm[p]->pos.x << "\t" << mpm[p]->pos.y ; if(threeD) afile << "\t" << mpm[p]->pos.z ; // history data MaterialBase *matptr = theMaterials[mpm[p]->MatID()]; char *hptr = mpm[p]->GetHistoryPtr(); for(q=0;q<quantity.size();q++) { afile << "\t" << matptr->GetHistory(quantity[q],hptr); } afile << endl; } // close the file afile.close(); if(afile.bad()) FileError("File error closing a particle history archive file",fname,"ArchiveData::ArchiveHistoryFile"); }
MaterialBase * SampleDynamic::lookupMaterial(Point & pos) { // std::cout << "lookuplayer" << std::endl; MaterialBase * m = material[lookupLayer(pos)]; // std::cout << m << ' ' << m->_arho << ' ' << m->am << ' ' << m->az << ' ' << m->mu << std::endl; // on-demand update if (m->_dirty) { // std::cout << "on demand aver" << std::endl; m->average(pka); // std::cout << m << ' ' << m->_arho << ' ' << m->am << ' ' << m->az << ' ' << m->mu << // std::endl; } return m; }
// Adjust time step now CustomTask *CarnotCycle::StepCalculation(void) { int p; MaterialBase *matID; double Vrel = 0.; int numgas = 0; double Tgas = 0.; // loop over nonrigid material points for(p=0;p<nmpmsNR;p++) { numgas++; Vrel += mpm[p]->GetRelativeVolume(); Tgas += mpm[p]->pPreviousTemperature; } // get averages Vrel /= (double)numgas; Tgas /= (double)numgas; switch(carnotStep) { case 0: carnotStep = 1; cout << "# Step 1: isothermal expansion" << endl; ConductionTask::adiabatic = FALSE; break; case 1: // stop when Vrel reaches V1rel if(Vrel >= V1rel) { // switch to adibatic expanion carnotStep = 2; ConductionTask::adiabatic = TRUE; cout << "# Step 2: adibatic expansion" << endl; } break; case 2: // stop when T cools to T2 if(Tgas<=T2) { // switch to pause carnotStep = 3; ConductionTask::adiabatic = FALSE; V2rel = Vrel; // find velocity for(p=0;p<nmpms;p++) { // verify material is defined and sets if field number (in in multimaterial mode) matID=theMaterials[mpm[p]->MatID()]; // material object for this particle if(matID->Rigid()) mpm[p]->ReverseParticle(false,false); else mpm[p]->StopParticle(); } // estimate next volume if(V3rel<1.) V3rel = V2rel/V1rel; cout << "# Step 2: isothermal compression to " << V3rel << "*V0" << endl; } break; case 3: // stop when Vrel reaches V3rel if(Vrel <= V3rel) { // switch to adibatic compression carnotStep = 4; ConductionTask::adiabatic = TRUE; cout << "# Step 4: adibatic compression" << endl; } break; case 4: // done when T increases to thermal.reference, or when volume returns to 1 if(Tgas>=thermal.reference) throw CommonException("Carnot cycle is complete","CarnotCycle::StepCalculation()"); //if(Vrel<=1.) // throw CommonException("Carnot cycle is complete","CarnotCycle::StepCalculation()"); break; default: break; } return nextTask; }
// when set, return total number of materials if this is a new one, or 1 if not in multimaterial mode // not thread safe due to push_back() int MaterialBase::SetField(int fieldNum,bool multiMaterials,int matid,int &activeNum) { if(!multiMaterials) { if(field<0) { field=0; activeField=activeNum; fieldNum=1; activeNum++; activeMatIDs.push_back(matid); int altBuffer,matBuffer = SizeOfMechanicalProperties(altBuffer); if(matBuffer > maxPropertyBufferSize) maxPropertyBufferSize = matBuffer; if(altBuffer > maxAltBufferSize) maxAltBufferSize = altBuffer; } } else { if(field<0) { // if sharing a field, look up shared material. if(shareMatField>0) { if(shareMatField>nmat) { throw CommonException("Material class trying to share velocity field with an undefined material type", "MaterialBase::SetField"); } // must match for rigid feature MaterialBase *matRef = theMaterials[shareMatField-1]; if(matRef->Rigid() != Rigid()) { throw CommonException("Material class trying to share velocity field with an incompatible material type", "MaterialBase::SetField"); } // base material cannot share too if(matRef->GetShareMatField()>=0) { throw CommonException("Material class trying to share velocity field with a material that share's its field", "MaterialBase::SetField"); } // set field to other material (and set other material if needed field = matRef->GetField(); if(field<0) { fieldNum = matRef->SetField(fieldNum,multiMaterials,shareMatField-1,activeNum); field = fieldNum-1; } } else { field=fieldNum; fieldNum++; // fieldMatIDs[i] for i=0 to # materials is material index for that material velocity field // when materials share fields, it points to the based shared material fieldMatIDs.push_back(matid); } // for first particle using this material, add to active material IDs and check required // material buffer sizes if(activeNum>=0) { activeField=activeNum; activeNum++; activeMatIDs.push_back(matid); int altBuffer,matBuffer = SizeOfMechanicalProperties(altBuffer); if(matBuffer > maxPropertyBufferSize) maxPropertyBufferSize = matBuffer; if(altBuffer > maxAltBufferSize) maxAltBufferSize = altBuffer; } } } return fieldNum; }
// increment external load on a particle // input is analysis time in seconds // (only called when diffusion is active) MatPtFluxBC *MatPtFluxBC::AddMPFlux(double bctime) { // condition value is g/(mm^2-sec), Divide by rho*csat to get potential flux in mm/sec // find this flux and then add (times area) to get mm^3-potential/sec MPMBase *mpmptr = mpm[ptNum-1]; MaterialBase *matptr = theMaterials[mpmptr->MatID()]; // Flux is a scalar and we need int_(face) F Ni(x) dA // Since F is constant, only need integral which is done by CPDI methods // which has be generalized to work for GIMP too // We use X_DIRECTION for bcDIR for efficiency. For Silent BC, change to // Normal direction to all caculation of n Vector fluxMag; ZeroVector(&fluxMag); int bcDir=X_DIRECTION; if(style==SILENT) { TransportProperties t; matptr->GetTransportProps(mpmptr,fmobj->np,&t); Tensor *D = &(t.diffusionTensor); // D in mm^2/sec, Dc in 1/mm if(fmobj->IsThreeD()) { fluxMag.x = D->xx*mpmptr->pDiffusion[gGRADx] + D->xy*mpmptr->pDiffusion[gGRADy] + D->xz*mpmptr->pDiffusion[gGRADz]; fluxMag.y = D->xy*mpmptr->pDiffusion[gGRADx] + D->yy*mpmptr->pDiffusion[gGRADy] + D->yz*mpmptr->pDiffusion[gGRADz]; fluxMag.z = D->xz*mpmptr->pDiffusion[gGRADx] + D->yz*mpmptr->pDiffusion[gGRADy] + D->zz*mpmptr->pDiffusion[gGRADz]; } else { fluxMag.x = D->xx*mpmptr->pDiffusion[gGRADx] + D->xy*mpmptr->pDiffusion[gGRADy]; fluxMag.y = D->xy*mpmptr->pDiffusion[gGRADx] + D->yy*mpmptr->pDiffusion[gGRADy]; } bcDir = N_DIRECTION; } else if(direction==EXTERNAL_FLUX) { // csatrho = rho0 V0 csat/V (units g/mm^3) double csatrho = mpmptr->GetRho()*mpmptr->GetConcSaturation()/mpmptr->GetRelativeVolume(); fluxMag.x = BCValue(bctime)/csatrho; } else { // coupled surface flux and ftime is bath concentration // time variable (t) is replaced by c-cbath, where c is the particle potential and cbath is bath potential varTime = mpmptr->pPreviousConcentration-GetBCFirstTime(); GetPosition(&varXValue,&varYValue,&varZValue,&varRotValue); double currentValue = fabs(scale*function->Val()); if(varTime>0.) currentValue=-currentValue; // csatrho = rho0 V0 csat/V (units g/mm^3) double csatrho = mpmptr->GetRho()*mpmptr->GetConcSaturation()/mpmptr->GetRelativeVolume(); fluxMag.x = currentValue/csatrho; } // get corners and direction from material point int cElem[4],numDnds; Vector corners[4],tscaled; double ratio = mpmptr->GetTractionInfo(face,bcDir,cElem,corners,&tscaled,&numDnds); // compact CPDI nodes into list of nodes (nds) and final shape function term (fn) // May need up to 8 (in 3D) for each of the numDnds (2 in 2D or 4 in 3D) int nds[8*numDnds+1]; double fn[8*numDnds+1]; int numnds = CompactCornerNodes(numDnds,corners,cElem,ratio,nds,fn); // add force to each node int i; for(i=1;i<=numnds;i++) diffusion->AddFluxCondition(nd[nds[i]],DotVectors(&fluxMag,&tscaled)*fn[i],false); return (MatPtFluxBC *)GetNextObject(); }
int main(int argc, char * argv[]) { if (argc != 3) { fprintf(stderr, "syntax:\n%s element energy[keV]\n", argv[0]); return 1; } // PKA energy Real E = atof(argv[2]) * 1000.0; // seed random number generator from system entropy pool FILE * urand = fopen("/dev/random", "r"); unsigned int seed; if (fread(&seed, sizeof(unsigned int), 1, urand) != 1) return 1; fclose(urand); // initialize global parameter structure and read data tables from file SimconfType * simconf = new SimconfType(seed); simconf->fullTraj = false; simconf->tmin = 0.2; // initialize sample structure SampleSolid * sample = new SampleSolid(200.0, 200.0, 200.0); // initialize trim engine for the sample TrimBase * trim = new TrimBase(simconf, sample); // TrimBase *trim = new TrimPrimaries(sample); // sample->bc[0] = SampleBase::CUT; // no PBC in x (just clusterless matrix) // Real atp = 0.1; // 10at% Mo 90at%Cu Real v_sam = sample->w[0] * sample->w[1] * sample->w[2]; Real s_sam = sample->w[1] * sample->w[2]; MaterialBase * material; Element element; const char * choice[4] = {"Fe", "Si", "Cu", "Au"}; int i; for (i = 0; i < 4 && strcmp(choice[i], argv[1]) != 0; ++i) ; if (i == 4) { fprintf(stderr, "Element choice not supported: %s\n", argv[1]); return 1; } Real A, Z; switch (i) { case 0: // Fe material = new MaterialBase(simconf, 7.87); // rho Z = 26.0; A = 56.0; element._Z = Z; element._m = A; element._t = 1.0; element._Edisp = 25.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample break; case 1: // Si material = new MaterialBase(simconf, 2.33); // rho Z = 14.0; A = 28.0; element._Z = Z; element._m = A; element._t = 1.0; element._Edisp = 25.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample break; case 2: // Cu material = new MaterialBase(simconf, 8.89); // rho Z = 29.0; A = 63.5; element._Z = Z; element._m = A; element._t = 1.0; element._Edisp = 25.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample break; case 3: // Au material = new MaterialBase(simconf, 19.32); // rho Z = 79.0; A = 197.0; element._Z = Z; element._m = A; element._t = 1.0; element._Edisp = 25.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample break; default: return 1; } const int nstep = 1000; // create a FIFO for recoils std::queue<IonBase *> recoils; Point pos2; IonBase *ff1, *pka; // squared displacement Real sqd = 0.0, sqd2 = 0.0; // main loop for (int n = 0; n < nstep; n++) { if (n % 10 == 0) fprintf(stderr, "pka #%d\n", n + 1); ff1 = new IonBase; ff1->_gen = 0; // generation (0 = PKA) ff1->_tag = -1; ff1->_id = simconf->_id++; ff1->_Z = Z; ff1->_m = A; ff1->_E = E; ff1->_dir(0) = 1; ff1->_dir(1) = 0; ff1->_dir(2) = 0; ff1->_pos(0) = 0; ff1->_pos(1) = sample->w[1] / 2.0; ff1->_pos(2) = sample->w[2] / 2.0; ff1->setEf(); recoils.push(ff1); while (!recoils.empty()) { pka = recoils.front(); recoils.pop(); sample->averages(pka); // store position if (pka->_gen > 0) pos2 = pka->_pos; // follow this ion's trajectory and store recoils trim->trim(pka, recoils); // do ion analysis/processing AFTER the cascade here if (pka->_gen > 0) sqd += (pos2 - pka->_pos).norm_sq(); else if (pka->_gen > 1) sqd2 += (pos2 - pka->_pos).norm_sq(); // done with this recoil delete pka; } } // output full damage data printf("total sum of square displacements: %g Ang^2\n", sqd); printf("%d vacancies per %d ions = %d vac/ion\n", simconf->vacancies_created, nstep, simconf->vacancies_created / nstep); Real natom = v_sam * sample->material[0]->_arho; printf("volume = %f Ang^3, surface area = %f Ang^2, containing %f atoms => %f dpa/(ion/Ang^2)\n", v_sam, s_sam, natom, simconf->vacancies_created / (natom * nstep / s_sam)); printf("sqd/dpa = %g\n sqd/vac = %g\n sqd2/vac = %g\nnvac = %d", sqd / (simconf->vacancies_created / natom), sqd / simconf->vacancies_created, sqd2 / simconf->vacancies_created, simconf->vacancies_created); /* // calculate modified kinchin pease data http://www.iue.tuwien.ac.at/phd/hoessinger/node47.html // just for the PKA Real Zatoms = 26.0, Matoms = 56.0; Real Epka = 5.0e6; Real ed = 0.0115 * std::pow(Zatoms, -7.0/3.0) * Epka; Real g = 3.4008 * std::pow(ed, 1.0/6.0) + 0.40244 * std::pow(ed, 3.0/4.0) + ed; Real kd = 0.1337 * std::pow(Zatoms, 2.0/3.0) / std::pow(Matoms, 0.5); //Z, M Real Ev = Epka / (1.0 + kd * g); Real Ed = 40.0; printf("%f modified PKA kinchin-pease vacancies per 100 ions = %f vac/ion\n", 100*0.8*Ev/(2.0*Ed), 0.8*Ev/(2.0*Ed)); // do Kinchin-Pease for all primary recoils printf("%f modified 1REC kinchin-pease vacancies per 100 ions = %f vac/ion\n", simconf->KP_vacancies, simconf->KP_vacancies / 100.0); */ return EXIT_SUCCESS; }
int main(int argc, char * argv[]) { char fname[200]; if (argc != 2) { fprintf(stderr, "syntax:\n%s basename\n", argv[0]); return 1; } // seed random number generator from system entropy pool FILE * urand = fopen("/dev/random", "r"); unsigned int seed; if (fread(&seed, sizeof(unsigned int), 1, urand) != 1) return 1; fclose(urand); // initialize global parameter structure and read data tables from file SimconfType * simconf = new SimconfType(seed); simconf->fullTraj = false; simconf->tmin = 0.2; // initialize sample structure SampleSolid * sample = new SampleSolid(200.0, 200.0, 200.0); // initialize trim engine for the sample snprintf(fname, 199, "%s.phon", argv[1]); // FILE *phon = fopen(fname, "wt"); // TrimPhononOut *trim = new TrimPhononOut(sample, phon); // TrimBase *trim = new TrimBase(sample); TrimBase * trim = new TrimPrimaries(simconf, sample); sample->bc[0] = SampleBase::CUT; // no PBC in x (just clusterless matrix) // Real atp = 0.1; // 10at% Mo 90at%Cu Real v_sam = sample->w[0] * sample->w[1] * sample->w[2]; Real s_sam = sample->w[1] * sample->w[2]; MaterialBase * material; Element element; /* // Fe material = new MaterialBase(simconf, 7.87); // rho element._Z = 26; // Fe element._m = 56.0; element._t = 1.0; element._Edisp = 40.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample // ZrO2 material = new MaterialBase(simconf, 5.68); // rho element._Z = 40; // Zr element._m = 91.0; element._t = 1.0; material->_element.push_back(element); element._Z = 8; // O element._m = 16.0; element._t = 2.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample */ // ZrO2 Xe 0.01 material = new MaterialBase(simconf, 5.68); // rho element._Z = 40; // Zr element._m = 90.0; // 91? element._t = 1.0; material->_element.push_back(element); element._Z = 8; // O element._m = 16.0; element._t = 2.0; material->_element.push_back(element); /*element._Z = 54; // Xe element._m = 132.0; element._t = 0.01; material->_element.push_back(element);*/ material->prepare(); // all materials added sample->material.push_back(material); // add material to sample /* // TiO2 precipitate material = new MaterialBase(simconf, 4.23); // rho element._Z = 22; // Ti element._m = 48.0; element._t = 1.0; material->_element.push_back(element); element._Z = 8; // O element._m = 16.0; element._t = 2.0; material->_element.push_back(element); material->prepare(); sample->material.push_back(material); // add material to sample // Y2Ti2O7 precipitate material = new MaterialBase(simconf, 4.6); // rho between 4.23 and 5.01 element._Z = 39; // Y element._m = 89.0; element._t = 2.0; element._Edisp = 57.0; material->_element.push_back(element); element._Z = 22; // Ti element._m = 48.0; element._t = 2.0; element._Edisp = 57.0; material->_element.push_back(element); element._Z = 8; // O element._m = 16.0; element._t = 7.0; element._Edisp = 57.0; material->_element.push_back(element); material->prepare(); sample->material.push_back(material); // add material to sample // xe bubble material = new MaterialBase(simconf, 3.5); // rho element._Z = 54; // Xe element._m = 132.0; element._t = 1.0; material->_element.push_back(element); material->prepare(); sample->material.push_back(material); // add material to sample */ const int nstep = 10000; // create a FIFO for recoils std::queue<IonBase *> recoils; Real dif2[3]; snprintf(fname, 199, "%s.Erec", argv[1]); FILE * erec = fopen(fname, "wt"); snprintf(fname, 199, "%s.dist", argv[1]); FILE * rdist = fopen(fname, "wt"); Real pos2[3]; IonBase *ff1, *pka; // Real A = 84.0, E = 1.8e6; int Z = 36; // 1.8MeV Kr Real A = 131.0, E = 2.0e4; int Z = 54; // 20keV Xe // Real A = 58.0, E = 5.0e6; int Z = 28; // 5MeV Ni // Real A = 56.0, E = 5.0e6; int Z = 26; // 5MeV Fe // main loop for (int n = 0; n < nstep; n++) { if (n % 10 == 0) fprintf(stderr, "pka #%d\n", n + 1); ff1 = new IonBase; ff1->_gen = 0; // generation (0 = PKA) ff1->_tag = -1; ff1->_id = simconf->_id++; ff1->_Z = Z; ff1->_m = A; ff1->_E = E; ff1->_dir(0) = 1; ff1->_dir(1) = 0; ff1->_dir(2) = 0; ff1->_pos(0) = 0; ff1->_pos(1) = sample->w[1] / 2.0; ff1->_pos(2) = sample->w[2] / 2.0; ff1->setEf(); recoils.push(ff1); while (!recoils.empty()) { pka = recoils.front(); recoils.pop(); sample->averages(pka); // do ion analysis/processing BEFORE the cascade here // fprintf(erec, "%f\t%d\t%d\n", pka->_E, pka->_gen, pka->_md); // pka is O or Ti // if (pka->_Z == 8 || pka->_Z == 22 || pka->_Z == 39) // pka is Xe Real oerec = pka->_E; if (pka->_Z == 542) { if (pka->_gen > 0) { // output energy and recoil generation // fprintf(erec, "%f\t%d\t%d\n", pka->_E, pka->_gen, pka->_md); } for (int i = 0; i < 3; ++i) { pos2[i] = pka->_pos(i); } } // follow this ion's trajectory and store recoils // printf("%f\t%d\n", pka->_E, pka->_Z); // pka->_md = id++; trim->trim(pka, recoils); fprintf(rdist, "%f 1\n", pka->_pos(0)); // do ion analysis/processing AFTER the cascade here // pka is O or Ti // if (pka->_Z == 8 || pka->_Z == 22 || pka->_Z == 39) // pka is Xe if (pka->_Z == 542) { // output // printf("%f %f %f %d\n", pka->_pos(0), pka->_pos(1), pka->_pos(2), pka->_tag); // print out distance to cluster of origin center (and depth of recoil) for (int i = 0; i < 3; ++i) { dif2[i] = pos2[i] - pka->_pos(i); // total distance it moved } fprintf(rdist, "%d %f %f %f %f %f\n", pka->_Z, pos2[0], pos2[1], pos2[2], std::sqrt(v_dot(dif2, dif2)), oerec); } // done with this recoil delete pka; // this should rather be done with spawnRecoil returning false // if (simconf->primariesOnly) while (!recoils.empty()) { delete recoils.front(); // recoils.pop(); }; } } fclose(rdist); fclose(erec); // output full damage data printf("%d vacancies per %d ions = %d vac/ion\n", simconf->vacancies_created, nstep, simconf->vacancies_created / nstep); Real natom = v_sam * sample->material[0]->_arho; printf("volume = %f Ang^3, surface area = %f Ang^2, containing %f atoms => %f dpa/(ion/Ang^2)", v_sam, s_sam, natom, simconf->vacancies_created / (natom * nstep / s_sam)); /* // calculate modified kinchin pease data http://www.iue.tuwien.ac.at/phd/hoessinger/node47.html // just for the PKA Real Zatoms = 26.0, Matoms = 56.0; Real Epka = 5.0e6; Real ed = 0.0115 * std::pow(Zatoms, -7.0/3.0) * Epka; Real g = 3.4008 * std::pow(ed, 1.0/6.0) + 0.40244 * std::pow(ed, 3.0/4.0) + ed; Real kd = 0.1337 * std::pow(Zatoms, 2.0/3.0) / std::pow(Matoms, 0.5); //Z, M Real Ev = Epka / (1.0 + kd * g); Real Ed = 40.0; printf("%f modified PKA kinchin-pease vacancies per 100 ions = %f vac/ion\n", 100*0.8*Ev/(2.0*Ed), 0.8*Ev/(2.0*Ed)); // do Kinchin-Pease for all primary recoils printf("%f modified 1REC kinchin-pease vacancies per 100 ions = %f vac/ion\n", simconf->KP_vacancies, simconf->KP_vacancies / 100.0); */ return EXIT_SUCCESS; }
int main(int argc, char * argv[]) { char fname[200]; if (argc != 4) // 2 { fprintf( stderr, "syntax:\n%s basename r Cbfactor\n\nCbfactor=1 => 7e-4 bubbles/nm^3\n", argv[0]); return 1; } // seed random number generator from system entropy pool FILE * urand = fopen("/dev/random", "r"); unsigned int seed; if (fread(&seed, sizeof(unsigned int), 1, urand) != 1) return 1; fclose(urand); // initialize global parameter structure and read data tables from file SimconfType * simconf = new SimconfType(seed); simconf->fullTraj = false; simconf->tmin = 0.2; // initialize sample structure sampleClusters * sample = new sampleClusters(400.0, 400.0, 400.0); // initialize trim engine for the sample snprintf(fname, 199, "%s.phon", argv[1]); // FILE *phon = fopen(fname, "wt"); // TrimPhononOut *trim = new TrimPhononOut(sample, phon); TrimBase * trim = new TrimBase(simconf, sample); // TrimBase *trim = new TrimPrimaries(sample); // Real r = 10.0; Real r = atof(argv[2]); // 10.0; Real Cbf = atof(argv[3]); // sample->bc[0] = CUT; // no pbc in x dir sample->initSpatialhash( int(sample->w[0] / r) - 1, int(sample->w[1] / r) - 1, int(sample->w[2] / r) - 1); Real v_sam = sample->w[0] * sample->w[1] * sample->w[2]; int n_cl; n_cl = v_sam * 7.0e-7 * Cbf; // Ola06 7e-4/nm^3 fprintf(stderr, "adding %d clusters...\n", n_cl); // cluster surfaces must be at least 25.0 Ang apart sample->addRandomClusters(n_cl, r, 15.0, simconf); // write cluster coords with tag numbers snprintf(fname, 199, "%s.clcoor", argv[1]); FILE * ccf = fopen(fname, "wt"); for (int i = 0; i < sample->cn; ++i) fprintf(ccf, "%f %f %f %f %d\n", sample->c[0][i], sample->c[1][i], sample->c[2][i], sample->c[3][i], i); fclose(ccf); fprintf(stderr, "sample built.\n"); MaterialBase * material; Element element; // UO2 material = new MaterialBase(simconf, 10.0); // rho element._Z = 92; // U element._m = 235.0; element._t = 1.0; material->_element.push_back(element); element._Z = 16; // O element._m = 32.0; element._t = 2.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample // xe bubble material = new MaterialBase(simconf, 3.5); // rho element._Z = 54; // Xe element._m = 132.0; element._t = 1.0; // element._t = 0.002; material->_element.push_back(element); material->prepare(); sample->material.push_back(material); // add material to sample // sample->material.push_back(material); // add material to sample // create a FIFO for recoils std::queue<IonBase *> recoils; Real norm; Point dif, dif2; MassInverter * m = new MassInverter; EnergyInverter * e = new EnergyInverter; Real A1, A2, Etot, E1, E2; int Z1, Z2; snprintf(fname, 199, "%s.Erec", argv[1]); FILE * erec = fopen(fname, "wt"); snprintf(fname, 199, "%s.dist", argv[1]); FILE * rdist = fopen(fname, "wt"); Point pos1, pos2; IonMDTag *ff1, *ff2, *pka; // 1000 fission events for (int n = 0; n < 1000; n++) // 2000 ff { if (n % 10 == 0) fprintf(stderr, "pka #%d\n", n + 1); ff1 = new IonMDTag; ff1->_gen = 0; // generation (0 = PKA) ff1->_tag = -1; ff1->_md = 0; ff1->_id = simconf->_id++; // generate fission fragment data A1 = m->x(simconf->drand()); // A1 = 131; A2 = 235.0 - A1; Etot = e->x(simconf->drand()); E1 = Etot * A2 / (A1 + A2); // E1 = 100; E2 = Etot - E1; Z1 = round((A1 * 92.0) / 235.0); // Z1 = 54; Z2 = 92 - Z1; ff1->_Z = Z1; ff1->_m = A1; ff1->_E = E1 * 1.0e6; // ff1->_Z = 53; // ff1->_m = 127; // ff1->_E = 70.0 * 1.0e6; do { for (int i = 0; i < 3; ++i) ff1->_dir(i) = simconf->drand() - 0.5; norm = ff1->_dir.norm_sq(); } while (norm <= 0.0001 || norm > 0.25); /* norm = 1.0; ff1->_dir(0) = 1.0; ff1->_dir(1) = 0.0; ff1->_dir(2) = 0.0; */ ff1->_dir /= std::sqrt(norm); // random origin (outside cluster!) do { for (int i = 0; i < 3; ++i) ff1->_pos(i) = simconf->drand() * sample->w[i]; } while (sample->lookupCluster(ff1->_pos) >= 0); ff1->setEf(); recoils.push(ff1); ff2 = new IonMDTag(*ff1); // copy constructor // ff1->_id = simconf->_id++; // reverse direction ff2->_dir = -ff2->_dir; ff2->_Z = Z2; ff2->_m = A2; ff2->_E = E2 * 1.0e6; ff2->setEf(); recoils.push(ff2); // fprintf(stderr, "A1=%f Z1=%d (%f MeV)\tA2=%f Z2=%d (%f MeV)\n", A1, Z1, E1, A2, Z2, E2); while (!recoils.empty()) { pka = dynamic_cast<IonMDTag *>(recoils.front()); recoils.pop(); sample->averages(pka); // do ion analysis/processing BEFORE the cascade here if (pka->_Z == 54) { // mark the first recoil that falls into the MD energy gap with 1 (child generations // increase the number) if (pka->_E > 200 && pka->_E < 12000 && pka->_md == 0) pka->_md = 1; if (pka->_gen > 0) { // output energy and recoil generation fprintf(erec, "%f\t%d\t%d\n", pka->_E, pka->_gen, pka->_md); } if (pka->_tag >= 0) { for (int i = 0; i < 3; ++i) { dif(i) = sample->c[i][pka->_tag] - pka->_pos(i); pos2(i) = pka->_pos(i); if (sample->bc[i] == SampleBase::PBC) dif(i) -= round(dif(i) / sample->w[i]) * sample->w[i]; pos1(i) = pka->_pos(i) + dif(i); // printf("%f\t%f\t%f\n", sample->c[i][pka->_tag], pka->_pos(i), pos1(i)); } // printf("\n"); // if (pka->_Z == 54 && pka->_gen > 0 && pka->_tag >= 0) printf("clust %f %f %f %d", // pos1[0], pos1[1], pos1[2], pka->_id); } } // follow this ion's trajectory and store recoils // printf("%f\t%d\n", pka->_E, pka->_Z); // pka->_md = id++; // printf("\nstart %f %f %f %d %d %d\n", pka->_pos(0), pka->_pos(1), pka->_pos(2), pka->_Z, // pka->_md, pka->_id); trim->trim(pka, recoils); // fprintf(phon, "%f %f %f %f %d %d\n", pka->_E, pka->_pos(0), pka->_pos(1), pka->_pos(2), // pka->_Z, pka->_id); // do ion analysis/processing AFTER the cascade here // pka is Xe if (pka->_Z == 54) { // output // printf("%f %f %f %d\n", pka->_pos(0), pka->_pos(1), pka->_pos(2), pka->_tag); // print out distance to cluster of origin center (and depth of recoil) if (pka->_tag >= 0) { dif = pos1 - pka->_pos; // distance to cluster center dif2 = pos2 - pka->_pos; // total distance it moved fprintf(rdist, "%f %d %f %f %f %f\n", dif.norm(), pka->_md, pka->_pos(0), pka->_pos(1), pka->_pos(2), dif2.norm()); } // do a random walk /* jumps = 0; do { material = sample->lookupLayer(pka->_pos); if (material->_tag >= 0) break; do { for (int i = 0; i < 3; ++i) pka->_dir(i) = simconf->drand() - 0.5; norm = v_dot(pka->_dir, pka->_dir); } while (norm <= 0.0001); v_scale(pka->_dir, jmp / std::sqrt(norm)); for (int i = 0; i < 3; ++i) pka->_pos(i) += pka->_dir(i); jumps++; } while (pka->_pos(0) > 0 && pka->_pos(0) < sample->w[0]); if (material->_tag >= 0 && jumps > 0) fprintf(stderr, "walked to cluster %d (originated at %d, %d jumps)\n", material->_tag, pka->_tag, jumps); */ } // done with this recoil delete pka; // this should rather be done with spawnRecoil returning false // if (simconf->primariesOnly) while (!recoils.empty()) { delete recoils.front(); // recoils.pop(); }; } } fclose(rdist); fclose(erec); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { char fname[200]; if (argc != 4) // 2 { fprintf(stderr, "syntax:\nmytrim_ODS basename r Cbfactor\n\nCbfactor=1 => 1.5e-4 clusters/nm^3\n"); return 1; } // seed randomnumber generator from system entropy pool FILE *urand = fopen("/dev/random", "r"); int seed; if (fread(&seed, sizeof(int), 1, urand) != 1) return 1; fclose(urand); r250_init(seed<0 ? -seed : seed); // random generator goes haywire with neg. seed // initialize global parameter structure and read data tables from file SimconfType * simconf = new SimconfType; simconf->fullTraj = false; simconf->tmin = 0.2; //simconf->tmin = 0.2; // initialize sample structure [] //sampleClusters *sample = new sampleClusters(50000.0, 400.0, 400.0); sampleClusters *sample = new sampleClusters(500.0, 1000.0, 1000.0); // initialize trim engine for the sample snprintf(fname, 199, "%s.phon", argv[1]); //FILE *phon = fopen(fname, "wt"); //TrimPhononOut *trim = new TrimPhononOut(sample, phon); TrimBase *trim = new TrimBase(simconf, sample); //TrimBase *trim = new TrimPrimaries(sample); //Real r = 10.0; Real r = atof(argv[2]); //10.0; Real Cbf = atof(argv[3]); sample->bc[0] = SampleBase::INF; // no PBC in x (just clusterless matrix) sample->initSpatialhash(int(sample->w[0] / r) - 1, int(sample->w[1] / r) - 1, int(sample->w[2] / r) - 1); // Real atp = 0.1; // 10at% Mo 90at%Cu Real v_sam = sample->w[0] * sample->w[1] * sample->w[2]; //Real v_cl = 4.0/3.0 * M_PI * cub(r); int n_cl; // = atp * scoef[29-1].atrho * v_sam / (v_cl * ((1.0 - atp) * scoef[42-1].atrho + atp * scoef[29-1].atrho)); n_cl = v_sam * 1.5e-7 * Cbf ; // Allen08 1.5e-4/nm^3 //fprintf(stderr, "adding %d clusters to reach %fat%% Mo\n", n_cl, atp * 100.0); // cluster surfaces must be at least 25.0 Ang apart fprintf(stderr, "adding %d clusters...\n", n_cl); sample->addRandomClusters(n_cl, r, 15.0); // write cluster coords with tag numbers snprintf(fname, 199, "%s.clcoor", argv[1]); FILE *ccf = fopen(fname, "wt"); for (int i = 0; i < sample->cn; ++i) fprintf(ccf, "%f %f %f %f %d\n", sample->c[0][i], sample->c[1][i], sample->c[2][i], sample->c[3][i], i); fclose(ccf); fprintf(stderr, "sample built.\n"); //return 0; MaterialBase *material; ElementBase *element; /* // Fe material = new MaterialBase(7.87); // rho element = new ElementBase; element->_Z = 26; // Fe element->_m = 56.0; element->_t = 1.0; element->_Edisp = 40.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample */ // Cu material = new MaterialBase(simconf, 8.94); // rho element = new ElementBase; element->_Z = 29; // Fe element->_m = 63.0; element->_t = 1.0; element->_Edisp = 40.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample /* // ZrO2 material = new MaterialBase(5.68); // rho element = new ElementBase; element->_Z = 40; // Zr element->_m = 91.0; element->_t = 1.0; material->_element.push_back(element); element = new ElementBase; element->_Z = 8; // O element->_m = 16.0; element->_t = 2.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample // TiO2 precipitate material = new MaterialBase(4.23); // rho element = new ElementBase; element->_Z = 22; // Ti element->_m = 48.0; element->_t = 1.0; material->_element.push_back(element); element = new ElementBase; element->_Z = 8; // O element->_m = 16.0; element->_t = 2.0; material->_element.push_back(element); material->prepare(); sample->material.push_back(material); // add material to sample // Y2Ti2O7 precipitate material = new MaterialBase(4.6); // rho between 4.23 and 5.01 element = new ElementBase; element->_Z = 39; // Y element->_m = 89.0; element->_t = 2.0; element->_Edisp = 57.0; material->_element.push_back(element); element = new ElementBase; element->_Z = 22; // Ti element->_m = 48.0; element->_t = 2.0; element->_Edisp = 57.0; material->_element.push_back(element); element = new ElementBase; element->_Z = 8; // O element->_m = 16.0; element->_t = 7.0; element->_Edisp = 57.0; material->_element.push_back(element); material->prepare(); sample->material.push_back(material); // add material to sample */ /* // xe bubble material = new MaterialBase(3.5); // rho element = new ElementBase; element->_Z = 54; // Xe element->_m = 132.0; element->_t = 1.0; material->_element.push_back(element); material->prepare(); sample->material.push_back(material); // add material to sample */ // TiB2 precipitate material = new MaterialBase(simconf, 4.52); // rho element = new ElementBase; element->_Z = 22; // Ti element->_m = 48.0; element->_t = 1.0; material->_element.push_back(element); element = new ElementBase; element->_Z = 5; // B element->_m = 11.0; element->_t = 2.0; material->_element.push_back(element); material->prepare(); sample->material.push_back(material); // add material to sample const int nstep = 1000; // create a FIFO for recoils std::queue<IonBase*> recoils; Real dif[3], dif2[3]; snprintf(fname, 199, "%s.Erec", argv[1]); FILE *erec = fopen(fname, "wt"); snprintf(fname, 199, "%s.dist", argv[1]); FILE *rdist = fopen(fname, "wt"); Real pos1[3], pos2[3]; IonMDTag *ff1, *pka; Real A = 84.0, E = 1.8e6; int Z = 36; // 1.8MeV Kr //Real A = 58.0, E = 5.0e6; int Z = 28; // 5MeV Ni //Real A = 56.0, E = 5.0e6; int Z = 26; // 5MeV Fe // 1000 ions for (int n = 0; n < nstep; n++) { if (n % 10 == 0) fprintf(stderr, "pka #%d\n", n+1); ff1 = new IonMDTag; ff1->gen = 0; // generation (0 = PKA) ff1->tag = -1; ff1->_md = 0; ff1->id = simconf->id++; ff1->_Z = Z; ff1->_m = A; ff1->_E = E; ff1->_dir(0) = 1; ff1->_dir(1) = 0; ff1->_dir(2) = 0; ff1->_pos(0) = 0; ff1->_pos(1) = sample->w[1] / 2.0; ff1->_pos(2) = sample->w[2] / 2.0; ff1->setEf(); recoils.push(ff1); while (!recoils.empty()) { pka = dynamic_cast<IonMDTag*>(recoils.front()); recoils.pop(); sample->averages(pka); // do ion analysis/processing BEFORE the cascade here //fprintf(erec, "%f\t%d\t%d\n", pka->_E, pka->gen, pka->_md); // pka is O or Ti //if (pka->_Z == 8 || pka->_Z == 22 || pka->_Z == 39) // pka is Xe //if (pka->_Z == 54) // pka is B or Ti if (pka->_Z == 5 || pka->_Z == 22) { if (pka->gen > 0) { // output energy and recoil generation fprintf(erec, "%f\t%d\t%d\n", pka->_E, pka->gen, pka->_md); } if (pka->tag >= 0) { for (int i = 0; i < 3; ++i) { dif[i] = sample->c[i][pka->tag] - pka->_pos(i); pos2[i] = pka->_pos(i); if (sample->bc[i] == SampleBase::PBC) dif[i] -= round(dif[i] / sample->w[i]) * sample->w[i]; pos1[i] = pka->_pos(i) + dif[i]; //printf("%f\t%f\t%f\n", sample->c[i][pka->tag], pka->_pos(i), pos1[i]); } //printf("\n"); //if (pka->_Z == 54 && pka->gen > 0 && pka->tag >= 0) printf("clust %f %f %f %d", pos1[0], pos1[1], pos1[2], pka->id); } } // follow this ion's trajectory and store recoils // printf("%f\t%d\n", pka->_E, pka->_Z); //pka->_md = id++; trim->trim(pka, recoils); // do ion analysis/processing AFTER the cascade here // pka is O or Ti //if (pka->_Z == 8 || pka->_Z == 22 || pka->_Z == 39) // pka is Xe //if (pka->_Z == 54) // pka is B or Ti if (pka->_Z == 5 || pka->_Z == 22) { // output //printf("%f %f %f %d\n", pka->_pos(0), pka->_pos(1), pka->_pos(2), pka->tag); // print out distance to cluster of origin center (and depth of recoil) if (pka->tag >= 0) { for (int i = 0; i < 3; ++i) { dif[i] = pos1[i] - pka->_pos(i); // distance to cluster center dif2[i] = pos2[i] - pka->_pos(i); // total distance it moved } fprintf(rdist, "%f %d %f %f %f %f\n", std::sqrt(v_dot(dif, dif)), pka->_Z, pka->_pos(0), pka->_pos(1), pka->_pos(2), std::sqrt(v_dot(dif2, dif2))); } // do a random walk /* jumps = 0; do { material = sample->lookupLayer(pka->_pos); if (material->tag >= 0) break; do { for (int i = 0; i < 3; ++i) pka->_dir(i) = dr250() - 0.5; norm = v_dot(pka->_dir, pka->_dir); } while (norm <= 0.0001); v_scale(pka->_dir, jmp / std::sqrt(norm)); for (int i = 0; i < 3; ++i) pka->_pos(i) += pka->_dir(i); jumps++; } while (pka->_pos(0) > 0 && pka->_pos(0) < sample->w[0]); if (material->tag >= 0 && jumps > 0) fprintf(stderr, "walked to cluster %d (originated at %d, %d jumps)\n", material->tag, pka->tag, jumps); */ } // done with this recoil delete pka; // this should rather be done with spawnRecoil returning false //if (simconf->primariesOnly) while (!recoils.empty()) { delete recoils.front(); recoils.pop(); }; } } fclose(rdist); fclose(erec); // output full damage data printf("%d vacancies per %d ions = %d vac/ion\n", simconf->vacancies_created, nstep, simconf->vacancies_created/nstep); /* // calculate modified kinchin pease data http://www.iue.tuwien.ac.at/phd/hoessinger/node47.html // just for the PKA Real Zatoms = 26.0, Matoms = 56.0; Real Epka = 5.0e6; Real ed = 0.0115 * std::pow(Zatoms, -7.0/3.0) * Epka; Real g = 3.4008 * std::pow(ed, 1.0/6.0) + 0.40244 * std::pow(ed, 3.0/4.0) + ed; Real kd = 0.1337 * std::pow(Zatoms, 2.0/3.0) / std::pow(Matoms, 0.5); //Z, M Real Ev = Epka / (1.0 + kd * g); Real Ed = 40.0; printf("%f modified PKA kinchin-pease vacancies per 100 ions = %f vac/ion\n", 100*0.8*Ev/(2.0*Ed), 0.8*Ev/(2.0*Ed)); // do Kinchin-Pease for all primary recoils printf("%f modified 1REC kinchin-pease vacancies per 100 ions = %f vac/ion\n", simconf->KP_vacancies, simconf->KP_vacancies / 100.0); */ return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { if (argc != 8) { std::cerr << "syntax: " << argv[0] << " basename angle[deg] diameter(nm) burried[0, 1] numbermultiplier xyzout[0, 1] lbinout[0, 1]" << std::endl; return 1; } Real theta = atof(argv[2]) * M_PI/180.0; // 0 = parallel to wire Real diameter = 10.0*atof(argv[3]); Real length = 11000.0; // 1.1 mu bool burried = (atoi(argv[4]) != 0); Real mult = atof(argv[5]); bool xyz_out = (atoi(argv[6]) != 0); bool ldat_out = (atoi(argv[7]) != 0); // ion series const int nstep = 5; Real ion_dose[nstep] = { 3.0e13, 2.2e13, 1.5e13, 1.2e13, 2.5e13 }; // in ions/cm^2 int ion_count[nstep]; IonBase* ion_prototype[nstep]; ion_prototype[0] = new IonBase( 5, 11.0 , 320.0e3); // Z, m, E ion_prototype[1] = new IonBase( 5, 11.0 , 220.0e3); // Z, m, E ion_prototype[2] = new IonBase( 5, 11.0 , 160.0e3); // Z, m, E ion_prototype[3] = new IonBase( 5, 11.0 , 120.0e3); // Z, m, E ion_prototype[4] = new IonBase(15, 31.0 , 250.0e3); // Z, m, E // seed randomnumber generator from system entropy pool FILE *urand = fopen("/dev/random", "r"); int seed; if (fread(&seed, sizeof(int), 1, urand) != 1) return 1; fclose(urand); r250_init(seed<0 ? -seed : seed); // random generator goes haywire with neg. seed // initialize global parameter structure and read data tables from file SimconfType * simconf = new SimconfType; //simconf->fullTraj = true; // initialize sample structure SampleWire *sample; if (burried) sample = new SampleBurriedWire(diameter, diameter, length); else { sample = new SampleWire(diameter, diameter, length); sample->bc[2] = SampleWire::CUT; } // calculate actual ion numbers for (int s = 0; s < nstep; ++s) { Real A; // irradiated area in Ang^2 if (burried) A =(length + sample->w[0]) * (length + sample->w[1]); else A = cos(theta) * M_PI * 0.25 * sample->w[0] * sample->w[1] + // slanted top face sin(theta) * length * sample->w[0]; // + projected side // 1cm^2 = 1e16 Ang**2, 1Ang^2 = 1e-16cm^2 ion_count[s] = ion_dose[s] * A * 1.0e-16 * mult; std::cerr << "Ion " << s << ' ' << ion_count[s] << std::endl; } // initialize trim engine for the sample /* const int z1 = 31; const int z2 = 33; TrimVacMap *trim = new TrimVacMap(sample, z1, z2); // GaAs */ //TrimBase *trim = new TrimBase(sample); TrimBase *trim = new TrimPrimaries(simconf, sample); MaterialBase *material; ElementBase *element; // Si material = new MaterialBase(simconf, 2.329); // rho element = new ElementBase; element->_Z = 14; // Si element->_m = 28.0; element->_t = 1.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample // SiO2 (material[1] for the cover layer in SampleBurriedWire) material = new MaterialBase(simconf, 2.634); // rho element = new ElementBase; element->_Z = 14; // Si element->_m = 28.0; element->_t = 1.0; material->_element.push_back(element); element = new ElementBase; element->_Z = 8; // O element->_m = 16.0; element->_t = 2.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample // create a FIFO for recoils std::queue<IonBase*> recoils; IonBase *pka; // map concentration along length int *lbins[2]; int lx = 100; // 100 bins int dl = length/Real(lx); lbins[1] = new int[lx]; // P z=15 for (int i = 0; i < 2; ++i) { lbins[i] = new int[lx]; // 0=B (z=5), 1=P (z=15) for (int l = 0; l < lx; ++l) lbins[i][l] = 0; } // xyz data int xyz_lines = 0; std::stringstream xyz_data; for (int s = 0; s < nstep; ++s) { for (int n = 0; n < ion_count[s]; ++n) { if (n % 10000 == 0) std::cerr << "pka #" << n+1 << std::endl; // generate new PKA from prototype ion pka = new IonBase(ion_prototype[s]); pka->gen = 0; // generation (0 = PKA) pka->tag = -1; pka->_dir(0) = 0.0; pka->_dir(1) = sin(theta); pka->_dir(2) = cos(theta); v_norm(pka->_dir); if (burried) { // cannot anticipate the straggling in the burrial layer, thus have to shoot onto a big surface // TODO: take theta into account! pka->_pos(0) = (dr250() - 0.5) * (length + sample->w[0]); pka->_pos(1) = (dr250() - 0.5) * (length + sample->w[1]); pka->_pos(2) = -250.0; // overcoat thickness } else { if (theta == 0.0) { // 0 degrees => start on top of wire! pka->_pos(2) = 0.0; do { pka->_pos(0) = dr250() * sample->w[0]; pka->_pos(1) = dr250() * sample->w[1]; } while (sample->lookupMaterial(pka->_pos) == 0); } else { // start on side _or_ top! Real vpos[3], t; do { do { vpos[0] = dr250() * sample->w[0]; vpos[1] = 0.0; vpos[2] = (dr250() * (length + diameter/tan(theta))) - diameter/tan(theta); t = (1.0 - std::sqrt(1.0 - sqr(2*vpos[0]/diameter - 1.0))) * diameter/(2.0*pka->_dir(1)); // if we start beyond wire length (that would be inside the substrate) then retry } while (t*pka->_dir(2) + vpos[2] >= length); // if first intersection with cylinder is at z<0 then check if we hit the top face instead if (t*pka->_dir(2) + vpos[2] < 0.0) t = -vpos[2]/pka->_dir(2); // start PKA at calculated intersection point for (int i = 0; i < 3; ++i) pka->_pos(i) = t*pka->_dir(i) + vpos[i]; } while (sample->lookupMaterial(pka->_pos) == 0); } } //cout << "START " << pka->_pos(0) << ' ' << pka->_pos(1) << ' ' << pka->_pos(2) << ' ' << std::endl; //continue; pka->setEf(); recoils.push(pka); while (!recoils.empty()) { pka = recoils.front(); recoils.pop(); sample->averages(pka); // do ion analysis/processing BEFORE the cascade here if (pka->_Z == ion_prototype[s]->_Z ) { //printf( "p1 %f\t%f\t%f\n", pka->_pos(0), pka->_pos(1), pka->_pos(2)); } // follow this ion's trajectory and store recoils trim->trim(pka, recoils); // do ion analysis/processing AFTER the cascade here // ion is in the wire if ( sample->lookupMaterial(pka->_pos) == sample->material[0]) { int l = pka->_pos(2) / dl; if (l >=0 && l < lx) { if (xyz_out) { xyz_data << simconf->scoef[pka->_Z-1].sym << ' ' << pka->_pos(0)/100.0 << ' ' << pka->_pos(1)/100.0 << ' ' << pka->_pos(2)/100.0 << std::endl; xyz_lines++; } if (ldat_out) lbins[ (pka->_Z == 5) ? 0 : 1 ][l]++; } } // done with this recoil delete pka; } } } // write xyz file if (xyz_out) { std::stringstream xyz_name; xyz_name << argv[1] << ".xyz"; std::ofstream xyz(xyz_name.str().c_str()); xyz << xyz_lines << std::endl << std::endl << xyz_data.str(); xyz.close(); } // write lbins file (atoms per nm^3) if (ldat_out) { std::stringstream ldat_name; ldat_name << argv[1] << ".ldat"; std::ofstream ldat(ldat_name.str().c_str()); Real dv = 1e-3 * dl * M_PI * 0.25 *sample->w[0] * sample->w[1]; // volume per bin in nm^3 for (int l = 0; l < lx; ++l) ldat << l*dl << ' ' << lbins[0][l]/(mult*dv) << ' ' << lbins[1][l]/(mult*dv) << std::endl; ldat.close(); } delete[] lbins[0]; delete[] lbins[1]; return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { char fname[200]; if (argc != 8) { fprintf(stderr, "syntax:\n%s basename Eion[eV] angle[deg] numpka zpka mpka r[nm]\n", argv[0]); return 1; } Real epka = atof(argv[2]); Real theta = atof(argv[3]) * M_PI/180.0; // 0 = perpendicular to wire int numpka = atoi(argv[4]); int zpka = atoi(argv[5]); Real mpka = atof(argv[6]); Real dwire = atof(argv[7])*20.0; // seed randomnumber generator from system entropy pool FILE *urand = fopen("/dev/random", "r"); int seed; if (fread(&seed, sizeof(int), 1, urand) != 1) return 1; fclose(urand); r250_init(seed<0 ? -seed : seed); // random generator goes haywire with neg. seed // initialize global parameter structure and read data tables from file SimconfType * simconf = new SimconfType; // initialize sample structure SampleWire *sample = new SampleWire(dwire, dwire, 100.0); // initialize trim engine for the sample const int z1 = 29; //Cu const int z2 = 22; //Ti const int z3 = 47; //Ag TrimVacMap *trim = new TrimVacMap(simconf, sample, z1, z2, z3); // GaCW MaterialBase *material; ElementBase *element; material = new MaterialBase(simconf, (56.0*8.920 + 38.0*4.507 + 8.0*10.490)/(56.0+38.0+8.0)); // rho element = new ElementBase; element->_Z = z1; // Cu element->_m = 63.546; element->_t = 56.0; material->_element.push_back(element); element = new ElementBase; element->_Z = z2; // Ti element->_m = 47.867; element->_t = 38.0; material->_element.push_back(element); element = new ElementBase; element->_Z = z3; // Ag element->_m = 107.87; element->_t = 8.0; material->_element.push_back(element); material->prepare(); // all materials added sample->material.push_back(material); // add material to sample // create a FIFO for recoils std::queue<IonBase*> recoils; IonBase *pka; const int mx = 20, my = 20; int imap[mx][my][3]; for (int e = 0; e < 3; e++) for (int x = 0; x < mx; x++) for (int y = 0; y < my; y++) imap[x][y][e] = 0; // 10000 ions for (int n = 0; n < numpka; n++) { if (n % 1000 == 0) fprintf(stderr, "pka #%d\n", n+1); pka = new IonBase; pka->gen = 0; // generation (0 = PKA) pka->tag = -1; pka->_Z = zpka; // S pka->_m = mpka; pka->_E = epka; pka->_dir(0) = 0.0; pka->_dir(1) = -cos(theta); pka->_dir(2) = sin(theta); v_norm(pka->_dir); pka->_pos(0) = dr250() * sample->w[0]; pka->_pos(2) = dr250() * sample->w[2]; // wire surface pka->_pos(1) = sample->w[1] / 2.0 * (1.0 + std::sqrt(1.0 - sqr((pka->_pos(0) / sample->w[0]) * 2.0 - 1.0))) - 0.5; pka->setEf(); recoils.push(pka); while (!recoils.empty()) { pka = recoils.front(); recoils.pop(); sample->averages(pka); // do ion analysis/processing BEFORE the cascade here if (pka->_Z == zpka ) { //printf( "p1 %f\t%f\t%f\n", pka->_pos(0), pka->_pos(1), pka->_pos(2)); } // follow this ion's trajectory and store recoils // printf("%f\t%d\n", pka->_E, pka->_Z); trim->trim(pka, recoils); // do ion analysis/processing AFTER the cascade here // ion is still in sample if ( sample->lookupMaterial(pka->_pos) != 0) { int x, y; x = ((pka->_pos(0) * mx) / sample->w[0]); y = ((pka->_pos(1) * my) / sample->w[1]); x -= int(x/mx) * mx; y -= int(y/my) * my; // keep track of interstitials for the two constituents if (pka->_Z == z1) imap[x][y][0]++; else if (pka->_Z == z2) imap[x][y][1]++; else if (pka->_Z == z3) imap[x][y][2]++; } // done with this recoil delete pka; } } const char *elnam[3] = { "Cu", "Ti", "Ag" }; FILE *intf, *vacf, *netf; // e<numberofelementsinwire for (int e = 0; e < 3; e++) { snprintf(fname, 199, "%s.%s.int", argv[1], elnam[e]); intf = fopen(fname, "wt"); snprintf(fname, 199, "%s.%s.vac", argv[1], elnam[e]); vacf = fopen(fname, "wt"); snprintf(fname, 199, "%s.%s.net", argv[1], elnam[e]); netf = fopen(fname, "wt"); for (int y = 0; y <= my; y++) { for (int x = 0; x <= mx; x++) { Real x1 = Real(x)/Real(mx)*sample->w[0]; Real y1 = Real(y)/Real(my)*sample->w[1]; fprintf(intf, "%f %f %d\n", x1, y1, (x<mx && y<my) ? imap[x][y][e] : 0); fprintf(vacf, "%f %f %d\n", x1, y1, (x<mx && y<my) ? trim->vmap[x][y][e] : 0); fprintf(netf, "%f %f %d\n", x1, y1, (x<mx && y<my) ? (imap[x][y][e] - trim->vmap[x][y][e]) : 0); } fprintf(intf, "\n"); fprintf(vacf, "\n"); fprintf(netf, "\n"); } fclose(intf); fclose(vacf); fclose(netf); } return EXIT_SUCCESS; }