/* compute function */
static int compute(void* km)
{
   /* local variables */
   intptr_t* pkim = *((intptr_t**) km);
   double R;
   double Rsqij;
   double phi;
   double dphi;
   double Rij[DIM];
   int ier;
   int i;
   int j;
   int k;
   int comp_energy;
   int comp_force;
   int comp_particleEnergy;
   int comp_virial;

   int* nAtoms;
   int* particleTypes;
   double* cutoff;
   double* epsilon;
   double* sigma;
   double* A;
   double* B;
   double* C;
   double* cutsq;
   double* coords;
   double* energy;
   double* force;
   double* particleEnergy;
   double* virial;

   /* check to see if we have been asked to compute the forces, particleEnergy, and virial */
   KIM_API_getm_compute(pkim, &ier, 4*3,
                        "energy",         &comp_energy,         1,
                        "forces",         &comp_force,          1,
                        "particleEnergy", &comp_particleEnergy, 1,
                        "virial",         &comp_virial,         1);
   if (KIM_STATUS_OK > ier)
   {
      KIM_API_report_error(__LINE__, __FILE__, "KIM_API_getm_compute", ier);
      return ier;
   }

   /* unpack data from KIM object */
   KIM_API_getm_data(pkim, &ier, 7*3,
                     "numberOfParticles", &nAtoms,         1,
                     "particleTypes",     &particleTypes,  1,
                     "energy",            &energy,         comp_energy,
                     "coordinates",       &coords,         1,
                     "forces",            &force,          comp_force,
                     "particleEnergy",    &particleEnergy, comp_particleEnergy,
                     "virial",            &virial,         comp_virial);
   if (KIM_STATUS_OK > ier)
   {
      KIM_API_report_error(__LINE__, __FILE__, "KIM_API_getm_data", ier);
      return ier;
   }

   /* unpack the Model's parameters stored in the KIM API object */
   KIM_API_getm_data(pkim, &ier, 7*3,
                     "cutoff",             &cutoff,  1,
                     "PARAM_FREE_epsilon", &epsilon, 1,
                     "PARAM_FREE_sigma",   &sigma,   1,
                     "PARAM_FIXED_A",      &A,       1,
                     "PARAM_FIXED_B",      &B,       1,
                     "PARAM_FIXED_C",      &C,       1,
                     "PARAM_FIXED_cutsq",  &cutsq,   1);
   if (KIM_STATUS_OK > ier)
   {
      KIM_API_report_error(__LINE__, __FILE__, "KIM_API_getm_data", ier);
      return ier;
   }

   /* Check to be sure that the atom types are correct */
   /**/
   ier = KIM_STATUS_FAIL; /* assume an error */
   for (i = 0; i < *nAtoms; ++i)
   {
      if ( SPECCODE != particleTypes[i])
      {
         KIM_API_report_error(__LINE__, __FILE__, "Unexpected species type detected", ier);
         return ier;
      }
   }
   ier = KIM_STATUS_OK; /* everything is ok */

   /* initialize potential energies, forces, and virial term */
   if (comp_particleEnergy)
   {
      for (i = 0; i < *nAtoms; ++i)
      {
         particleEnergy[i] = 0.0;
      }
   }
   if (comp_energy)
   {
      *energy = 0.0;
   }

   if (comp_force)
   {
      for (i = 0; i < *nAtoms; ++i)
      {
         for (k = 0; k < DIM; ++k)
         {
            force[i*DIM + k] = 0.0;
         }
      }
   }

   if (comp_virial)
   {
      for (i = 0; i < 6; ++i)
      {
         virial[i] = 0.0;
      }
   }

   /* Compute energy and forces */

   /* We'll use a half list approach                                  */
   /* Don't need to consider the last atom since all its interactions */
   /* are accounted for eariler in the loop                           */
   for (i = 0; i < *nAtoms-1; ++i)
   {
      for (j = i+1; j < *nAtoms; ++j)
      {
         /* compute relative position vector and squared distance */
         Rsqij = 0.0;
         for (k = 0; k < DIM; ++k)
         {
            Rij[k] = coords[j*DIM + k] - coords[i*DIM + k];

            /* compute squared distance */
            Rsqij += Rij[k]*Rij[k];
         }

         /* compute energy and force */
         if (Rsqij < *cutsq) /* particles are interacting ? */
         {
            R = sqrt(Rsqij);
            if (comp_force || comp_virial)
            {
               /* compute pair potential and its derivative */
               calc_phi_dphi(cutoff, epsilon, sigma, A, B, C, R, &phi, &dphi);
            }
            else
            {
               /* compute just pair potential */
               calc_phi(cutoff, epsilon, sigma, A, B, C, R, &phi);
            }

            /* contribution to energy */
            if (comp_particleEnergy)
            {
               particleEnergy[i] += 0.5*phi;
               particleEnergy[j] += 0.5*phi;
            }
            if (comp_energy)
            {
               *energy += phi;
            }

            /* contribution to virial tensor */
            if (comp_virial)
            {
               /* virial(i,j) = r(i)*r(j)*(dV/dr)/r */
               virial[0] += Rij[0]*Rij[0]*dphi/R;
               virial[1] += Rij[1]*Rij[1]*dphi/R;
               virial[2] += Rij[2]*Rij[2]*dphi/R;
               virial[3] += Rij[1]*Rij[2]*dphi/R;
               virial[4] += Rij[0]*Rij[2]*dphi/R;
               virial[5] += Rij[0]*Rij[1]*dphi/R;
            }

            /* contribution to forces */
            if (comp_force)
            {
               for (k = 0; k < DIM; ++k)
               {
                  force[i*DIM + k] += dphi*Rij[k]/R; /* accumulate force on atom i */
                  force[j*DIM + k] -= dphi*Rij[k]/R; /* accumulate force on atom j */
               }
            }
         }
      } /* loop on j */
   }    /* loop on i */

   /* everything is great */
   ier = KIM_STATUS_OK;
   return ier;
}
/* compute function */
static int compute(void* km)
{
   /* local variables */
   intptr_t* pkim = *((intptr_t**) km);
   double R;
   double Rsqij;
   double phi;
   double dphi;
   double dEidr = 0.0;
   double Rij[DIM];
   int ier;
   int i;
   int j;
   int jj;
   int k;
   int numOfPartNeigh;
   int currentPart;
   int comp_energy;
   int comp_force;
   int comp_particleEnergy;
   int comp_virial;
   int IterOrLoca;
   int HalfOrFull;
   int NBC;
   const char* NBCstr;
   int numberContrib;

   int* nParts;
   int* particleSpecies;
   double* Rij_list;
   double* coords;
   double* energy;
   double* force;
   double* particleEnergy;
   double* virial;
   int* neighListOfCurrentPart;
   double* boxSideLengths;
   int* numContrib;


   /* Determine neighbor list boundary condition (NBC) */
   /* and half versus full mode: */
   /*****************************
    * HalfOrFull = 1 -- Half
    *            = 2 -- Full
    *****************************/
   ier = KIM_API_get_NBC_method(pkim, &NBCstr);
   if (KIM_STATUS_OK > ier)
   {
      KIM_API_report_error(__LINE__, __FILE__, "KIM_API_get_NBC_method", ier);
      return ier;
   }
   if (!strcmp("NEIGH_RVEC_H",NBCstr))
   {
      NBC = 0;
      HalfOrFull = 1;
   }
   else if (!strcmp("NEIGH_PURE_H",NBCstr))
   {
      NBC = 1;
      HalfOrFull = 1;
   }
   else if (!strcmp("NEIGH_RVEC_F",NBCstr))
   {
      NBC = 0;
      HalfOrFull = 2;
   }
   else if (!strcmp("NEIGH_PURE_F",NBCstr))
   {
      NBC = 1;
      HalfOrFull = 2;
   }
   else if (!strcmp("MI_OPBC_H",NBCstr))
   {
      NBC = 2;
      HalfOrFull = 1;
   }
   else if (!strcmp("MI_OPBC_F",NBCstr))
   {
      NBC = 2;
      HalfOrFull = 2;
   }
   else if (!strcmp("CLUSTER",NBCstr))
   {
      NBC = 3;
      HalfOrFull = 1;
   }
   else
   {
      ier = KIM_STATUS_FAIL;
      KIM_API_report_error(__LINE__, __FILE__, "Unknown NBC method", ier);
      return ier;
   }

   /* determine neighbor list handling mode */
   if (NBC != 3)
   {
      /*****************************
       * IterOrLoca = 1 -- Iterator
       *            = 2 -- Locator
       *****************************/
      IterOrLoca = KIM_API_get_neigh_mode(pkim, &ier);
      if (KIM_STATUS_OK > ier)
      {
         KIM_API_report_error(__LINE__, __FILE__, "KIM_API_get_neigh_mode", ier);
         return ier;
      }
      if ((IterOrLoca != 1) && (IterOrLoca != 2))
      {
         printf("* ERROR: Unsupported IterOrLoca mode = %i\n", IterOrLoca);
         return KIM_STATUS_FAIL;
      }
   }
   else
   {
      IterOrLoca = 2;   /* for CLUSTER NBC */
   }

   /* check to see if we have been asked to compute the forces, particleEnergy, energy and virial */
   KIM_API_getm_compute(pkim, &ier, 4*3,
                        "energy",         &comp_energy,         1,
                        "forces",         &comp_force,          1,
                        "particleEnergy", &comp_particleEnergy, 1,
                        "virial",         &comp_virial,         1);
   if (KIM_STATUS_OK > ier)
   {
      KIM_API_report_error(__LINE__, __FILE__, "KIM_API_getm_compute", ier);
      return ier;
   }

   /* unpack data from KIM object */
   KIM_API_getm_data(pkim, &ier, 9*3,
                     "numberOfParticles",           &nParts,         1,
                     "particleSpecies",             &particleSpecies,1,
                     "coordinates",                 &coords,         1,
                     "numberContributingParticles", &numContrib,     (HalfOrFull==1),
                     "boxSideLengths",              &boxSideLengths, (NBC==2),
                     "energy",                      &energy,         (comp_energy==1),
                     "forces",                      &force,          (comp_force==1),
                     "particleEnergy",              &particleEnergy, (comp_particleEnergy==1),
                     "virial",                      &virial,         (comp_virial==1));
   if (KIM_STATUS_OK > ier)
   {
      KIM_API_report_error(__LINE__, __FILE__, "KIM_API_getm_data", ier);
      return ier;
   }

   if (HalfOrFull == 1)
   {
      if (3 != NBC) /* non-CLUSTER cases */
      {
         numberContrib = *numContrib;
      }
      else
      {
         numberContrib = *nParts;
      }
   }
   else
   { /* provide initialization even if not used */
      numberContrib = *nParts;
   }

   /* Check to be sure that the species are correct */
   /**/
   ier = KIM_STATUS_FAIL; /* assume an error */
   for (i = 0; i < *nParts; ++i)
   {
      if ( SPECCODE != particleSpecies[i])
      {
         KIM_API_report_error(__LINE__, __FILE__, "Unexpected species detected", ier);
         return ier;
      }
   }
   ier = KIM_STATUS_OK; /* everything is ok */

   /* initialize potential energies, forces, and virial term */
   if (comp_particleEnergy)
   {
      for (i = 0; i < *nParts; ++i)
      {
         particleEnergy[i] = 0.0;
      }
   }
   if (comp_energy)
   {
      *energy = 0.0;
   }

   if (comp_force)
   {
      for (i = 0; i < *nParts; ++i)
      {
         for (k = 0; k < DIM; ++k)
         {
            force[i*DIM + k] = 0.0;
         }
      }
   }

   if (comp_virial)
   {
      for (i = 0; i < 6; ++i)
      {
         virial[i] = 0.0;
      }
   }

   /* Initialize neighbor handling for CLUSTER NBC */
   if (3 == NBC) /* CLUSTER */
   {
      neighListOfCurrentPart = (int *) malloc((*nParts)*sizeof(int));
   }

   /* Initialize neighbor handling for Iterator mode */

   if (1 == IterOrLoca)
   {
      ier = KIM_API_get_neigh(pkim, 0, 0, &currentPart, &numOfPartNeigh,
                               &neighListOfCurrentPart, &Rij_list);
      /* check for successful initialization */
      if (KIM_STATUS_NEIGH_ITER_INIT_OK != ier)
      {
         KIM_API_report_error(__LINE__, __FILE__, "KIM_API_get_neigh", ier);
         ier = KIM_STATUS_FAIL;
         return ier;
      }
   }

   /* Compute energy and forces */

   /* loop over particles and compute enregy and forces */
   i = -1;
   while( 1 )
   {

      /* Set up neighbor list for next particle for all NBC methods */
      if (1 == IterOrLoca) /* ITERATOR mode */
      {
         ier = KIM_API_get_neigh(pkim, 0, 1, &currentPart, &numOfPartNeigh,
                                  &neighListOfCurrentPart, &Rij_list);
         if (KIM_STATUS_NEIGH_ITER_PAST_END == ier) /* the end of the list, terminate loop */
         {
            break;
         }
         if (KIM_STATUS_OK > ier) /* some sort of problem, return */
         {
            KIM_API_report_error(__LINE__, __FILE__, "KIM_API_get_neigh", ier);
            return ier;
         }

         i = currentPart;
      }
      else
      {
         i++;
         if (*nParts <= i) /* incremented past end of list, terminate loop */
         {
            break;
         }

         if (3 == NBC)     /* CLUSTER NBC method */
         {
            numOfPartNeigh = *nParts - (i + 1);
            for (k = 0; k < numOfPartNeigh; ++k)
            {
               neighListOfCurrentPart[k] = i + k + 1;
            }
            ier = KIM_STATUS_OK;
         }
         else              /* All other NBCs */
         {
            ier = KIM_API_get_neigh(pkim, 1, i, &currentPart, &numOfPartNeigh,
                                     &neighListOfCurrentPart, &Rij_list);
            if (KIM_STATUS_OK != ier) /* some sort of problem, return */
            {
            KIM_API_report_error(__LINE__, __FILE__, "KIM_API_get_neigh", ier);
            ier = KIM_STATUS_FAIL;
            return ier;
            }
         }
      }

      /* loop over the neighbors of particle i */
      for (jj = 0; jj < numOfPartNeigh; ++ jj)
      {

         j = neighListOfCurrentPart[jj]; /* get neighbor ID */

         /* compute relative position vector and squared distance */
         Rsqij = 0.0;
         for (k = 0; k < DIM; ++k)
         {
            if (0 != NBC) /* all methods except NEIGH_RVEC */
            {
               Rij[k] = coords[j*DIM + k] - coords[i*DIM + k];
            }
            else          /* NEIGH_RVEC_F method */
            {
               Rij[k] = Rij_list[jj*DIM + k];
            }

            /* apply periodic boundary conditions if required */
            if (2 == NBC)
            {
               if (abs(Rij[k]) > 0.5*boxSideLengths[k])
               {
                  Rij[k] -= (Rij[k]/fabs(Rij[k]))*boxSideLengths[k];
               }
            }

            /* compute squared distance */
            Rsqij += Rij[k]*Rij[k];
         }

         /* compute energy and force */
         if (Rsqij < MODEL_CUTSQ) /* particles are interacting ? */
         {
            R = sqrt(Rsqij);
            if (comp_force || comp_virial)
            {
               /* compute pair potential and its derivative */
               calc_phi_dphi(R, &phi, &dphi);

               /* compute dEidr */
               if ((1 == HalfOrFull) && (j < numberContrib))
               {
                  /* HALF mode -- double contribution */
                  dEidr = dphi;
               }
               else
               {
                  /* FULL mode -- regular contribution */
                  dEidr = 0.5*dphi;
               }
            }
            else
            {
               /* compute just pair potential */
               calc_phi(R, &phi);
            }

            /* contribution to energy */
            if (comp_particleEnergy)
            {
               particleEnergy[i] += 0.5*phi;
               /* if half list add energy for the other particle in the pair */
               if ((1 == HalfOrFull) && (j < numberContrib)) particleEnergy[j] += 0.5*phi;
            }
            if (comp_energy)
            {
               if ((1 == HalfOrFull) && (j < numberContrib))
               {
                  /* Half mode -- add v to total energy */
                  *energy += phi;
               }
               else
               {
                  /* Full mode -- add half v to total energy */
                  *energy += 0.5*phi;
               }
            }

            /* contribution to virial tensor */
            if (comp_virial)
            {
               /* virial(i,j) = r(i)*r(j)*(dV/dr)/r */
               virial[0] += Rij[0]*Rij[0]*dEidr/R;
               virial[1] += Rij[1]*Rij[1]*dEidr/R;
               virial[2] += Rij[2]*Rij[2]*dEidr/R;
               virial[3] += Rij[1]*Rij[2]*dEidr/R;
               virial[4] += Rij[0]*Rij[2]*dEidr/R;
               virial[5] += Rij[0]*Rij[1]*dEidr/R;
            }

            /* contribution to forces */
            if (comp_force)
            {
               for (k = 0; k < DIM; ++k)
               {
                  force[i*DIM + k] += dEidr*Rij[k]/R; /* accumulate force on particle i */
                  force[j*DIM + k] -= dEidr*Rij[k]/R; /* accumulate force on particle j */
               }
            }
         }
      } /* loop on jj */
   }    /* infinite while loop (terminated by break statements above */


   /* Free temporary storage */
   if (3 == NBC)
   {
      free(neighListOfCurrentPart);
   }

   /* everything is great */
   ier = KIM_STATUS_OK;
   return ier;
}
示例#3
0
int AsapKimPotential::compute(void* km)
{
  int ier;

  assert(potential != NULL);
  assert(pkim = *((intptr_t**) km));   // Sanity check
  double *cutoff = NULL;
  int *nAtoms = NULL;
  int *nTotalAtoms = NULL;
  int* particleSpecies = NULL;

  // Flags indicating what we need to compute.
  int comp_energy;
  int comp_force;
  int comp_particleEnergy;
  int comp_virial = 0;
  int comp_particleVirial = 0;

  // Quantities to be computed
  double *coords = NULL;
  double *energy = NULL;
  double *forces = NULL;
  double *particleEnergy = NULL;
  double *virial = NULL;
  double *particleVirial = NULL;

  /* check to see if we have been asked to compute the forces and particleEnergy */
  /* If we support virials, also check if we should calculate them */
  KIM_API_getm_compute(pkim, &ier, 5*3,
                       "energy",         &comp_energy,         1,
                       "forces",         &comp_force,          1,
                       "particleEnergy", &comp_particleEnergy, 1,
                       "virial",         &comp_virial,         supportvirial,
                       "particleVirial", &comp_particleVirial, supportvirial
  );
  if (KIM_STATUS_OK > ier)
    {
      KIM_API_report_error(__LINE__, __FILE__, "KIM_API_getm_compute", ier);
      return ier;
    }

  KIM_API_getm_data(pkim, &ier, 10*3,
                    "cutoff",                      &cutoff,          1,
                    "numberOfParticles",           &nTotalAtoms,     1,
                    "numberContributingParticles", &nAtoms,          need_contrib,
                    "particleSpecies",             &particleSpecies, 1,
                    "coordinates",                 &coords,          1,
                    "energy",                      &energy,          comp_energy,
                    "forces",                      &forces,          comp_force,
                    "particleEnergy",              &particleEnergy,  comp_particleEnergy,
                    "virial",                      &virial,          comp_virial,
                    "particleVirial",              &particleVirial,  comp_particleVirial
                    );
  if (KIM_STATUS_OK > ier)
    {
      KIM_API_report_error(__LINE__, __FILE__, "KIM_API_getm_data", ier);
      return ier;
    }
  if (!need_contrib)
    nAtoms = nTotalAtoms;

  if (atoms == NULL)
    {
      // First call, create the Atoms interface object
      atoms = new KimAtoms(pkim);
      assert(atoms != NULL);
      atoms->ReInit(*nAtoms, *nTotalAtoms - *nAtoms, coords, particleSpecies);
      potential->SetAtoms(NULL, atoms);
    }
  else
    {
      atoms->ReInit(*nAtoms, *nTotalAtoms - *nAtoms, coords, particleSpecies);
    }

  // Now do the actual computation
  try
  {
      if (comp_particleEnergy)
        {
          const vector<double> &energies_v = potential->GetPotentialEnergies(NULL);
          assert(energies_v.size() == *nAtoms);
          for (int i = 0; i < *nAtoms; i++)
            particleEnergy[i] = energies_v[i];
        }
      if (comp_energy)
        *energy = potential->GetPotentialEnergy(NULL);
      if (comp_particleVirial)
        {
          const vector<SymTensor> &virials = potential->GetVirials(NULL);
          assert(virials.size() == *nTotalAtoms);
          const double *virials_ptr = (double *) &virials[0];
          for (int i = 0; i < 6*(*nTotalAtoms); i++)
            particleVirial[i] = virials_ptr[i];
        }
      if (comp_virial)
        {
          SymTensor v = potential->GetVirial(NULL);
          for (int i = 0; i < 6; i++)
            virial[i] = v[i];
        }
      if (comp_force)
        {
          const vector<Vec> &forces_v = potential->GetForces(NULL);
          assert(forces_v.size() == *nTotalAtoms);
          const double *forces_v_ptr = (double *) &forces_v[0];
          for (int i = 0; i < 3*(*nTotalAtoms); i++)
            forces[i] = forces_v_ptr[i];
        }
  }
  catch (AsapError &e)
  {
      ier = KIM_STATUS_FAIL;
      string msg = e.GetMessage();
      // Will the following line store a pointer to something inside msg? Hopefully not!
      KIM_API_report_error(__LINE__, __FILE__, (char *) msg.c_str(), ier);
      return ier;
  }
  return KIM_STATUS_OK;
}