kim-api-v2  2.0.0+912e79a.GNU
An Application Programming Interface (API) for the Knowledgebase of Interatomic Models (KIM).
LennardJones612Implementation.cpp
Go to the documentation of this file.
1 // CDDL HEADER START
2 //
3 // The contents of this file are subject to the terms of the Common Development
4 // and Distribution License Version 1.0 (the "License").
5 //
6 // You can obtain a copy of the license at
7 // http://www.opensource.org/licenses/CDDL-1.0. See the License for the
8 // specific language governing permissions and limitations under the License.
9 //
10 // When distributing Covered Code, include this CDDL HEADER in each file and
11 // include the License file in a prominent location with the name LICENSE.CDDL.
12 // If applicable, add the following below this CDDL HEADER, with the fields
13 // enclosed by brackets "[]" replaced with your own identifying information:
14 //
15 // Portions Copyright (c) [yyyy] [name of copyright owner]. All rights reserved.
16 //
17 // CDDL HEADER END
18 //
19 
20 //
21 // Copyright (c) 2013--2015, Regents of the University of Minnesota.
22 // All rights reserved.
23 //
24 // Contributors:
25 // Ryan S. Elliott
26 // Stephen M. Whalen
27 // Andrew Akerson
28 //
29 
30 
31 #include <cmath>
32 #include <cstdlib>
33 #include <cstring>
34 #include <fstream>
35 #include <iostream>
36 #include <map>
37 #include <sstream>
38 
41 
42 #define MAXLINE 1024
43 #define IGNORE_RESULT(fn) \
44  if (fn) {}
45 
46 
47 //==============================================================================
48 //
49 // Implementation of LennardJones612Implementation public member functions
50 //
51 //==============================================================================
52 
53 //******************************************************************************
54 #undef KIM_LOGGER_OBJECT_NAME
55 #define KIM_LOGGER_OBJECT_NAME modelDriverCreate
56 //
58  KIM::ModelDriverCreate * const modelDriverCreate,
59  KIM::LengthUnit const requestedLengthUnit,
60  KIM::EnergyUnit const requestedEnergyUnit,
61  KIM::ChargeUnit const requestedChargeUnit,
62  KIM::TemperatureUnit const requestedTemperatureUnit,
63  KIM::TimeUnit const requestedTimeUnit,
64  int * const ier) :
65  numberModelSpecies_(0),
66  numberUniqueSpeciesPairs_(0),
67  shift_(0),
68  cutoffs_(NULL),
69  epsilons_(NULL),
70  sigmas_(NULL),
71  influenceDistance_(0.0),
72  cutoffsSq2D_(NULL),
73  modelWillNotRequestNeighborsOfNoncontributingParticles_(1),
74  fourEpsilonSigma6_2D_(NULL),
75  fourEpsilonSigma12_2D_(NULL),
76  twentyFourEpsilonSigma6_2D_(NULL),
77  fortyEightEpsilonSigma12_2D_(NULL),
78  oneSixtyEightEpsilonSigma6_2D_(NULL),
79  sixTwentyFourEpsilonSigma12_2D_(NULL),
80  shifts2D_(NULL),
81  cachedNumberOfParticles_(0)
82 {
83  FILE * parameterFilePointers[MAX_PARAMETER_FILES];
84  int numberParameterFiles;
85  modelDriverCreate->GetNumberOfParameterFiles(&numberParameterFiles);
86  *ier = OpenParameterFiles(
87  modelDriverCreate, numberParameterFiles, parameterFilePointers);
88  if (*ier) return;
89 
90  *ier = ProcessParameterFiles(
91  modelDriverCreate, numberParameterFiles, parameterFilePointers);
92  CloseParameterFiles(numberParameterFiles, parameterFilePointers);
93  if (*ier) return;
94 
95  *ier = ConvertUnits(modelDriverCreate,
96  requestedLengthUnit,
97  requestedEnergyUnit,
98  requestedChargeUnit,
99  requestedTemperatureUnit,
100  requestedTimeUnit);
101  if (*ier) return;
102 
103  *ier = SetRefreshMutableValues(modelDriverCreate);
104  if (*ier) return;
105 
106  *ier = RegisterKIMModelSettings(modelDriverCreate);
107  if (*ier) return;
108 
109  *ier = RegisterKIMParameters(modelDriverCreate);
110  if (*ier) return;
111 
112  *ier = RegisterKIMFunctions(modelDriverCreate);
113  if (*ier) return;
114 
115  // everything is good
116  *ier = false;
117  return;
118 }
119 
120 //******************************************************************************
122 { // note: it is ok to delete a null pointer and we have ensured that
123  // everything is initialized to null
124 
125  delete[] cutoffs_;
126  Deallocate2DArray(cutoffsSq2D_);
127  delete[] epsilons_;
128  delete[] sigmas_;
129  Deallocate2DArray(fourEpsilonSigma6_2D_);
130  Deallocate2DArray(fourEpsilonSigma12_2D_);
131  Deallocate2DArray(twentyFourEpsilonSigma6_2D_);
132  Deallocate2DArray(fortyEightEpsilonSigma12_2D_);
133  Deallocate2DArray(oneSixtyEightEpsilonSigma6_2D_);
134  Deallocate2DArray(sixTwentyFourEpsilonSigma12_2D_);
135  Deallocate2DArray(shifts2D_);
136 }
137 
138 //******************************************************************************
139 #undef KIM_LOGGER_OBJECT_NAME
140 #define KIM_LOGGER_OBJECT_NAME modelRefresh
141 //
143  KIM::ModelRefresh * const modelRefresh)
144 {
145  int ier;
146 
147  ier = SetRefreshMutableValues(modelRefresh);
148  if (ier) return ier;
149 
150  // nothing else to do for this case
151 
152  // everything is good
153  ier = false;
154  return ier;
155 }
156 
157 //******************************************************************************
159  KIM::ModelCompute const * const modelCompute,
160  KIM::ModelComputeArguments const * const modelComputeArguments)
161 {
162  int ier;
163 
164  // KIM API Model Input compute flags
165  bool isComputeProcess_dEdr = false;
166  bool isComputeProcess_d2Edr2 = false;
167  //
168  // KIM API Model Output compute flags
169  bool isComputeEnergy = false;
170  bool isComputeForces = false;
171  bool isComputeParticleEnergy = false;
172  bool isComputeVirial = false;
173  bool isComputeParticleVirial = false;
174  //
175  // KIM API Model Input
176  int const * particleSpeciesCodes = NULL;
177  int const * particleContributing = NULL;
178  VectorOfSizeDIM const * coordinates = NULL;
179  //
180  // KIM API Model Output
181  double * energy = NULL;
182  double * particleEnergy = NULL;
183  VectorOfSizeDIM * forces = NULL;
184  VectorOfSizeSix * virial = NULL;
185  VectorOfSizeSix * particleVirial = NULL;
186  ier = SetComputeMutableValues(modelComputeArguments,
187  isComputeProcess_dEdr,
188  isComputeProcess_d2Edr2,
189  isComputeEnergy,
190  isComputeForces,
191  isComputeParticleEnergy,
192  isComputeVirial,
193  isComputeParticleVirial,
194  particleSpeciesCodes,
195  particleContributing,
196  coordinates,
197  energy,
198  particleEnergy,
199  forces,
200  virial,
201  particleVirial);
202  if (ier) return ier;
203 
204  // Skip this check for efficiency
205  //
206  // ier = CheckParticleSpecies(modelComputeArguments, particleSpeciesCodes);
207  // if (ier) return ier;
208 
209  bool const isShift = (1 == shift_);
210 
212  return ier;
213 }
214 
215 //******************************************************************************
217  KIM::ModelComputeArgumentsCreate * const modelComputeArgumentsCreate) const
218 {
219  int ier;
220 
221  ier = RegisterKIMComputeArgumentsSettings(modelComputeArgumentsCreate);
222  if (ier) return ier;
223 
224  // nothing else to do for this case
225 
226  // everything is good
227  ier = false;
228  return ier;
229 }
230 
231 //******************************************************************************
233  KIM::ModelComputeArgumentsDestroy * const modelComputeArgumentsDestroy)
234  const
235 {
236  int ier;
237 
238  (void) modelComputeArgumentsDestroy; // avoid unused parameter warning
239 
240  // nothing else to do for this case
241 
242  // everything is good
243  ier = false;
244  return ier;
245 }
246 
247 //==============================================================================
248 //
249 // Implementation of LennardJones612Implementation private member functions
250 //
251 //==============================================================================
252 
253 //******************************************************************************
254 void LennardJones612Implementation::AllocatePrivateParameterMemory()
255 {
256  // nothing to do for this case
257 }
258 
259 //******************************************************************************
260 void LennardJones612Implementation::AllocateParameterMemory()
261 { // allocate memory for data
262  cutoffs_ = new double[numberUniqueSpeciesPairs_];
264  cutoffsSq2D_, numberModelSpecies_, numberModelSpecies_);
265 
266  epsilons_ = new double[numberUniqueSpeciesPairs_];
267  sigmas_ = new double[numberUniqueSpeciesPairs_];
269  fourEpsilonSigma6_2D_, numberModelSpecies_, numberModelSpecies_);
271  fourEpsilonSigma12_2D_, numberModelSpecies_, numberModelSpecies_);
273  twentyFourEpsilonSigma6_2D_, numberModelSpecies_, numberModelSpecies_);
275  fortyEightEpsilonSigma12_2D_, numberModelSpecies_, numberModelSpecies_);
277  oneSixtyEightEpsilonSigma6_2D_, numberModelSpecies_, numberModelSpecies_);
278  AllocateAndInitialize2DArray(sixTwentyFourEpsilonSigma12_2D_,
279  numberModelSpecies_,
280  numberModelSpecies_);
281 
283  shifts2D_, numberModelSpecies_, numberModelSpecies_);
284 }
285 
286 //******************************************************************************
287 #undef KIM_LOGGER_OBJECT_NAME
288 #define KIM_LOGGER_OBJECT_NAME modelDriverCreate
289 //
290 int LennardJones612Implementation::OpenParameterFiles(
291  KIM::ModelDriverCreate * const modelDriverCreate,
292  int const numberParameterFiles,
293  FILE * parameterFilePointers[MAX_PARAMETER_FILES])
294 {
295  int ier;
296 
297  if (numberParameterFiles > MAX_PARAMETER_FILES)
298  {
299  ier = true;
300  LOG_ERROR("LennardJones612 given too many parameter files");
301  return ier;
302  }
303 
304  for (int i = 0; i < numberParameterFiles; ++i)
305  {
306  std::string const * paramFileName;
307  ier = modelDriverCreate->GetParameterFileName(i, &paramFileName);
308  if (ier)
309  {
310  LOG_ERROR("Unable to get parameter file name");
311  return ier;
312  }
313  parameterFilePointers[i] = fopen(paramFileName->c_str(), "r");
314  if (parameterFilePointers[i] == 0)
315  {
316  char message[MAXLINE];
317  sprintf(message,
318  "LennardJones612 parameter file number %d cannot be opened",
319  i);
320  ier = true;
321  LOG_ERROR(message);
322  for (int j = i - 1; i <= 0; --i) { fclose(parameterFilePointers[j]); }
323  return ier;
324  }
325  }
326 
327  // everything is good
328  ier = false;
329  return ier;
330 }
331 
332 //******************************************************************************
333 #undef KIM_LOGGER_OBJECT_NAME
334 #define KIM_LOGGER_OBJECT_NAME modelDriverCreate
335 //
336 int LennardJones612Implementation::ProcessParameterFiles(
337  KIM::ModelDriverCreate * const modelDriverCreate,
338  int const numberParameterFiles,
339  FILE * const parameterFilePointers[MAX_PARAMETER_FILES])
340 {
341  int N, ier;
342  int endOfFileFlag = 0;
343  char spec1[MAXLINE], spec2[MAXLINE], nextLine[MAXLINE];
344  char * nextLinePtr;
345  int iIndex, jIndex, indx, iiIndex, jjIndex;
346  double nextCutoff, nextEpsilon, nextSigma;
347 
348  (void) numberParameterFiles; // avoid unused parameter warning
349 
350  nextLinePtr = nextLine;
351 
352  getNextDataLine(
353  parameterFilePointers[0], nextLinePtr, MAXLINE, &endOfFileFlag);
354  ier = sscanf(nextLine, "%d %d", &N, &shift_);
355  if (ier != 2)
356  {
357  sprintf(nextLine, "unable to read first line of the parameter file");
358  ier = true;
359  LOG_ERROR(nextLine);
360  fclose(parameterFilePointers[0]);
361  return ier;
362  }
363  numberModelSpecies_ = N;
364  numberUniqueSpeciesPairs_
365  = ((numberModelSpecies_ + 1) * numberModelSpecies_) / 2;
366  AllocateParameterMemory();
367 
368  // set all values in the arrays to -1 for mixing later
369  for (int i = 0; i < ((N + 1) * N / 2); i++)
370  {
371  cutoffs_[i] = -1;
372  epsilons_[i] = -1;
373  sigmas_[i] = -1;
374  }
375 
376 
377  // keep track of known species
378  std::map<KIM::SpeciesName const, int, KIM::SPECIES_NAME::Comparator>
379  modelSpeciesMap;
380  std::vector<KIM::SpeciesName> speciesNameVector;
381  int index = 0;
382 
383  // Read and process data lines
384  getNextDataLine(
385  parameterFilePointers[0], nextLinePtr, MAXLINE, &endOfFileFlag);
386  while (endOfFileFlag == 0)
387  {
388  ier = sscanf(nextLine,
389  "%s %s %lg %lg %lg",
390  spec1,
391  spec2,
392  &nextCutoff,
393  &nextEpsilon,
394  &nextSigma);
395  if (ier != 5)
396  {
397  sprintf(nextLine, "error reading lines of the parameter file");
398  LOG_ERROR(nextLine);
399  return true;
400  }
401 
402  // convert species strings to proper type instances
403  KIM::SpeciesName const specName1(spec1);
404  KIM::SpeciesName const specName2(spec2);
405 
406  // check for new species
407  std::map<KIM::SpeciesName const, int, KIM::SPECIES_NAME::Comparator>::
408  const_iterator iIter
409  = modelSpeciesMap.find(specName1);
410  if (iIter == modelSpeciesMap.end())
411  {
412  modelSpeciesMap[specName1] = index;
413  modelSpeciesCodeList_.push_back(index);
414  speciesNameVector.push_back(specName1);
415 
416  ier = modelDriverCreate->SetSpeciesCode(specName1, index);
417  if (ier) return ier;
418  iIndex = index;
419  index++;
420  }
421  else
422  {
423  iIndex = modelSpeciesMap[specName1];
424  }
425  std::map<KIM::SpeciesName const, int, KIM::SPECIES_NAME::Comparator>::
426  const_iterator jIter
427  = modelSpeciesMap.find(specName2);
428  if (jIter == modelSpeciesMap.end())
429  {
430  modelSpeciesMap[specName2] = index;
431  modelSpeciesCodeList_.push_back(index);
432  speciesNameVector.push_back(specName2);
433 
434  ier = modelDriverCreate->SetSpeciesCode(specName2, index);
435  if (ier) return ier;
436  jIndex = index;
437  index++;
438  }
439  else
440  {
441  jIndex = modelSpeciesMap[specName2];
442  }
443 
444  if (iIndex >= jIndex)
445  { indx = jIndex * N + iIndex - (jIndex * jIndex + jIndex) / 2; }
446  else
447  {
448  indx = iIndex * N + jIndex - (iIndex * iIndex + iIndex) / 2;
449  }
450  cutoffs_[indx] = nextCutoff;
451  epsilons_[indx] = nextEpsilon;
452  sigmas_[indx] = nextSigma;
453 
454  getNextDataLine(
455  parameterFilePointers[0], nextLinePtr, MAXLINE, &endOfFileFlag);
456  }
457 
458  // check that we got all like - like pairs
459  sprintf(nextLine, "There are not values for like-like pairs of:");
460  for (int i = 0; i < N; i++)
461  {
462  if (cutoffs_[(i * N + i - (i * i + i) / 2)] == -1)
463  {
464  strcat(nextLine, " ");
465  strcat(nextLine, (speciesNameVector[i].ToString()).c_str());
466  ier = -1;
467  }
468  }
469  if (ier == -1)
470  {
471  LOG_ERROR(nextLine);
472  return true;
473  }
474 
475  // Perform Mixing if nessisary
476  for (int jIndex = 0; jIndex < N; jIndex++)
477  {
478  jjIndex = (jIndex * N + jIndex - (jIndex * jIndex + jIndex) / 2);
479  for (int iIndex = (jIndex + 1); iIndex < N; iIndex++)
480  {
481  indx = jIndex * N + iIndex - (jIndex * jIndex + jIndex) / 2;
482  if (cutoffs_[indx] == -1)
483  {
484  iiIndex = (iIndex * N + iIndex - (iIndex * iIndex + iIndex) / 2);
485  epsilons_[indx] = sqrt(epsilons_[iiIndex] * epsilons_[jjIndex]);
486  sigmas_[indx] = (sigmas_[iiIndex] + sigmas_[jjIndex]) / 2.0;
487  cutoffs_[indx] = (cutoffs_[iiIndex] + cutoffs_[jjIndex]) / 2.0;
488  }
489  }
490  }
491 
492  // everything is good
493  ier = false;
494  return ier;
495 }
496 
497 //******************************************************************************
498 void LennardJones612Implementation::getNextDataLine(FILE * const filePtr,
499  char * nextLinePtr,
500  int const maxSize,
501  int * endOfFileFlag)
502 {
503  do
504  {
505  if (fgets(nextLinePtr, maxSize, filePtr) == NULL)
506  {
507  *endOfFileFlag = 1;
508  break;
509  }
510  while ((nextLinePtr[0] == ' ' || nextLinePtr[0] == '\t')
511  || (nextLinePtr[0] == '\n' || nextLinePtr[0] == '\r'))
512  { nextLinePtr = (nextLinePtr + 1); }
513  } while ((strncmp("#", nextLinePtr, 1) == 0) || (strlen(nextLinePtr) == 0));
514 }
515 
516 //******************************************************************************
517 void LennardJones612Implementation::CloseParameterFiles(
518  int const numberParameterFiles,
519  FILE * const parameterFilePointers[MAX_PARAMETER_FILES])
520 {
521  for (int i = 0; i < numberParameterFiles; ++i)
522  fclose(parameterFilePointers[i]);
523 }
524 
525 //******************************************************************************
526 #undef KIM_LOGGER_OBJECT_NAME
527 #define KIM_LOGGER_OBJECT_NAME modelDriverCreate
528 //
529 int LennardJones612Implementation::ConvertUnits(
530  KIM::ModelDriverCreate * const modelDriverCreate,
531  KIM::LengthUnit const requestedLengthUnit,
532  KIM::EnergyUnit const requestedEnergyUnit,
533  KIM::ChargeUnit const requestedChargeUnit,
534  KIM::TemperatureUnit const requestedTemperatureUnit,
535  KIM::TimeUnit const requestedTimeUnit)
536 {
537  int ier;
538 
539  // define default base units
545 
546  // changing units of cutoffs and sigmas
547  double convertLength = 1.0;
548  ier = KIM::ModelDriverCreate::ConvertUnit(fromLength,
549  fromEnergy,
550  fromCharge,
551  fromTemperature,
552  fromTime,
553  requestedLengthUnit,
554  requestedEnergyUnit,
555  requestedChargeUnit,
556  requestedTemperatureUnit,
557  requestedTimeUnit,
558  1.0,
559  0.0,
560  0.0,
561  0.0,
562  0.0,
563  &convertLength);
564  if (ier)
565  {
566  LOG_ERROR("Unable to convert length unit");
567  return ier;
568  }
569  if (convertLength != ONE)
570  {
571  for (int i = 0; i < numberUniqueSpeciesPairs_; ++i)
572  {
573  cutoffs_[i] *= convertLength; // convert to active units
574  sigmas_[i] *= convertLength; // convert to active units
575  }
576  }
577  // changing units of epsilons
578  double convertEnergy = 1.0;
579  ier = KIM::ModelDriverCreate::ConvertUnit(fromLength,
580  fromEnergy,
581  fromCharge,
582  fromTemperature,
583  fromTime,
584  requestedLengthUnit,
585  requestedEnergyUnit,
586  requestedChargeUnit,
587  requestedTemperatureUnit,
588  requestedTimeUnit,
589  0.0,
590  1.0,
591  0.0,
592  0.0,
593  0.0,
594  &convertEnergy);
595  if (ier)
596  {
597  LOG_ERROR("Unable to convert energy unit");
598  return ier;
599  }
600  if (convertEnergy != ONE)
601  {
602  for (int i = 0; i < numberUniqueSpeciesPairs_; ++i)
603  {
604  epsilons_[i] *= convertEnergy; // convert to active units
605  }
606  }
607 
608  // register units
609  ier = modelDriverCreate->SetUnits(requestedLengthUnit,
610  requestedEnergyUnit,
614  if (ier)
615  {
616  LOG_ERROR("Unable to set units to requested values");
617  return ier;
618  }
619 
620  // everything is good
621  ier = false;
622  return ier;
623 }
624 
625 //******************************************************************************
626 int LennardJones612Implementation::RegisterKIMModelSettings(
627  KIM::ModelDriverCreate * const modelDriverCreate) const
628 {
629  // register numbering
630  int error = modelDriverCreate->SetModelNumbering(KIM::NUMBERING::zeroBased);
631 
632  return error;
633 }
634 
635 //******************************************************************************
636 #undef KIM_LOGGER_OBJECT_NAME
637 #define KIM_LOGGER_OBJECT_NAME modelComputeArgumentsCreate
638 //
639 int LennardJones612Implementation::RegisterKIMComputeArgumentsSettings(
640  KIM::ModelComputeArgumentsCreate * const modelComputeArgumentsCreate) const
641 {
642  // register arguments
643  LOG_INFORMATION("Register argument supportStatus");
644  int error = modelComputeArgumentsCreate->SetArgumentSupportStatus(
647  || modelComputeArgumentsCreate->SetArgumentSupportStatus(
650  || modelComputeArgumentsCreate->SetArgumentSupportStatus(
653  || modelComputeArgumentsCreate->SetArgumentSupportStatus(
656  || modelComputeArgumentsCreate->SetArgumentSupportStatus(
659 
660 
661  // register callbacks
662  LOG_INFORMATION("Register callback supportStatus");
663  error = error
664  || modelComputeArgumentsCreate->SetCallbackSupportStatus(
667  || modelComputeArgumentsCreate->SetCallbackSupportStatus(
670 
671  return error;
672 }
673 
674 //******************************************************************************
675 // helper macro
676 #define SNUM(x) \
677  static_cast<std::ostringstream &>(std::ostringstream() << std::dec << x).str()
678 //******************************************************************************
679 #undef KIM_LOGGER_OBJECT_NAME
680 #define KIM_LOGGER_OBJECT_NAME modelDriverCreate
681 //
682 int LennardJones612Implementation::RegisterKIMParameters(
683  KIM::ModelDriverCreate * const modelDriverCreate)
684 {
685  int ier = false;
686 
687  // publish parameters (order is important)
688  ier = modelDriverCreate->SetParameterPointer(
689  1,
690  &shift_,
691  "shift",
692  "If (shift == 1), all LJ potentials are shifted to zero energy "
693  "at their respective cutoff distance. Otherwise, no shifting is "
694  "performed.");
695  if (ier)
696  {
697  LOG_ERROR("set_parameter shift");
698  return ier;
699  }
700 
701  ier = modelDriverCreate->SetParameterPointer(
702  numberUniqueSpeciesPairs_,
703  cutoffs_,
704  "cutoffs",
705  "Lower-triangular matrix (of size N=" + SNUM(numberModelSpecies_)
706  + ") "
707  "in row-major storage. Ordering is according to SpeciesCode "
708  "values. "
709  "For example, to find the parameter related to SpeciesCode 'i' and "
710  "SpeciesCode 'j' (i >= j), use (zero-based) "
711  "index = (j*N + i - (j*j + j)/2).");
712  if (ier)
713  {
714  LOG_ERROR("set_parameter cutoffs");
715  return ier;
716  }
717  ier = modelDriverCreate->SetParameterPointer(
718  numberUniqueSpeciesPairs_,
719  epsilons_,
720  "epsilons",
721  "Lower-triangular matrix (of size N=" + SNUM(numberModelSpecies_)
722  + ") "
723  "in row-major storage. Ordering is according to SpeciesCode "
724  "values. "
725  "For example, to find the parameter related to SpeciesCode 'i' and "
726  "SpeciesCode 'j' (i >= j), use (zero-based) "
727  "index = (j*N + i - (j*j + j)/2).");
728  if (ier)
729  {
730  LOG_ERROR("set_parameter epsilons");
731  return ier;
732  }
733  ier = modelDriverCreate->SetParameterPointer(
734  numberUniqueSpeciesPairs_,
735  sigmas_,
736  "sigmas",
737  "Lower-triangular matrix (of size N=" + SNUM(numberModelSpecies_)
738  + ") "
739  "in row-major storage. Ordering is according to SpeciesCode "
740  "values. "
741  "For example, to find the parameter related to SpeciesCode 'i' and "
742  "SpeciesCode 'j' (i >= j), use (zero-based) "
743  "index = (j*N + i - (j*j + j)/2).");
744  if (ier)
745  {
746  LOG_ERROR("set_parameter sigmas");
747  return ier;
748  }
749 
750  // everything is good
751  ier = false;
752  return ier;
753 }
754 
755 //******************************************************************************
756 int LennardJones612Implementation::RegisterKIMFunctions(
757  KIM::ModelDriverCreate * const modelDriverCreate) const
758 {
759  int error;
760 
761  // Use function pointer definitions to verify correct prototypes
769 
770  // register the destroy() and reinit() functions
771  error = modelDriverCreate->SetRoutinePointer(
774  true,
775  reinterpret_cast<KIM::Function *>(destroy))
776  || modelDriverCreate->SetRoutinePointer(
779  true,
780  reinterpret_cast<KIM::Function *>(refresh))
781  || modelDriverCreate->SetRoutinePointer(
784  true,
785  reinterpret_cast<KIM::Function *>(compute))
786  || modelDriverCreate->SetRoutinePointer(
789  true,
790  reinterpret_cast<KIM::Function *>(CACreate))
791  || modelDriverCreate->SetRoutinePointer(
794  true,
795  reinterpret_cast<KIM::Function *>(CADestroy));
796  return error;
797 }
798 
799 //******************************************************************************
800 template<class ModelObj>
801 int LennardJones612Implementation::SetRefreshMutableValues(
802  ModelObj * const modelObj)
803 { // use (possibly) new values of parameters to compute other quantities
804  // NOTE: This function is templated because it's called with both a
805  // modelDriverCreate object during initialization and with a
806  // modelRefresh object when the Model's parameters have been altered
807  int ier;
808 
809  // update cutoffsSq, epsilons, and sigmas
810  for (int i = 0; i < numberModelSpecies_; ++i)
811  {
812  for (int j = 0; j <= i; ++j)
813  {
814  int const index = j * numberModelSpecies_ + i - (j * j + j) / 2;
815  cutoffsSq2D_[i][j] = cutoffsSq2D_[j][i]
816  = (cutoffs_[index] * cutoffs_[index]);
817  fourEpsilonSigma6_2D_[i][j] = fourEpsilonSigma6_2D_[j][i]
818  = 4.0 * epsilons_[index] * pow(sigmas_[index], 6.0);
819  fourEpsilonSigma12_2D_[i][j] = fourEpsilonSigma12_2D_[j][i]
820  = 4.0 * epsilons_[index] * pow(sigmas_[index], 12.0);
821  twentyFourEpsilonSigma6_2D_[i][j] = twentyFourEpsilonSigma6_2D_[j][i]
822  = 6.0 * fourEpsilonSigma6_2D_[i][j];
823  fortyEightEpsilonSigma12_2D_[i][j] = fortyEightEpsilonSigma12_2D_[j][i]
824  = 12.0 * fourEpsilonSigma12_2D_[i][j];
825  oneSixtyEightEpsilonSigma6_2D_[i][j]
826  = oneSixtyEightEpsilonSigma6_2D_[j][i]
827  = 7.0 * twentyFourEpsilonSigma6_2D_[i][j];
828  sixTwentyFourEpsilonSigma12_2D_[i][j]
829  = sixTwentyFourEpsilonSigma12_2D_[j][i]
830  = 13.0 * fortyEightEpsilonSigma12_2D_[i][j];
831  }
832  }
833 
834  // update cutoff value in KIM API object
835  influenceDistance_ = 0.0;
836 
837  for (int i = 0; i < numberModelSpecies_; i++)
838  {
839  int indexI = modelSpeciesCodeList_[i];
840 
841  for (int j = 0; j < numberModelSpecies_; j++)
842  {
843  int indexJ = modelSpeciesCodeList_[j];
844 
845  if (influenceDistance_ < cutoffsSq2D_[indexI][indexJ])
846  { influenceDistance_ = cutoffsSq2D_[indexI][indexJ]; }
847  }
848  }
849 
850  influenceDistance_ = sqrt(influenceDistance_);
851  modelObj->SetInfluenceDistancePointer(&influenceDistance_);
852  modelObj->SetNeighborListPointers(
853  1,
854  &influenceDistance_,
855  &modelWillNotRequestNeighborsOfNoncontributingParticles_);
856 
857  // update shifts
858  // compute and set shifts2D_ check if minus sign
859  double const * const * const constFourEpsSig6_2D = fourEpsilonSigma6_2D_;
860  double const * const * const constFourEpsSig12_2D = fourEpsilonSigma12_2D_;
861  if (1 == shift_)
862  {
863  double phi;
864  for (int iSpecies = 0; iSpecies < numberModelSpecies_; iSpecies++)
865  {
866  for (int jSpecies = 0; jSpecies <= iSpecies; jSpecies++)
867  {
868  int const index = jSpecies * numberModelSpecies_ + iSpecies
869  - (jSpecies * jSpecies + jSpecies) / 2;
870  double const rij2 = cutoffs_[index] * cutoffs_[index];
871  double const r2iv = 1.0 / rij2;
872  double const r6iv = r2iv * r2iv * r2iv;
874  shifts2D_[iSpecies][jSpecies] = shifts2D_[jSpecies][iSpecies] = phi;
875  }
876  }
877  }
878 
879  // everything is good
880  ier = false;
881  return ier;
882 }
883 
884 //******************************************************************************
885 #undef KIM_LOGGER_OBJECT_NAME
886 #define KIM_LOGGER_OBJECT_NAME modelComputeArguments
887 //
888 int LennardJones612Implementation::SetComputeMutableValues(
889  KIM::ModelComputeArguments const * const modelComputeArguments,
890  bool & isComputeProcess_dEdr,
891  bool & isComputeProcess_d2Edr2,
892  bool & isComputeEnergy,
893  bool & isComputeForces,
894  bool & isComputeParticleEnergy,
895  bool & isComputeVirial,
896  bool & isComputeParticleVirial,
897  int const *& particleSpeciesCodes,
898  int const *& particleContributing,
899  VectorOfSizeDIM const *& coordinates,
900  double *& energy,
901  double *& particleEnergy,
902  VectorOfSizeDIM *& forces,
903  VectorOfSizeSix *& virial,
904  VectorOfSizeSix *& particleVirial)
905 {
906  int ier = true;
907 
908  // get compute flags
909  int compProcess_dEdr;
910  int compProcess_d2Edr2;
911 
912  modelComputeArguments->IsCallbackPresent(
914  modelComputeArguments->IsCallbackPresent(
915  KIM::COMPUTE_CALLBACK_NAME::ProcessD2EDr2Term, &compProcess_d2Edr2);
916 
917  isComputeProcess_dEdr = compProcess_dEdr;
918  isComputeProcess_d2Edr2 = compProcess_d2Edr2;
919 
920  int const * numberOfParticles;
921  ier = modelComputeArguments->GetArgumentPointer(
923  || modelComputeArguments->GetArgumentPointer(
926  || modelComputeArguments->GetArgumentPointer(
929  || modelComputeArguments->GetArgumentPointer(
931  (double const **) &coordinates)
932  || modelComputeArguments->GetArgumentPointer(
934  || modelComputeArguments->GetArgumentPointer(
936  || modelComputeArguments->GetArgumentPointer(
938  (double const **) &forces)
939  || modelComputeArguments->GetArgumentPointer(
941  (double const **) &virial)
942  || modelComputeArguments->GetArgumentPointer(
944  (double const **) &particleVirial);
945  if (ier)
946  {
947  LOG_ERROR("GetArgumentPointer");
948  return ier;
949  }
950 
951  isComputeEnergy = (energy != NULL);
952  isComputeParticleEnergy = (particleEnergy != NULL);
953  isComputeForces = (forces != NULL);
954  isComputeVirial = (virial != NULL);
955  isComputeParticleVirial = (particleVirial != NULL);
956 
957  // update values
958  cachedNumberOfParticles_ = *numberOfParticles;
959 
960  // everything is good
961  ier = false;
962  return ier;
963 }
964 
965 //******************************************************************************
966 #undef KIM_LOGGER_OBJECT_NAME
967 #define KIM_LOGGER_OBJECT_NAME modelCompute
968 int LennardJones612Implementation::CheckParticleSpeciesCodes(
969  KIM::ModelCompute const * const modelCompute,
970  int const * const particleSpeciesCodes) const
971 {
972  int ier;
973  for (int i = 0; i < cachedNumberOfParticles_; ++i)
974  {
975  if ((particleSpeciesCodes[i] < 0)
976  || (particleSpeciesCodes[i] >= numberModelSpecies_))
977  {
978  ier = true;
979  LOG_ERROR("unsupported particle species codes detected");
980  return ier;
981  }
982  }
983 
984  // everything is good
985  ier = false;
986  return ier;
987 }
988 
989 //******************************************************************************
990 int LennardJones612Implementation::GetComputeIndex(
991  const bool & isComputeProcess_dEdr,
992  const bool & isComputeProcess_d2Edr2,
993  const bool & isComputeEnergy,
994  const bool & isComputeForces,
995  const bool & isComputeParticleEnergy,
996  const bool & isComputeVirial,
997  const bool & isComputeParticleVirial,
998  const bool & isShift) const
999 {
1000  // const int processdE = 2;
1001  const int processd2E = 2;
1002  const int energy = 2;
1003  const int force = 2;
1004  const int particleEnergy = 2;
1005  const int virial = 2;
1006  const int particleVirial = 2;
1007  const int shift = 2;
1008 
1009 
1010  int index = 0;
1011 
1012  // processdE
1013  index += (int(isComputeProcess_dEdr)) * processd2E * energy * force
1014  * particleEnergy * virial * particleVirial * shift;
1015 
1016  // processd2E
1017  index += (int(isComputeProcess_d2Edr2)) * energy * force * particleEnergy
1018  * virial * particleVirial * shift;
1019 
1020  // energy
1021  index += (int(isComputeEnergy)) * force * particleEnergy * virial
1022  * particleVirial * shift;
1023 
1024  // force
1025  index += (int(isComputeForces)) * particleEnergy * virial * particleVirial
1026  * shift;
1027 
1028  // particleEnergy
1029  index += (int(isComputeParticleEnergy)) * virial * particleVirial * shift;
1030 
1031  // virial
1032  index += (int(isComputeVirial)) * particleVirial * shift;
1033 
1034  // particleVirial
1035  index += (int(isComputeParticleVirial)) * shift;
1036 
1037  // shift
1038  index += (int(isShift));
1039 
1040  return index;
1041 }
1042 
1043 //******************************************************************************
1044 void LennardJones612Implementation::ProcessVirialTerm(
1045  const double & dEidr,
1046  const double & rij,
1047  const double * const r_ij,
1048  const int & i,
1049  const int & j,
1050  VectorOfSizeSix virial) const
1051 {
1052  (void) i; // avoid unused parameter warning
1053  (void) j;
1054 
1055  double const v = dEidr / rij;
1056 
1057  virial[0] += v * r_ij[0] * r_ij[0];
1058  virial[1] += v * r_ij[1] * r_ij[1];
1059  virial[2] += v * r_ij[2] * r_ij[2];
1060  virial[3] += v * r_ij[1] * r_ij[2];
1061  virial[4] += v * r_ij[0] * r_ij[2];
1062  virial[5] += v * r_ij[0] * r_ij[1];
1063 }
1064 
1065 //******************************************************************************
1066 void LennardJones612Implementation::ProcessParticleVirialTerm(
1067  const double & dEidr,
1068  const double & rij,
1069  const double * const r_ij,
1070  const int & i,
1071  const int & j,
1072  VectorOfSizeSix * const particleVirial) const
1073 {
1074  double const v = dEidr / rij;
1075  VectorOfSizeSix vir;
1076 
1077  vir[0] = 0.5 * v * r_ij[0] * r_ij[0];
1078  vir[1] = 0.5 * v * r_ij[1] * r_ij[1];
1079  vir[2] = 0.5 * v * r_ij[2] * r_ij[2];
1080  vir[3] = 0.5 * v * r_ij[1] * r_ij[2];
1081  vir[4] = 0.5 * v * r_ij[0] * r_ij[2];
1082  vir[5] = 0.5 * v * r_ij[0] * r_ij[1];
1083 
1084  for (int k = 0; k < 6; ++k)
1085  {
1086  particleVirial[i][k] += vir[k];
1087  particleVirial[j][k] += vir[k];
1088  }
1089 }
1090 
1091 //==============================================================================
1092 //
1093 // Implementation of helper functions
1094 //
1095 //==============================================================================
1096 
1097 //******************************************************************************
1098 void AllocateAndInitialize2DArray(double **& arrayPtr,
1099  int const extentZero,
1100  int const extentOne)
1101 { // allocate memory and set pointers
1102  arrayPtr = new double *[extentZero];
1103  arrayPtr[0] = new double[extentZero * extentOne];
1104  for (int i = 1; i < extentZero; ++i)
1105  { arrayPtr[i] = arrayPtr[i - 1] + extentOne; }
1106 
1107  // initialize
1108  for (int i = 0; i < extentZero; ++i)
1109  {
1110  for (int j = 0; j < extentOne; ++j) { arrayPtr[i][j] = 0.0; }
1111  }
1112 }
1113 
1114 //******************************************************************************
1115 void Deallocate2DArray(double **& arrayPtr)
1116 { // deallocate memory
1117  if (arrayPtr != NULL) delete[] arrayPtr[0];
1118  delete[] arrayPtr;
1119 
1120  // nullify pointer
1121  arrayPtr = NULL;
1122 }
Numbering const zeroBased
The standard zeroBased numbering.
TimeUnit const ps
The standard picosecond unit of time.
#define LOG_ERROR(message)
Convenience macro for ERROR Log entries with compile-time optimization.
TimeUnit const unused
Indicates that a TimeUnit is not used.
int SetSpeciesCode(SpeciesName const speciesName, int const code)
Set integer code for supported SpeciesName.
EnergyUnit const eV
The standard electronvolt unit of energy.
ComputeCallbackName const ProcessD2EDr2Term
The standard ProcessD2EDr2Term callback.
recursive subroutine, public destroy(model_destroy_handle, ierr)
An Extensible Enumeration for the ChargeUnit&#39;s supported by the KIM API.
ComputeArgumentName const partialParticleEnergy
The standard partialParticleEnergy argument.
An Extensible Enumeration for the LengthUnit&#39;s supported by the KIM API.
int Refresh(KIM::ModelRefresh *const modelRefresh)
SupportStatus const optional
The standard optional status.
void AllocateAndInitialize2DArray(double **&arrayPtr, int const extentZero, int const extentOne)
int SetArgumentSupportStatus(ComputeArgumentName const computeArgumentName, SupportStatus const supportStatus)
Set the SupportStatus of a ComputeArgumentName.
int ComputeArgumentsDestroy(KIM::ModelComputeArgumentsDestroy *const modelComputeArgumentsDestroy) const
TemperatureUnit const K
The standard Kelvin unit of temperature.
static int Refresh(KIM::ModelRefresh *const modelRefresh)
recursive subroutine, public refresh(model_refresh_handle, ierr)
#define LENNARD_JONES_PHI(exshift)
static int Compute(KIM::ModelCompute const *const modelCompute, KIM::ModelComputeArguments const *const modelComputeArguments)
Provides the interface to a KIM API Model object for use by models within their MODEL_ROUTINE_NAME::C...
Provides the interface to a KIM API ComputeArguments object for use by models within their MODEL_ROUT...
ChargeUnit const unused
Indicates that a ChargeUnit is not used.
TemperatureUnit const unused
Indicates that a TemperatureUnit is not used.
int Compute(KIM::ModelCompute const *const modelCompute, KIM::ModelComputeArguments const *const modelComputeArguments)
ComputeArgumentName const partialVirial
The standard partialVirial argument.
void GetNumberOfParameterFiles(int *const numberOfParameterFiles) const
Get the number of parameter files provided by the parameterized model.
Provides the interface to a KIM API ComputeArguments object for use by models within their MODEL_ROUT...
An Extensible Enumeration for the EnergyUnit&#39;s supported by the KIM API.
int IsCallbackPresent(ComputeCallbackName const computeCallbackName, int *const present) const
Determine if the Simulator has provided a non-NULL function pointer for a ComputeCallbackName of inte...
void Deallocate2DArray(double **&arrayPtr)
ModelRoutineName const Destroy
The standard Destroy routine.
int SetParameterPointer(int const extent, int *const ptr, std::string const &name, std::string const &description)
Set the next parameter data pointer to be provided by the model.
double VectorOfSizeSix[6]
static int Destroy(KIM::ModelDestroy *const modelDestroy)
int ComputeArgumentsCreate(KIM::ModelComputeArgumentsCreate *const modelComputeArgumentsCreate) const
int SetUnits(LengthUnit const lengthUnit, EnergyUnit const energyUnit, ChargeUnit const chargeUnit, TemperatureUnit const temperatureUnit, TimeUnit const timeUnit)
Set the Model&#39;s base unit values.
int ModelComputeArgumentsCreateFunction(ModelCompute const *const modelCompute, ModelComputeArgumentsCreate *const modelComputeArgumentsCreate)
Prototype for MODEL_ROUTINE_NAME::ComputeArgumentsCreate routine.
ComputeCallbackName const ProcessDEDrTerm
The standard ProcessDEDrTerm callback.
An Extensible Enumeration for the TimeUnit&#39;s supported by the KIM API.
static int ComputeArgumentsDestroy(KIM::ModelCompute const *const modelCompute, KIM::ModelComputeArgumentsDestroy *const modelComputeArgumentsDestroy)
ModelRoutineName const Refresh
The standard Refresh routine.
ModelRoutineName const ComputeArgumentsDestroy
The standard ComputeArgumentsDestroy routine.
ModelRoutineName const ComputeArgumentsCreate
The standard ComputeArgumentsCreate routine.
ComputeArgumentName const coordinates
The standard coordinates argument.
LengthUnit const A
The standard angstrom unit of length.
int GetParameterFileName(int const index, std::string const **const parameterFileName) const
Get a particular parameter file name.
ComputeArgumentName const partialEnergy
The standard partialEnergy argument.
ModelRoutineName const Compute
The standard Compute routine.
ComputeArgumentName const particleSpeciesCodes
The standard particleSpeciesCodes argument.
ComputeArgumentName const numberOfParticles
The standard numberOfParticles argument.
Provides the interface to a KIM API ComputeArguments object for use by models within their MODEL_ROUT...
Provides the interface to a KIM API Model object for use by models within their MODEL_ROUTINE_NAME::C...
ComputeArgumentName const partialParticleVirial
The standard partialParticleVirial argument.
LanguageName const cpp
The standard cpp language.
int ModelDestroyFunction(ModelDestroy *const modelDestroy)
Prototype for MODEL_ROUTINE_NAME::Destroy routine.
int GetArgumentPointer(ComputeArgumentName const computeArgumentName, int const **const ptr) const
Get the data pointer for a ComputeArgumentName.
SpeciesName const N
The standard Nitrogen species.
Provides the interface to a KIM API Model object for use by models within their MODEL_ROUTINE_NAME::R...
An Extensible Enumeration for the TemperatureUnit&#39;s supported by the KIM API.
static int ComputeArgumentsCreate(KIM::ModelCompute const *const modelCompute, KIM::ModelComputeArgumentsCreate *const modelComputeArgumentsCreate)
LogVerbosity const error
The standard error verbosity.
#define LOG_INFORMATION(message)
Convenience macro for INFORMATION Log entries with compile-time optimization.
An Extensible Enumeration for the SpeciesName&#39;s supported by the KIM API.
ChargeUnit const e
The standard electron unit of charge.
double VectorOfSizeDIM[DIMENSION]
LennardJones612Implementation(KIM::ModelDriverCreate *const modelDriverCreate, KIM::LengthUnit const requestedLengthUnit, KIM::EnergyUnit const requestedEnergyUnit, KIM::ChargeUnit const requestedChargeUnit, KIM::TemperatureUnit const requestedTemperatureUnit, KIM::TimeUnit const requestedTimeUnit, int *const ier)
int SetModelNumbering(Numbering const numbering)
Set the Model&#39;s particle Numbering.
int ModelComputeArgumentsDestroyFunction(ModelCompute const *const modelCompute, ModelComputeArgumentsDestroy *const modelComputeArgumentsDestroy)
Prototype for MODEL_ROUTINE_NAME::ComputeArgumentsDestroy routine.
int SetRoutinePointer(ModelRoutineName const modelRoutineName, LanguageName const languageName, int const required, Function *const fptr)
Set the function pointer for the ModelRoutineName of interest.
int ModelRefreshFunction(ModelRefresh *const modelRefresh)
Prototype for MODEL_ROUTINE_NAME::Refresh routine.
ComputeArgumentName const particleContributing
The standard particleContributing argument.
ComputeArgumentName const partialForces
The standard partialForces argument.
static int ConvertUnit(LengthUnit const fromLengthUnit, EnergyUnit const fromEnergyUnit, ChargeUnit const fromChargeUnit, TemperatureUnit const fromTemperatureUnit, TimeUnit const fromTimeUnit, LengthUnit const toLengthUnit, EnergyUnit const toEnergyUnit, ChargeUnit const toChargeUnit, TemperatureUnit const toTemperatureUnit, TimeUnit const toTimeUnit, double const lengthExponent, double const energyExponent, double const chargeExponent, double const temperatureExponent, double const timeExponent, double *const conversionFactor)
Get the multiplicative factor to convert between a derived unit represented in two different sets of ...
int ModelComputeFunction(ModelCompute const *const modelCompute, ModelComputeArguments const *const modelComputeArgumentsCreate)
Prototype for MODEL_ROUTINE_NAME::Compute routine.
#define MAX_PARAMETER_FILES
int SetCallbackSupportStatus(ComputeCallbackName const computeCallbackName, SupportStatus const supportStatus)
Set the SupportStatus of a ComputeCallbackName.