/* */ /* 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) 2019, Regents of the University of Minnesota. */ /* All rights reserved. */ /* */ /* Contributors: */ /* Daniel S. Karls */ /* Ellad B. Tadmor */ /* Ryan S. Elliott */ /* */ #include "KIM_LogMacros.h" #include "KIM_ModelDriverHeaders.h" #include #include #include #include #include "bondorder.inc" #define TRUE 1 #define FALSE 0 /******************************************************************************/ /* Below are the definitions for some constants */ /******************************************************************************/ #define DIM 3 /* dimensionality of space */ #define SPECCODE 1 /* internal species code */ #define SPEC_NAME_LEN 64 /* max length of species name string */ #define SPEC_NAME_FMT "%63s" /* scan format of species name string */ /* Define prototype for Model Driver init */ int model_driver_create(KIM_ModelDriverCreate * const modelDriverCreate, KIM_LengthUnit const requestedLengthUnit, KIM_EnergyUnit const requestedEnergyUnit, KIM_ChargeUnit const requestedChargeUnit, KIM_TemperatureUnit const requestedTemperatureUnit, KIM_TimeUnit const requestedTimeUnit); /* Define prototypes for destroy */ /* defined as static to avoid namespace clashes with other codes */ static int destroy_routine(KIM_ModelDestroy * const modelDestroy); /* Define prototype for routines */ static int compute_routine(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 refresh_routine(KIM_ModelRefresh * const modelRefresh); static int write_parameterized_model(KIM_ModelWriteParameterizedModel const * const modelWriteParameterizedModel); /* Define model_buffer structure */ struct model_buffer { double influenceDistance; double cutoff; double cut_sq; int modelWillNotRequestNeighborsOfNoncontributingParticles; char species_name[SPEC_NAME_LEN]; double * params; }; /* 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_routine(KIM_ModelCompute const * const modelCompute, KIM_ModelComputeArguments const * const modelComputeArguments) { /* local variables */ double tmp; double Rij; double Rik; double Rjk; double Ril; double Rsqij; double Rsqik; double Rsqjk; double Rsqil; double Z; double Z_i; double *dZi_dR; double bij; double zeta_ij; double phi2; double dphi2_dRij; double dphi2_dbij; double dbij_dzeta_ij; double dbij_dZi; double phi2_force_contrib; double coordination_force_contrib; double phi3; double dphi3_dRij; double dphi3_dRik; double dphi3_dRjk; double phi3_force_contrib_ij; double phi3_force_contrib_ik; double phi3_force_contrib_jk; double r_ij[DIM]; double r_ik[DIM]; double r_jk[DIM]; double r_il[DIM]; int ier; int atom_i; int neigh_count; int neigh_count2; int atom_j; int atom_k; int atom_l; int dim; int dZi_dR_size; int const * neigh_list_of_current_part; struct model_buffer const * buffer; int comp_energy; int comp_force; int const * n_parts; int const * particle_species_codes; int const * particle_contributing; double const * cut_sq; double const * params; double const * coords; double * energy; double * force; int numb_of_part_neigh; /* get buffer from KIM object */ KIM_ModelCompute_GetModelBufferPointer(modelCompute, (void **) &buffer); /* unpack info from the buffer */ cut_sq = &(buffer->cut_sq); params = buffer->params; ier = KIM_ModelComputeArguments_GetArgumentPointerInteger( modelComputeArguments, KIM_COMPUTE_ARGUMENT_NAME_numberOfParticles, (int **) &n_parts) || KIM_ModelComputeArguments_GetArgumentPointerInteger( modelComputeArguments, KIM_COMPUTE_ARGUMENT_NAME_particleSpeciesCodes, (int **) &particle_species_codes) || KIM_ModelComputeArguments_GetArgumentPointerInteger( modelComputeArguments, KIM_COMPUTE_ARGUMENT_NAME_particleContributing, (int **) &particle_contributing) || KIM_ModelComputeArguments_GetArgumentPointerDouble( modelComputeArguments, KIM_COMPUTE_ARGUMENT_NAME_coordinates, (double **) &coords) || KIM_ModelComputeArguments_GetArgumentPointerDouble( modelComputeArguments, KIM_COMPUTE_ARGUMENT_NAME_partialEnergy, (double **) &energy) || KIM_ModelComputeArguments_GetArgumentPointerDouble( modelComputeArguments, KIM_COMPUTE_ARGUMENT_NAME_partialForces, (double **) &force); if (ier) { LOG_ERROR("Unable to get argument pointer."); return ier; } comp_energy = (energy != NULL); comp_force = (force != NULL); /* Check to be sure that the species are correct */ /**/ ier = TRUE; /* assume an error */ for (atom_i = 0; atom_i < *n_parts; ++atom_i) { if (SPECCODE != particle_species_codes[atom_i]) { LOG_ERROR("Unexpected species code detected."); return ier; } } ier = FALSE; /* everything is ok */ /* initialize potential energies, forces, and virial term */ if (comp_energy) { *energy = 0.0; } if (comp_force) { for (atom_i = 0; atom_i < *n_parts; ++atom_i) { for (dim = 0; dim < DIM; ++dim) { force[atom_i * DIM + dim] = 0.0; } } } /* perform initial allocation of array containing derivatives of Z_i * w.r.t. Rij for each neighbor j of atom i */ dZi_dR_size = 100; dZi_dR = (double*) malloc(sizeof(double) * dZi_dR_size); /* Compute energy and forces */ /* loop over particles and compute energy and forces */ for (atom_i = 0; atom_i < *n_parts; ++atom_i) { if (particle_contributing[atom_i]) { ier = KIM_ModelComputeArguments_GetNeighborList( modelComputeArguments, 0, atom_i, &numb_of_part_neigh, &neigh_list_of_current_part); if (ier) { /* some sort of problem, exit */ LOG_ERROR("Unable to get neighbor list."); /* free dynamic memory */ free(dZi_dR); ier = TRUE; return ier; } /* reset coordination */ Z_i = 0.0; /* check if number of neighbors exceeds our current array size for * storing derivatives of coordination w.r.t. each neighbor */ if (numb_of_part_neigh > dZi_dR_size) { free(dZi_dR); while (dZi_dR_size < numb_of_part_neigh) { dZi_dR_size *= 2; } dZi_dR = (double*) malloc(sizeof(double) * dZi_dR_size); } /* first loop over the neighbors of particle atom_i to calculate * coordination */ for (neigh_count = 0; neigh_count < numb_of_part_neigh; ++neigh_count) { atom_j = neigh_list_of_current_part[neigh_count]; /* get ID */ /* compute relative position vector between atoms i and j, and squared * distance */ Rsqij = 0.0; for (dim = 0; dim < DIM; ++dim) { r_ij[dim] = coords[atom_j * DIM + dim] - coords[atom_i * DIM + dim]; /* compute squared distance */ Rsqij += r_ij[dim] * r_ij[dim]; } /* compute energy and force */ if (Rsqij < *cut_sq) { /* particles i and j are interacting */ Rij = sqrt(Rsqij); if (comp_force) { /* compute coordination and its derivative w.r.t. Rij */ calc_Zi_dZi(params, Rij, &Z, &dZi_dR[neigh_count]); } else { /* compute just coordination */ calc_Zi_dZi(params, Rij, &Z, NULL); } Z_i += Z; } } /* Second loop over the neighbors of particle atom_i to calculate energy * & forces */ for (neigh_count = 0; neigh_count < numb_of_part_neigh; ++neigh_count) { atom_j = neigh_list_of_current_part[neigh_count]; /* get ID */ /* compute relative position vector between atoms i and j, and squared * distance */ Rsqij = 0.0; for (dim = 0; dim < DIM; ++dim) { r_ij[dim] = coords[atom_j * DIM + dim] - coords[atom_i * DIM + dim]; /* compute squared distance */ Rsqij += r_ij[dim] * r_ij[dim]; } /* reset bond order */ zeta_ij = 0.0; /* compute energy and force */ if (Rsqij < *cut_sq) { /* particles i and j are interacting */ Rij = sqrt(Rsqij); /* First secondary loop over neighbors to calculate bond order */ for (neigh_count2 = 0; neigh_count2 < numb_of_part_neigh; ++neigh_count2) { atom_k = neigh_list_of_current_part[neigh_count2]; /* get ID */ if (atom_k == atom_j) { continue; } /* compute relative position vector between atoms i and k, and * squared distance */ Rsqik = 0.0; for (dim = 0; dim < DIM; ++dim) { r_ik[dim] = coords[atom_k * DIM + dim] - coords[atom_i * DIM + dim]; /* compute squared distance */ Rsqik += r_ik[dim] * r_ik[dim]; } /* compute energy and force */ if (Rsqik < *cut_sq) { /* particles i and k are interacting */ Rik = sqrt(Rsqik); /* compute relative position vector between atoms j and k, and * squared distance */ Rsqjk = 0.0; for (dim = 0; dim < DIM; ++dim) { r_jk[dim] = coords[atom_k * DIM + dim] - coords[atom_j * DIM + dim]; /* compute squared distance */ Rsqjk += r_jk[dim] * r_jk[dim]; } if (SKIP_CHECK_ON_RJK || Rsqjk < *cut_sq) { Rjk = sqrt(Rsqjk); /* compute just three-body interaction */ calc_phi3_dphi3(params, Rij, Rik, Rjk, &phi3, NULL, NULL, NULL); /* contribution to bond order */ zeta_ij += phi3; } } } /* loop on neigh_count2 */ if (comp_force) { /* compute bond order and its derivative w.r.t. zeta_ij */ calc_bij_dbij(params, Z_i, zeta_ij, &bij, &dbij_dZi, &dbij_dzeta_ij); /* compute two-body energy and its derivatives w.r.t. Rij and bij */ calc_phi2_dphi2(params, Rij, bij, &phi2, &dphi2_dRij, &dphi2_dbij); } else { /* compute just bond order */ calc_bij_dbij(params, Z_i, zeta_ij, &bij, NULL, NULL); /* compute just two-body energy */ calc_phi2_dphi2(params, Rij, bij, &phi2, NULL, NULL); } /* contribution to energy */ if (comp_energy) { *energy += 0.5 * phi2; } /* contribution to forces */ if (comp_force) { for (dim = 0; dim < DIM; ++dim) { phi2_force_contrib = 0.5 * dphi2_dRij * r_ij[dim] / Rij; force[atom_i * DIM + dim] += phi2_force_contrib; /* accumulate force on atom_i */ force[atom_j * DIM + dim] -= phi2_force_contrib; /* accumulate force on atom_j */ } /* Another secondary loop to apply coordination forces */ for (neigh_count2 = 0; neigh_count2 < numb_of_part_neigh; ++neigh_count2) { atom_l = neigh_list_of_current_part[neigh_count2]; /* get ID */ /* compute relative position vector between atoms i and l, and * squared distance */ Rsqil = 0.0; for (dim = 0; dim < DIM; ++dim) { r_il[dim] = coords[atom_l * DIM + dim] - coords[atom_i * DIM + dim]; /* compute squared distance */ Rsqil += r_il[dim] * r_il[dim]; } /* compute energy and force */ if (Rsqil < *cut_sq) { /* particles i and l are interacting */ Ril = sqrt(Rsqil); /* contribution to forces */ for (dim = 0; dim < DIM; ++dim) { coordination_force_contrib = 0.5 * dphi2_dbij * dbij_dZi * dZi_dR[neigh_count2] * r_il[dim]/Ril; force[atom_i * DIM + dim] += coordination_force_contrib; force[atom_l * DIM + dim] -= coordination_force_contrib; } } } /* Another, final, secondary loop over neighbors to calculate three-body * energy and forces */ for (neigh_count2 = 0; neigh_count2 < numb_of_part_neigh; ++neigh_count2) { atom_k = neigh_list_of_current_part[neigh_count2]; /* get ID */ if (atom_k == atom_j) { continue; } /* compute relative position vector between atoms i and k, and * squared distance */ Rsqik = 0.0; for (dim = 0; dim < DIM; ++dim) { r_ik[dim] = coords[atom_k * DIM + dim] - coords[atom_i * DIM + dim]; /* compute squared distance */ Rsqik += r_ik[dim] * r_ik[dim]; } /* compute energy and force */ if (Rsqik < *cut_sq) { /* particles i and k are interacting */ Rik = sqrt(Rsqik); /* compute relative position vector between atoms j and k, and * squared distance */ Rsqjk = 0.0; for (dim = 0; dim < DIM; ++dim) { r_jk[dim] = coords[atom_k * DIM + dim] - coords[atom_j * DIM + dim]; /* compute squared distance */ Rsqjk += r_jk[dim] * r_jk[dim]; } if (SKIP_CHECK_ON_RJK || Rsqjk < *cut_sq) { Rjk = sqrt(Rsqjk); /* compute three-body interaction and its derivatives with * respect to Rij and Rik */ calc_phi3_dphi3(params, Rij, Rik, Rjk, &phi3, &dphi3_dRij, &dphi3_dRik, &dphi3_dRjk); /* contribution to forces */ for (dim = 0; dim < DIM; ++dim) { tmp = 0.5 * dphi2_dbij * dbij_dzeta_ij; phi3_force_contrib_ij = dphi3_dRij * r_ij[dim] / Rij; phi3_force_contrib_ik = dphi3_dRik * r_ik[dim] / Rik; phi3_force_contrib_jk = dphi3_dRjk * r_jk[dim] / Rjk; force[atom_i * DIM + dim] += tmp * (phi3_force_contrib_ij + phi3_force_contrib_ik); /* accumulate phi3 derivatives for atom_i */ force[atom_j * DIM + dim] += tmp * (-phi3_force_contrib_ij + phi3_force_contrib_jk); /* accumulate three-body force on atom_j */ force[atom_k * DIM + dim] += tmp * (-phi3_force_contrib_ik - phi3_force_contrib_jk); /* accumulate partial three-body force on atom_k */ } } /* if Rsqjk < *cut_sq */ } /* if Rsqik < *cut_sq */ } /* loop on neigh_count2 */ } /* check on whether forces were asked for */ } /* if Rsqij < *cut_sq */ } /* loop on neigh_count */ } /* if particle_contributing */ } /* loop on atom_i */ /* free the dynamic array used to store derivatives of coordination w.r.t. * Rij for each neighbor */ free(dZi_dR); /* everything is great */ ier = FALSE; return ier; } /* Create function */ #undef KIM_LOGGER_FUNCTION_NAME #define KIM_LOGGER_FUNCTION_NAME KIM_ModelDriverCreate_LogEntry #undef KIM_LOGGER_OBJECT_NAME #define KIM_LOGGER_OBJECT_NAME modelDriverCreate int model_driver_create(KIM_ModelDriverCreate * const modelDriverCreate, KIM_LengthUnit const requestedLengthUnit, KIM_EnergyUnit const requestedEnergyUnit, KIM_ChargeUnit const requestedChargeUnit, KIM_TemperatureUnit const requestedTemperatureUnit, KIM_TimeUnit const requestedTimeUnit) { /* KIM variables */ int number_of_parameter_files; char const * param_file_1_name; /* Local variables */ FILE * fid; char species_name_string[SPEC_NAME_LEN]; char strbuf[256]; KIM_SpeciesName species_name; int ier; int param_count; double * params; double conversion_factor; struct model_buffer * buffer; /* Use function pointer definitions to verify prototypes */ KIM_ModelDriverCreateFunction * create = model_driver_create; KIM_ModelComputeArgumentsCreateFunction * ca_create = compute_arguments_create; KIM_ModelComputeFunction * compute = compute_routine; KIM_ModelRefreshFunction * refresh = refresh_routine; KIM_ModelWriteParameterizedModelFunction * write_model = write_parameterized_model; KIM_ModelComputeArgumentsDestroyFunction * ca_destroy = compute_arguments_destroy; KIM_ModelDestroyFunction * destroy = destroy_routine; (void) create; /* avoid unused parameter warnings */ (void) requestedChargeUnit; (void) requestedTemperatureUnit; (void) requestedTimeUnit; /* using requested units */ ier = KIM_ModelDriverCreate_SetUnits(modelDriverCreate, requestedLengthUnit, requestedEnergyUnit, KIM_CHARGE_UNIT_unused, KIM_TEMPERATURE_UNIT_unused, KIM_TIME_UNIT_unused); if (ier == TRUE) { LOG_ERROR("Unable to set units."); return ier; } ier = KIM_ModelDriverCreate_SetModelNumbering(modelDriverCreate, KIM_NUMBERING_zeroBased); if (ier == TRUE) { LOG_ERROR("Unable to set numbering."); return ier; } /* store pointer to functions in KIM object */ ier = KIM_ModelDriverCreate_SetRoutinePointer( modelDriverCreate, KIM_MODEL_ROUTINE_NAME_ComputeArgumentsCreate, KIM_LANGUAGE_NAME_c, TRUE, (KIM_Function *) ca_create) || KIM_ModelDriverCreate_SetRoutinePointer( modelDriverCreate, KIM_MODEL_ROUTINE_NAME_Compute, KIM_LANGUAGE_NAME_c, TRUE, (KIM_Function *) compute) || KIM_ModelDriverCreate_SetRoutinePointer( modelDriverCreate, KIM_MODEL_ROUTINE_NAME_Refresh, KIM_LANGUAGE_NAME_c, TRUE, (KIM_Function *) refresh) || KIM_ModelDriverCreate_SetRoutinePointer( modelDriverCreate, KIM_MODEL_ROUTINE_NAME_WriteParameterizedModel, KIM_LANGUAGE_NAME_c, FALSE, (KIM_Function *) write_model) || KIM_ModelDriverCreate_SetRoutinePointer( modelDriverCreate, KIM_MODEL_ROUTINE_NAME_ComputeArgumentsDestroy, KIM_LANGUAGE_NAME_c, TRUE, (KIM_Function *) ca_destroy) || KIM_ModelDriverCreate_SetRoutinePointer( modelDriverCreate, KIM_MODEL_ROUTINE_NAME_Destroy, KIM_LANGUAGE_NAME_c, TRUE, (KIM_Function *) destroy); if (ier == TRUE) { LOG_ERROR("Unable to register model function pointers."); return ier; } /* get number of parameter files */ KIM_ModelDriverCreate_GetNumberOfParameterFiles(modelDriverCreate, &number_of_parameter_files); /* set param_file_1_name */ if (number_of_parameter_files != 1) { ier = TRUE; LOG_ERROR("Incorrect number of parameter files."); return ier; } ier = KIM_ModelDriverCreate_GetParameterFileName( modelDriverCreate, 0, ¶m_file_1_name); if (ier == TRUE) { LOG_ERROR("Unable to get parameter file name."); return ier; } /* Read in model parameters from parameter file */ fid = fopen(param_file_1_name, "r"); if (fid == NULL) { ier = TRUE; LOG_ERROR("Unable to open parameter file."); return ier; } ier = fscanf(fid, SPEC_NAME_FMT, species_name_string); /* species symbol */ /* Check that we successfully read in this line */ if (1 != ier) { ier = TRUE; fclose(fid); LOG_ERROR("Unable to read species from parameter file."); } /* Consume the rest of the species line */ if (fgets(strbuf, 256, fid) == NULL) { if (ferror(fid)) { /* A read error was encountered */ ier = TRUE; fclose(fid); LOG_ERROR("Error occurred while trying to read parameter file (ferror)."); return ier; } else if (feof(fid)) { /* Reached the EOF mark before reading a character */ ier = TRUE; fclose(fid); LOG_ERROR("Error occurred while trying to read parameter file (reached EOF)."); return ier; } } params = (double *) malloc(sizeof(double) * NUM_PARAMS); if (params == NULL) { ier = TRUE; fclose(fid); LOG_ERROR("Unable to malloc memory for parameters."); return ier; } for (param_count = 0; param_count < NUM_PARAMS; ++param_count) { if (fgets(strbuf, 256, fid) == NULL) { if (ferror(fid)) { /* A read error was encountered */ ier = TRUE; fclose(fid); LOG_ERROR("Error occurred while trying to read parameter file (ferror)."); return ier; } else if (feof(fid)) { /* Reached the EOF mark before reading a character */ ier = TRUE; fclose(fid); LOG_ERROR("Error occurred while trying to read parameter file (reached EOF)."); return ier; } } /* Cast string read in to double (this will throw out comments) */ params[param_count] = strtod(strbuf, NULL); /* convert units */ if ((param_units[param_count][0] != 0.0) || (param_units[param_count][1] != 0.0)) { ier = KIM_ModelDriverCreate_ConvertUnit(*length_unit, *energy_unit, KIM_CHARGE_UNIT_unused, KIM_TEMPERATURE_UNIT_unused, KIM_TIME_UNIT_unused, requestedLengthUnit, requestedEnergyUnit, KIM_CHARGE_UNIT_unused, KIM_TEMPERATURE_UNIT_unused, KIM_TIME_UNIT_unused, param_units[param_count][0], param_units[param_count][1], 0.0, 0.0, 0.0, &conversion_factor); if (ier == TRUE) { fclose(fid); LOG_ERROR("Unable to convert units of parameter."); return ier; } params[param_count] *= conversion_factor; } } fclose(fid); /* register species */ species_name = KIM_SpeciesName_FromString(species_name_string); ier = KIM_ModelDriverCreate_SetSpeciesCode( modelDriverCreate, species_name, SPECCODE); if (ier == TRUE) { LOG_ERROR("Unable to set species code."); return ier; } /* allocate buffer */ buffer = (struct model_buffer *) malloc(sizeof(struct model_buffer)); if (NULL == buffer) { ier = TRUE; LOG_ERROR("Unable to malloc memory for buffer."); return ier; } /* setup buffer */ buffer->params = params; buffer->influenceDistance = get_influence_distance(buffer->params); buffer->cutoff = buffer->influenceDistance; buffer->cut_sq = buffer->cutoff * buffer->cutoff; buffer->modelWillNotRequestNeighborsOfNoncontributingParticles = 1; sprintf(buffer->species_name, "%s", /* no buffer overrun possible, due to above code */ species_name_string); /* end setup buffer */ /* store in model buffer */ KIM_ModelDriverCreate_SetModelBufferPointer(modelDriverCreate, (void *) buffer); /* publish model parameters */ for (param_count = 0; param_count < NUM_PARAMS; ++param_count) { ier = KIM_ModelDriverCreate_SetParameterPointerDouble( modelDriverCreate, 1, &(buffer->params[param_count]), param_strings[param_count][0], param_strings[param_count][1]); if (ier == TRUE) { LOG_ERROR("Unable to set parameter pointer(s)."); return TRUE; } } /* store model cutoff in KIM object */ KIM_ModelDriverCreate_SetInfluenceDistancePointer( modelDriverCreate, &(buffer->influenceDistance)); KIM_ModelDriverCreate_SetNeighborListPointers( modelDriverCreate, 1, &(buffer->cutoff), &(buffer->modelWillNotRequestNeighborsOfNoncontributingParticles)); return FALSE; } /* Refresh function */ #undef KIM_LOGGER_FUNCTION_NAME #define KIM_LOGGER_FUNCTION_NAME KIM_ModelRefresh_LogEntry #undef KIM_LOGGER_OBJECT_NAME #define KIM_LOGGER_OBJECT_NAME modelRefresh int refresh_routine(KIM_ModelRefresh * const modelRefresh) { struct model_buffer * buffer; /* get model buffer from KIM object */ KIM_ModelRefresh_GetModelBufferPointer(modelRefresh, (void **) &buffer); /* update cutoff and cutoff square */ buffer->influenceDistance = get_influence_distance(buffer->params); buffer->cutoff = buffer->influenceDistance; buffer->cut_sq = buffer->cutoff * buffer->cutoff; /* store model cutoff in KIM object */ KIM_ModelRefresh_SetInfluenceDistancePointer(modelRefresh, &(buffer->influenceDistance)); KIM_ModelRefresh_SetNeighborListPointers( modelRefresh, 1, &(buffer->cutoff), &(buffer->modelWillNotRequestNeighborsOfNoncontributingParticles)); return FALSE; } /* destroy function */ static int destroy_routine(KIM_ModelDestroy * const modelDestroy) { /* Local variables */ struct model_buffer * buffer; int ier; /* get model buffer from KIM object */ KIM_ModelDestroy_GetModelBufferPointer(modelDestroy, (void **) &buffer); /* free the buffer */ free(buffer->params); free(buffer); ier = FALSE; return ier; } /* 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 ier; (void) modelCompute; /* avoid unused parameter warning */ /* register arguments */ ier = KIM_ModelComputeArgumentsCreate_SetArgumentSupportStatus( modelComputeArgumentsCreate, KIM_COMPUTE_ARGUMENT_NAME_partialEnergy, KIM_SUPPORT_STATUS_optional) || KIM_ModelComputeArgumentsCreate_SetArgumentSupportStatus( modelComputeArgumentsCreate, KIM_COMPUTE_ARGUMENT_NAME_partialParticleEnergy, KIM_SUPPORT_STATUS_optional) || KIM_ModelComputeArgumentsCreate_SetArgumentSupportStatus( modelComputeArgumentsCreate, KIM_COMPUTE_ARGUMENT_NAME_partialForces, KIM_SUPPORT_STATUS_optional); if (ier == TRUE) { LOG_ERROR("Unable to set argument supportStatus."); 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; /* Nothing further to do */ return FALSE; } /* write parameterized model routine */ #undef KIM_LOGGER_FUNCTION_NAME #define KIM_LOGGER_FUNCTION_NAME KIM_ModelWriteParameterizedModel_LogEntry #undef KIM_LOGGER_OBJECT_NAME #define KIM_LOGGER_OBJECT_NAME modelWriteParameterizedModel /* */ #define STR_LEN 2048 static int write_parameterized_model( KIM_ModelWriteParameterizedModel const * const modelWriteParameterizedModel) { FILE * fp; char string_buffer[STR_LEN]; struct model_buffer const * buffer; char const * path; char const * model_name; int param_count; int max_str_len; /* get buffer from KIM object */ KIM_ModelWriteParameterizedModel_GetModelBufferPointer( modelWriteParameterizedModel, (void **) &buffer); KIM_ModelWriteParameterizedModel_GetPath(modelWriteParameterizedModel, &path); KIM_ModelWriteParameterizedModel_GetModelName(modelWriteParameterizedModel, &model_name); max_str_len = strlen(path) + strlen(model_name) + 9; if (max_str_len >= STR_LEN) { LOG_ERROR("Path and model name too long for internal buffers."); return TRUE; } sprintf(string_buffer, "%s.params", model_name); KIM_ModelWriteParameterizedModel_SetParameterFileName( modelWriteParameterizedModel, string_buffer); sprintf(string_buffer, "%s/%s.params", path, model_name); fp = fopen(string_buffer, "w"); if (NULL == fp) { LOG_ERROR("Unable to open parameter file for write."); return TRUE; } fprintf(fp, "%s\n", buffer->species_name); for (param_count = 0; param_count < NUM_PARAMS; ++param_count) { fprintf(fp, "%20.15f\n", buffer->params[param_count]); } fclose(fp); return FALSE; }