/*
*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License Version 1.0 (the "License").
*
* You can obtain a copy of the license at
* http://www.opensource.org/licenses/CDDL-1.0.  See the License for the
* specific language governing permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each file and
* include the License file in a prominent location with the name LICENSE.CDDL.
* If applicable, add the following below this CDDL HEADER, with the fields
* enclosed by brackets "[]" replaced with your own identifying information:
*
* Portions Copyright (c) [yyyy] [name of copyright owner]. All rights reserved.
*
* CDDL HEADER END
*

*
* Copyright (c) 2013, Regents of the University of Minnesota.
* All rights reserved.
*
* Contributors:
*    Ryan S. Elliott
*    Ellad B. Tadmor
*    Stephen M. Whalen
*
*/

/*******************************************************************************
 *
 *  EAM_NN_Johnson_1988_Cu
 *
 *  Johnson pair functional model for Cu
 *
 *  Reference: R. A. Johnson, "Analytic nearest-neighbor model for fcc metals",
 *             Phys. Rev. B, 55(8):4941-4946, 1988.
 *
 *  Language: C
 *
 *******************************************************************************/


#include "KIM_ModelHeaders.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "KIM_LogMacros.h"

#define TRUE 1
#define FALSE 0

/******************************************************************************
 * Below are the definitions and values of all Model parameters
 *******************************************************************************/
#define DIM 3 /* dimensionality of space */
#define SPECCODE 1 /* internal species code */
#define MODEL_CUTOFF 3.5 /* cutoff radius in angstroms */
#define MODEL_CUTSQ (MODEL_CUTOFF * MODEL_CUTOFF)
#define JEAM_R0 2.556 /* A */
#define JEAM_PHI0 0.59 /* eV */
#define JEAM_GAM 8.00
#define JEAM_G0 0.30 /* eV */
#define JEAM_BET 5.85
#define JEAM_EC 3.54 /* eV/atom */
#define JEAM_ALF 5.09
#define JEAM_RHO0 3.60 /* eV (=12*JEAM_G0) */

/* Model buffer definition */
struct buffer
{
  int modelWillNotRequestNeighborsOfNoncontributingParticles;

  double influenceDistance;
  double cutoff;
};
typedef struct buffer buffer;

/* Define prototype for Model create */
int model_create(KIM_ModelCreate * const modelCreate,
                 KIM_LengthUnit const requestedLengthUnit,
                 KIM_EnergyUnit const requestedEnergyUnit,
                 KIM_ChargeUnit const requestedChargeUnit,
                 KIM_TemperatureUnit const requestedTemperatureUnit,
                 KIM_TimeUnit const requestedTimeUnit);

/* Define prototypes for model reinit, compute, and destroy */
/* defined as static to avoid namespace clashes with other Models */
/**/
static int
compute(KIM_ModelCompute const * const modelCompute,
        KIM_ModelComputeArguments const * const modelComputeArguments);
static int compute_arguments_create(
    KIM_ModelCompute const * const modelCompute,
    KIM_ModelComputeArgumentsCreate * const modelComputeArgumentsCreate);
static int compute_arguments_destroy(
    KIM_ModelCompute const * const modelCompute,
    KIM_ModelComputeArgumentsDestroy * const modelComputeArgumentsDestroy);

static int model_destroy(KIM_ModelDestroy * const modelDestroy);
/**/
static void calc_phi(double r, double * phi);
static void calc_phi_dphi(double r, double * phi, double * dphi);
static void calc_g(double r, double * g);
static void calc_dg(double r, double * dg);
static void calc_U(double rho, double * U);
static void calc_U_dU(double rho, double * U, double * dU);

/* Calculate pair potential phi(r) */
static void calc_phi(double r, double * phi)
{
  /* local variables */
  double rnorm;

  if (r > MODEL_CUTOFF)
  {
    /* Argument exceeds cutoff radius */
    *phi = 0.0;
  }
  else
  {
    rnorm = r / JEAM_R0;
    *phi = JEAM_PHI0 * exp(-JEAM_GAM * (rnorm - 1.0));
  }

  return;
}

