Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}