/* Calculate pair potential phi(r) and its derivative dphi(r) */
static void calc_phi_dphi(double r, double * phi, double * dphi)
{
  /* local variables */
  double rnorm;

  if (r > MODEL_CUTOFF)
  {
    /* Argument exceeds cutoff radius */
    *phi = 0.0;
    *dphi = 0.0;
  }
  else
  {
    rnorm = r / JEAM_R0;
    *phi = JEAM_PHI0 * exp(-JEAM_GAM * (rnorm - 1.0));
    *dphi = -(JEAM_GAM / JEAM_R0) * (*phi);
  }

  return;
}

/* Calculate electron density g(r) */
static void calc_g(double r, double * g)
{
  /* local variables */
  double rnorm;

  if (r > MODEL_CUTOFF)
  {
    /* Argument exceeds cutoff radius */
    *g = 0.0;
  }
  else
  {
    rnorm = r / JEAM_R0;
    *g = JEAM_G0 * exp(-JEAM_BET * (rnorm - 1.0));
  }

  return;
}

/* Calculate electron density derivative dg(r) */
static void calc_dg(double r, double * dg)
{
  /* local variables */
  double rnorm;
  double g;

  if (r > MODEL_CUTOFF)
  {
    /* Argument exceeds cutoff radius */
    *dg = 0.0;
  }
  else
  {
    rnorm = r / JEAM_R0;
    g = JEAM_G0 * exp(-JEAM_BET * (rnorm - 1.0));
    *dg = -(JEAM_BET / JEAM_R0) * g;
  }

  return;
}

/* Calculate embedding function U(rho) */
static void calc_U(double rho, double * U)
{
  /* local variables */
  double rhonorm;
  double rhonorm_gob;
  double rhonorm_aob;
  double logrhonorm;
  double aob;
  double gob;

  if (rho == 0.0)
  {
    *U = 0.0;

    return;
  }

  aob = JEAM_ALF / JEAM_BET;
  gob = JEAM_GAM / JEAM_BET;
  rhonorm = rho / JEAM_RHO0;
  rhonorm_aob = pow(rhonorm, aob);
  rhonorm_gob = pow(rhonorm, gob);
  logrhonorm = log(rhonorm);

  *U = -JEAM_EC * (1.0 - aob * logrhonorm) * rhonorm_aob
       - 6.0 * JEAM_PHI0 * rhonorm_gob;

  return;
}

/* Calculate embedding function U(rho) and first derivative dU(rho) */
static void calc_U_dU(double rho, double * U, double * dU)
{
  /* local variables */
  double rhonorm;
  double rhonorm_gob;
  double rhonorm_aob;
  double logrhonorm;
  double aob;
  double gob;

  if (rho == 0.0)
  {
    *U = 0.0;
    *dU = 0.0;

    return;
  }

  aob = JEAM_ALF / JEAM_BET;
  gob = JEAM_GAM / JEAM_BET;
  rhonorm = rho / JEAM_RHO0;
  rhonorm_aob = pow(rhonorm, aob);
  rhonorm_gob = pow(rhonorm, gob);
  logrhonorm = log(rhonorm);

  *U = -JEAM_EC * (1.0 - aob * logrhonorm) * rhonorm_aob
       - 6.0 * JEAM_PHI0 * rhonorm_gob;
  *dU = (JEAM_EC * aob * aob * logrhonorm * rhonorm_aob
         - 6.0 * JEAM_PHI0 * gob * rhonorm_gob)
        / rho;

  return;
}

/* compute function */
#undef KIM_LOGGER_FUNCTION_NAME
#define KIM_LOGGER_FUNCTION_NAME KIM_ModelCompute_LogEntry
#undef KIM_LOGGER_OBJECT_NAME
#define KIM_LOGGER_OBJECT_NAME modelCompute
static int
compute(KIM_ModelCompute const * const modelCompute,
        KIM_ModelComputeArguments const * const modelComputeArguments)
{
  double r;
  double Rij[DIM];
  double Rsqij;
  double phi;
  double dphi;
  double g;
  double dg;
  double dU;
  double dphieff = 0.0;
  double dphii;
  double dUi;
  double Ei;
  double dphij;
  double dUj;
  double Ej;
  int ier;
  int i;
  int j;
  int jj;
  int k;
  int comp_force;
  int comp_particleEnergy;
  int comp_virial;
  int comp_energy;
  double * rho;
  double U;
  double * derU = 0;

  int const * neighListOfCurrentPart;
  int numOfPartNeigh;
  int * nParts;
  double * energy;
  double * coords;
  double * force;
  double * particleEnergy;

  int * particleContributing;
  int * particleSpeciesCodes;
  double * virial;

  LOG_INFORMATION("Getting data pointers");
  ier = KIM_ModelComputeArguments_GetArgumentPointerInteger(
            modelComputeArguments,
            KIM_COMPUTE_ARGUMENT_NAME_numberOfParticles,
            &nParts)
        || KIM_ModelComputeArguments_GetArgumentPointerInteger(
               modelComputeArguments,
               KIM_COMPUTE_ARGUMENT_NAME_particleSpeciesCodes,
               &particleSpeciesCodes)
        || KIM_ModelComputeArguments_GetArgumentPointerInteger(
               modelComputeArguments,
               KIM_COMPUTE_ARGUMENT_NAME_particleContributing,
               &particleContributing)
        || KIM_ModelComputeArguments_GetArgumentPointerDouble(
               modelComputeArguments,
               KIM_COMPUTE_ARGUMENT_NAME_coordinates,
               &coords)
        || KIM_ModelComputeArguments_GetArgumentPointerDouble(
               modelComputeArguments,
               KIM_COMPUTE_ARGUMENT_NAME_partialEnergy,
               &energy)
        || KIM_ModelComputeArguments_GetArgumentPointerDouble(
               modelComputeArguments,
               KIM_COMPUTE_ARGUMENT_NAME_partialForces,
               &force)
        || KIM_ModelComputeArguments_GetArgumentPointerDouble(
               modelComputeArguments,
               KIM_COMPUTE_ARGUMENT_NAME_partialParticleEnergy,
               &particleEnergy)
        || KIM_ModelComputeArguments_GetArgumentPointerDouble(
               modelComputeArguments,
               KIM_COMPUTE_ARGUMENT_NAME_partialVirial,
               &virial);

  if (ier)
  {
    LOG_ERROR("get data pointers failed");
    return ier;
  }

  comp_energy = (energy != 0);
  comp_force = (force != 0);
  comp_particleEnergy = (particleEnergy != 0);
  comp_virial = (virial != 0);

  /* Check to be sure that the species are correct */
  /**/
  ier = TRUE; /* assume an error */
  for (i = 0; i < *nParts; ++i)
  {
    if (SPECCODE != particleSpeciesCodes[i])
    {
      LOG_ERROR("Unexpected species code detected");
      return ier;
    }
  }
  ier = FALSE; /* everything is ok */

  /* initialize potential energies, forces, and virial term */
  /* Note: that the variable `particleEnergy' does not need to be initialized
   * because it's initial value is set during the embedding energy calculation.
   */
  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; }
  }

  /* pair functional electron density */
  rho = (double *) malloc((*nParts) * sizeof(double));
  for (i = 0; i < *nParts; ++i) { rho[i] = 0.0; }

  /* EAM embedded energy deriv */
  if ((comp_force) || (comp_virial))
  { derU = (double *) malloc((*nParts) * sizeof(double)); }

  /* loop over particles in the neighbor list a first time,
   * to compute electron density (=coordination)
   */
  LOG_INFORMATION("Starting first compute loop for elctron density");
  for (i = 0; i < *nParts; ++i)
  {
    if (particleContributing[i])
    {
      ier = KIM_ModelComputeArguments_GetNeighborList(modelComputeArguments,
                                                      0,
                                                      i,
                                                      &numOfPartNeigh,
                                                      &neighListOfCurrentPart);
      if (ier)
      {
        /* some sort of problem, exit */
        LOG_ERROR("GetNeighborList failed");
        ier = TRUE;
        return ier;
      }

      /* loop over the neighbors of particle i */
      for (jj = 0; jj < numOfPartNeigh; ++jj)
      {
        j = neighListOfCurrentPart[jj]; /* get neighbor ID */

        if (!(particleContributing[j] && j < i)) /* short-circuit half-list */
        {
          /* 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 contribution to electron density */
          if (Rsqij < MODEL_CUTSQ) /* particles are interacting ? */
          {
            r = sqrt(Rsqij); /* compute distance */
            calc_g(r, &g); /* compute electron density */
            rho[i] += g; /* accumulate electron density */

            if (particleContributing[j]) { rho[j] += g; }
          }
        }
      } /* loop on jj */
    } /* if contributing */
  } /* loop on i */

  /* Now that we know the electron densities, calculate embedding part
   * of energy U and its derivative U' (derU)
   */
  LOG_INFORMATION("Starting second compute loop for embedding part of energy");
  for (i = 0; i < *nParts; ++i)
  {
    if (particleContributing[i])
    {
      if (comp_force || comp_virial)
      {
        calc_U_dU(
            rho[i], &U, &dU); /* compute embedding energy and its derivative */
        derU[i] = dU; /* store dU for later use */
      }
      else
      {
        calc_U(rho[i], &U); /* compute just embedding energy */
      }

      /* accumulate the embedding energy contribution */
      /* Assuming U)rho=0) = 0.0 */
      if (comp_particleEnergy) { particleEnergy[i] += U; }
      else if (comp_energy)
      {
        *energy += U;
      }
    }
  }

  /* Loop over particles in the neighbor list a second time to compute
   * the forces and complete energy calculation
   */

  LOG_INFORMATION("Starting thrid compute loop for forces and energy");
  for (i = 0; i < *nParts; ++i)
  {
    if (particleContributing[i])
    {
      ier = KIM_ModelComputeArguments_GetNeighborList(modelComputeArguments,
                                                      0,
                                                      i,
                                                      &numOfPartNeigh,
                                                      &neighListOfCurrentPart);
      if (ier)
      {
        /* some sort of problem, exit */
        LOG_ERROR("GetNeighborList failed");
        ier = TRUE;
        return ier;
      }
      /* loop over the neighbors of atom i */
      for (jj = 0; jj < numOfPartNeigh; ++jj)
      {
        j = neighListOfCurrentPart[jj]; /* get neighbor ID */

        if (!(particleContributing[j] && j < i)) /* short-circuit half-list */
        {
          /* 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 < 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);

              /* copmute elect dens first deriv */
              calc_dg(r, &dg);

              /* compute dEidr */

              /* HALF mode -- double contribution */
              if (particleContributing[j])
              {
                dphii = 0.5 * dphi;
                dphij = 0.5 * dphi;
                dUi = derU[i] * dg;
                dUj = derU[j] * dg;
              }
              else
              {
                dphii = 0.5 * dphi;
                dphij = 0.0;
                dUi = derU[i] * dg;
                dUj = 0.0;
              }

              dphieff = dphii + dphij + dUi + dUj;
            }
            else
            {
              /* compute just pair potential */
              calc_phi(r, &phi);
            }


            /* HALF mode */
            Ei = 0.5 * phi;
            if (particleContributing[j])
              Ej = 0.5 * phi;
            else
              Ej = 0.0;

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

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

            /* contribution to forces */
            if (comp_force)
            { /* Ei contribution */
              for (k = 0; k < DIM; ++k)
              {
                force[i * DIM + k]
                    += dphieff * Rij[k] / r; /* accumulate force on atom i */
                force[j * DIM + k]
                    -= dphieff * Rij[k] / r; /* accumulate force on atom j */
              }
            }
          }
        }
      } /* loop on jj */
    } /* if contributing */
  } /* loop on i */
  LOG_INFORMATION("Finished compute loop");

  /* Free temporary storage */
  free(rho);
  if (comp_force || comp_virial) { free(derU); }

  /* everything is great */
  ier = FALSE;

  return ier;
}


/* Create function */
/* Define prototype for Model create */
#undef KIM_LOGGER_FUNCTION_NAME
#define KIM_LOGGER_FUNCTION_NAME KIM_ModelCreate_LogEntry
#undef KIM_LOGGER_OBJECT_NAME
#define KIM_LOGGER_OBJECT_NAME modelCreate
int model_create(KIM_ModelCreate * const modelCreate,
                 KIM_LengthUnit const requestedLengthUnit,
                 KIM_EnergyUnit const requestedEnergyUnit,
                 KIM_ChargeUnit const requestedChargeUnit,
                 KIM_TemperatureUnit const requestedTemperatureUnit,
                 KIM_TimeUnit const requestedTimeUnit)
{
  buffer * bufferPointer;
  int error;

  /* set units */
  LOG_INFORMATION("Set model units");
  error = KIM_ModelCreate_SetUnits(modelCreate, /* ignoring requested units */
                                   KIM_LENGTH_UNIT_A,
                                   KIM_ENERGY_UNIT_eV,
                                   KIM_CHARGE_UNIT_unused,
                                   KIM_TEMPERATURE_UNIT_unused,
                                   KIM_TIME_UNIT_unused);

  /* register species */
  LOG_INFORMATION("Setting species code");
  error = error
          || KIM_ModelCreate_SetSpeciesCode(
                 modelCreate, KIM_SPECIES_NAME_Cu, SPECCODE);

  /* register numbering */
  LOG_INFORMATION("Setting model numbering");
  error = error
          || KIM_ModelCreate_SetModelNumbering(modelCreate,
                                               KIM_NUMBERING_zeroBased);

  /* register function pointers */
  LOG_INFORMATION("Register model function pointers");
  error = error
          || KIM_ModelCreate_SetRoutinePointer(modelCreate,
                                               KIM_MODEL_ROUTINE_NAME_Compute,
                                               KIM_LANGUAGE_NAME_c,
                                               TRUE,
                                               (KIM_Function *) &compute);
  error = error
          || KIM_ModelCreate_SetRoutinePointer(
                 modelCreate,
                 KIM_MODEL_ROUTINE_NAME_ComputeArgumentsCreate,
                 KIM_LANGUAGE_NAME_c,
                 TRUE,
                 (KIM_Function *) &compute_arguments_create);
  error = error
          || KIM_ModelCreate_SetRoutinePointer(
                 modelCreate,
                 KIM_MODEL_ROUTINE_NAME_ComputeArgumentsDestroy,
                 KIM_LANGUAGE_NAME_c,
                 TRUE,
                 (KIM_Function *) &compute_arguments_destroy);
  error = error
          || KIM_ModelCreate_SetRoutinePointer(modelCreate,
                                               KIM_MODEL_ROUTINE_NAME_Destroy,
                                               KIM_LANGUAGE_NAME_c,
                                               TRUE,
                                               (KIM_Function *) &model_destroy);

  /* allocate buffer */
  bufferPointer = (buffer *) malloc(sizeof(buffer));

  /* store model buffer in KIM object */
  LOG_INFORMATION("Set influence distance and cutoffs");
  KIM_ModelCreate_SetModelBufferPointer(modelCreate, bufferPointer);

  /* set buffer values */
  bufferPointer->influenceDistance = MODEL_CUTOFF;
  bufferPointer->cutoff = MODEL_CUTOFF;
  bufferPointer->modelWillNotRequestNeighborsOfNoncontributingParticles = 1;

  /* register influence distance */
  KIM_ModelCreate_SetInfluenceDistancePointer(
      modelCreate, &(bufferPointer->influenceDistance));

  /* register cutoff */
  KIM_ModelCreate_SetNeighborListPointers(
      modelCreate,
      1,
      &(bufferPointer->cutoff),
      (const int *) &(
          bufferPointer
              ->modelWillNotRequestNeighborsOfNoncontributingParticles));

  if (error)
  {
    free(bufferPointer);
    LOG_ERROR("Unable to successfully initialize model");
    return TRUE;
  }
  else
  {
    return FALSE;
  }
}

/* Initialization function */
#undef KIM_LOGGER_FUNCTION_NAME
#define KIM_LOGGER_FUNCTION_NAME KIM_ModelDestroy_LogEntry
#undef KIM_LOGGER_OBJECT_NAME
#define KIM_LOGGER_OBJECT_NAME modelDestroy
int model_destroy(KIM_ModelDestroy * const modelDestroy)
{
  buffer * bufferPointer;

  LOG_INFORMATION("Getting buffer");
  KIM_ModelDestroy_GetModelBufferPointer(modelDestroy,
                                         (void **) &bufferPointer);
  LOG_INFORMATION("Freeing model memory");
  free(bufferPointer);

  return FALSE;
}

/* compute arguments create routine */
#undef KIM_LOGGER_FUNCTION_NAME
#define KIM_LOGGER_FUNCTION_NAME KIM_ModelComputeArgumentsCreate_LogEntry
#undef KIM_LOGGER_OBJECT_NAME
#define KIM_LOGGER_OBJECT_NAME modelComputeArgumentsCreate
static int compute_arguments_create(
    KIM_ModelCompute const * const modelCompute,
    KIM_ModelComputeArgumentsCreate * const modelComputeArgumentsCreate)
{
  int error;

  (void) modelCompute; /* Avoid unused argument warning */

  /* register arguments */
  LOG_INFORMATION("Register argument supportStatus");
  error = KIM_ModelComputeArgumentsCreate_SetArgumentSupportStatus(
      modelComputeArgumentsCreate,
      KIM_COMPUTE_ARGUMENT_NAME_partialEnergy,
      KIM_SUPPORT_STATUS_optional);

  error = error
          || KIM_ModelComputeArgumentsCreate_SetArgumentSupportStatus(
                 modelComputeArgumentsCreate,
                 KIM_COMPUTE_ARGUMENT_NAME_partialForces,
                 KIM_SUPPORT_STATUS_optional);

  error = error
          || KIM_ModelComputeArgumentsCreate_SetArgumentSupportStatus(
                 modelComputeArgumentsCreate,
                 KIM_COMPUTE_ARGUMENT_NAME_partialParticleEnergy,
                 KIM_SUPPORT_STATUS_optional);

  error = error
          || KIM_ModelComputeArgumentsCreate_SetArgumentSupportStatus(
                 modelComputeArgumentsCreate,
                 KIM_COMPUTE_ARGUMENT_NAME_partialVirial,
                 KIM_SUPPORT_STATUS_optional);

  /* register call backs */
  LOG_INFORMATION("Register call back supportStatus");

  if (error)
  {
    LOG_ERROR("Unable to successfully initialize compute arguments");
    return TRUE;
  }
  else
  {
    return FALSE;
  }
}

/* compute arguments destroy routine */
static int compute_arguments_destroy(
    KIM_ModelCompute const * const modelCompute,
    KIM_ModelComputeArgumentsDestroy * const modelComputeArgumentsDestroy)
{
  (void) modelCompute; /* avoid unused parameter warning */
  (void) modelComputeArgumentsDestroy; /* avoid unused parameter warning */

  /* Nothing further to do */

  return FALSE;
}
