diff --git a/src/KIM/kim_init.cpp b/src/KIM/kim_init.cpp index 605d5cd7ee..5da513d972 100644 --- a/src/KIM/kim_init.cpp +++ b/src/KIM/kim_init.cpp @@ -92,7 +92,12 @@ void KimInit::command(int narg, char **arg) strcpy(user_units,arg[1]); if (narg == 3) { if (strcmp(arg[2],"unit_conversion_mode")==0) unit_conversion_mode = true; - else { error->all(FLERR,"Illegal kim_init command"); } + else { + error->all(FLERR,fmt::format("Illegal kim_init command.\nThe argument " + "followed by unit_style {} is an optional " + "argument and when is used must " + "be unit_conversion_mode", user_units)); + } } else unit_conversion_mode = false; char *model_units; @@ -122,38 +127,41 @@ void get_kim_unit_names( KIM_TimeUnit & timeUnit, Error * error) { - if ((strcmp(system,"real")==0)) { + if (strcmp(system,"real") == 0) { lengthUnit = KIM_LENGTH_UNIT_A; energyUnit = KIM_ENERGY_UNIT_kcal_mol; chargeUnit = KIM_CHARGE_UNIT_e; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_fs; - } else if ((strcmp(system,"metal")==0)) { + } else if (strcmp(system,"metal") == 0) { lengthUnit = KIM_LENGTH_UNIT_A; energyUnit = KIM_ENERGY_UNIT_eV; chargeUnit = KIM_CHARGE_UNIT_e; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_ps; - } else if ((strcmp(system,"si")==0)) { + } else if (strcmp(system,"si") == 0) { lengthUnit = KIM_LENGTH_UNIT_m; energyUnit = KIM_ENERGY_UNIT_J; chargeUnit = KIM_CHARGE_UNIT_C; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_s; - } else if ((strcmp(system,"cgs")==0)) { + } else if (strcmp(system,"cgs") == 0) { lengthUnit = KIM_LENGTH_UNIT_cm; energyUnit = KIM_ENERGY_UNIT_erg; chargeUnit = KIM_CHARGE_UNIT_statC; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_s; - } else if ((strcmp(system,"electron")==0)) { + } else if (strcmp(system,"electron") == 0) { lengthUnit = KIM_LENGTH_UNIT_Bohr; energyUnit = KIM_ENERGY_UNIT_Hartree; chargeUnit = KIM_CHARGE_UNIT_e; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_fs; - } else if ((strcmp(system,"lj")==0)) { - error->all(FLERR,"LAMMPS unit_style lj not supported by KIM models"); + } else if (strcmp(system,"lj") == 0 || + strcmp(system,"micro") ==0 || + strcmp(system,"nano")==0) { + error->all(FLERR,fmt::format("LAMMPS unit_style {} not supported " + "by KIM models", system)); } else { error->all(FLERR,"Unknown unit_style"); } @@ -171,19 +179,19 @@ void KimInit::determine_model_type_and_units(char * model_name, KIM_TemperatureUnit temperatureUnit; KIM_TimeUnit timeUnit; int units_accepted; - KIM_Collections * kim_Coll; + KIM_Collections * collections; KIM_CollectionItemType itemType; - int kim_error = KIM_Collections_Create(&kim_Coll); - if (kim_error) { - error->all(FLERR,"Unable to access KIM Collections to find Model."); - } + int kim_error = KIM_Collections_Create(&collections); + if (kim_error) + error->all(FLERR,"Unable to access KIM Collections to find Model"); - kim_error = KIM_Collections_GetItemType(kim_Coll, model_name, &itemType); - if (kim_error) { - error->all(FLERR,"KIM Model name not found."); - } - KIM_Collections_Destroy(&kim_Coll); + auto logID = fmt::format("{}_Collections", comm->me); + KIM_Collections_SetLogID(collections, logID.c_str()); + + kim_error = KIM_Collections_GetItemType(collections, model_name, &itemType); + if (kim_error) error->all(FLERR,"KIM Model name not found"); + KIM_Collections_Destroy(&collections); if (KIM_CollectionItemType_Equal(itemType, KIM_COLLECTION_ITEM_TYPE_portableModel)) { @@ -199,12 +207,13 @@ void KimInit::determine_model_type_and_units(char * model_name, &units_accepted, &pkim); - if (kim_error) - error->all(FLERR,"Unable to load KIM Simulator Model."); + if (kim_error) error->all(FLERR,"Unable to load KIM Simulator Model"); model_type = MO; if (units_accepted) { + logID = fmt::format("{}_Model", comm->me); + KIM_Model_SetLogID(pkim, logID.c_str()); *model_units = new char[strlen(user_units)+1]; strcpy(*model_units,user_units); return; @@ -226,6 +235,8 @@ void KimInit::determine_model_type_and_units(char * model_name, &units_accepted, &pkim); if (units_accepted) { + logID = fmt::format("{}_Model", comm->me); + KIM_Model_SetLogID(pkim, logID.c_str()); *model_units = new char[strlen(systems[i])+1]; strcpy(*model_units,systems[i]); return; @@ -238,37 +249,40 @@ void KimInit::determine_model_type_and_units(char * model_name, error->all(FLERR,"KIM Model does not support the requested unit system"); } } else if (KIM_CollectionItemType_Equal( - itemType, KIM_COLLECTION_ITEM_TYPE_simulatorModel)) { - KIM_SimulatorModel * kim_SM; - kim_error = KIM_SimulatorModel_Create(model_name, &kim_SM); + itemType, KIM_COLLECTION_ITEM_TYPE_simulatorModel)) { + KIM_SimulatorModel * simulatorModel; + kim_error = KIM_SimulatorModel_Create(model_name, &simulatorModel); if (kim_error) - error->all(FLERR,"Unable to load KIM Simulator Model."); + error->all(FLERR,"Unable to load KIM Simulator Model"); model_type = SM; + logID = fmt::format("{}_SimulatorModel", comm->me); + KIM_SimulatorModel_SetLogID(simulatorModel, logID.c_str()); + int sim_fields; int sim_lines; char const * sim_field; char const * sim_value; - KIM_SimulatorModel_GetNumberOfSimulatorFields(kim_SM, &sim_fields); - KIM_SimulatorModel_CloseTemplateMap(kim_SM); + KIM_SimulatorModel_GetNumberOfSimulatorFields(simulatorModel, &sim_fields); + KIM_SimulatorModel_CloseTemplateMap(simulatorModel); for (int i=0; i < sim_fields; ++i) { KIM_SimulatorModel_GetSimulatorFieldMetadata( - kim_SM,i,&sim_lines,&sim_field); + simulatorModel, i, &sim_lines, &sim_field); if (0 == strcmp(sim_field,"units")) { - KIM_SimulatorModel_GetSimulatorFieldLine(kim_SM,i,0,&sim_value); + KIM_SimulatorModel_GetSimulatorFieldLine( + simulatorModel, i, 0, &sim_value); int len=strlen(sim_value)+1; - *model_units = new char[len]; strcpy(*model_units,sim_value); + *model_units = new char[len]; + strcpy(*model_units,sim_value); break; } } - KIM_SimulatorModel_Destroy(&kim_SM); + KIM_SimulatorModel_Destroy(&simulatorModel); if ((! unit_conversion_mode) && (strcmp(*model_units, user_units)!=0)) { - std::string mesg("Incompatible units for KIM Simulator Model, " - "required units = "); - mesg += *model_units; - error->all(FLERR,mesg); + error->all(FLERR,fmt::format("Incompatible units for KIM Simulator Model" + ", required units = {}", *model_units)); } } } @@ -295,13 +309,16 @@ void KimInit::do_init(char *model_name, char *user_units, char *model_units, KIM KIM_SimulatorModel * simulatorModel; if (model_type == SM) { int kim_error = - KIM_SimulatorModel_Create(model_name,&simulatorModel); + KIM_SimulatorModel_Create(model_name, &simulatorModel); if (kim_error) - error->all(FLERR,"Unable to load KIM Simulator Model."); + error->all(FLERR,"Unable to load KIM Simulator Model"); + + auto logID = fmt::format("{}_SimulatorModel", comm->me); + KIM_SimulatorModel_SetLogID(simulatorModel, logID.c_str()); char const *sim_name, *sim_version; KIM_SimulatorModel_GetSimulatorNameAndVersion( - simulatorModel,&sim_name, &sim_version); + simulatorModel, &sim_name, &sim_version); if (0 != strcmp(sim_name,"LAMMPS")) error->all(FLERR,"Incompatible KIM Simulator Model"); @@ -389,7 +406,7 @@ void KimInit::do_init(char *model_name, char *user_units, char *model_units, KIM mesg += fmt::format(" {:<8} | {:<{}} | {:<10} | {}\n",i+1,str_name, max_len,data_type,extent); } - } else mesg += "No mutable parameters. \n"; + } else mesg += "No mutable parameters.\n"; KIM_Model_Destroy(&pkim); input->write_echo(mesg); @@ -447,7 +464,7 @@ void KimInit::do_variables(const std::string &from, const std::string &to) conversion_factor); if (ier != 0) error->all(FLERR,fmt::format("Unable to obtain conversion factor: " - "unit = {}; from = {}; to = {}.", + "unit = {}; from = {}; to = {}", units[i], from, to)); variable->internal_set(v_unit,conversion_factor); @@ -461,23 +478,28 @@ void KimInit::do_variables(const std::string &from, const std::string &to) void KimInit::write_log_cite(char *model_name) { - KIM_Collections * coll; - int err = KIM_Collections_Create(&coll); + KIM_Collections * collections; + int err = KIM_Collections_Create(&collections); if (err) return; + auto logID = fmt::format("{}_Collections", comm->me); + KIM_Collections_SetLogID(collections, logID.c_str()); + int extent; if (model_type == MO) { err = KIM_Collections_CacheListOfItemMetadataFiles( - coll,KIM_COLLECTION_ITEM_TYPE_portableModel,model_name,&extent); + collections, KIM_COLLECTION_ITEM_TYPE_portableModel, + model_name,&extent); } else if (model_type == SM) { err = KIM_Collections_CacheListOfItemMetadataFiles( - coll,KIM_COLLECTION_ITEM_TYPE_simulatorModel,model_name,&extent); + collections, KIM_COLLECTION_ITEM_TYPE_simulatorModel, + model_name, &extent); } else { - error->all(FLERR,"Unknown model type."); + error->all(FLERR,"Unknown model type"); } if (err) { - KIM_Collections_Destroy(&coll); + KIM_Collections_Destroy(&collections); return; } @@ -486,7 +508,8 @@ void KimInit::write_log_cite(char *model_name) int availableAsString; char const * fileString; err = KIM_Collections_GetItemMetadataFile( - coll,i,&fileName,nullptr,nullptr,&availableAsString,&fileString); + collections, i, &fileName, nullptr, nullptr, + &availableAsString, &fileString); if (err) continue; if (0 == strncmp("kimcite",fileName,7)) { @@ -494,5 +517,5 @@ void KimInit::write_log_cite(char *model_name) } } - KIM_Collections_Destroy(&coll); + KIM_Collections_Destroy(&collections); } diff --git a/src/KIM/kim_interactions.cpp b/src/KIM/kim_interactions.cpp index 7eb0289207..713f91b56c 100644 --- a/src/KIM/kim_interactions.cpp +++ b/src/KIM/kim_interactions.cpp @@ -16,6 +16,7 @@ Ryan S. Elliott (UMN) Ellad B. Tadmor (UMN) Ronald Miller (Carleton U) + Yaser Afshar (UMN) ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- @@ -87,6 +88,7 @@ void KimInteractions::command(int narg, char **arg) if (!domain->box_exist) error->all(FLERR,"Must use 'kim_interactions' command after " "simulation box is defined"); + do_setup(narg,arg); } @@ -98,7 +100,11 @@ void KimInteractions::do_setup(int narg, char **arg) if ((narg == 1) && (0 == strcmp("fixed_types",arg[0]))) { fixed_types = true; } else if (narg != atom->ntypes) { - error->all(FLERR,"Illegal kim_interactions command"); + error->all(FLERR,fmt::format("Illegal kim_interactions command.\nThe " + "LAMMPS simulation has {} atom type(s), but " + "{} chemical species passed to the " + "kim_interactions command", + atom->ntypes, narg)); } else { fixed_types = false; } @@ -121,22 +127,20 @@ void KimInteractions::do_setup(int narg, char **arg) input->write_echo("#=== BEGIN kim_interactions ==================================\n"); if (simulatorModel) { - if (!fixed_types) { - std::string delimiter(""); - std::string atom_type_sym_list; - std::string atom_type_num_list; + std::string atom_type_sym_list = + fmt::format("{}", fmt::join(arg, arg + narg, " ")); + + std::string atom_type_num_list = + fmt::format("{}", species_to_atomic_no(arg[0])); - for (int i = 0; i < narg; i++) { - atom_type_sym_list += delimiter + arg[i]; - atom_type_num_list += delimiter + std::to_string(species_to_atomic_no(arg[i])); - delimiter = " "; - } + for (int i = 1; i < narg; ++i) + atom_type_num_list += fmt::format(" {}", species_to_atomic_no(arg[i])); KIM_SimulatorModel_AddTemplateMap( - simulatorModel,"atom-type-sym-list",atom_type_sym_list.c_str()); + simulatorModel, "atom-type-sym-list", atom_type_sym_list.c_str()); KIM_SimulatorModel_AddTemplateMap( - simulatorModel,"atom-type-num-list",atom_type_num_list.c_str()); + simulatorModel, "atom-type-num-list", atom_type_num_list.c_str()); KIM_SimulatorModel_CloseTemplateMap(simulatorModel); // validate species selection @@ -150,14 +154,14 @@ void KimInteractions::do_setup(int narg, char **arg) for (auto atom_type_sym : utils::split_words(atom_type_sym_list)) { species_is_supported = false; if (atom_type_sym == "NULL") continue; - for (int i=0; i < sim_num_species; ++i) { - KIM_SimulatorModel_GetSupportedSpecies(simulatorModel,i,&sim_species); + for (int i = 0; i < sim_num_species; ++i) { + KIM_SimulatorModel_GetSupportedSpecies( + simulatorModel, i, &sim_species); if (atom_type_sym == sim_species) species_is_supported = true; } if (!species_is_supported) { - std::string msg = "Species '"; - msg += atom_type_sym + "' is not supported by this KIM Simulator Model"; - error->all(FLERR,msg); + error->all(FLERR,fmt::format("Species '{}' is not supported by this " + "KIM Simulator Model", atom_type_sym)); } } } else { @@ -169,29 +173,39 @@ void KimInteractions::do_setup(int narg, char **arg) int sim_fields, sim_lines; const char *sim_field, *sim_value; KIM_SimulatorModel_GetNumberOfSimulatorFields(simulatorModel, &sim_fields); - for (int i=0; i < sim_fields; ++i) { + for (int i = 0; i < sim_fields; ++i) { KIM_SimulatorModel_GetSimulatorFieldMetadata( - simulatorModel,i,&sim_lines,&sim_field); + simulatorModel, i, &sim_lines, &sim_field); - if (0 == strcmp(sim_field,"units")) { - KIM_SimulatorModel_GetSimulatorFieldLine(simulatorModel,i,0,&sim_value); - if (0 != strcmp(sim_value,update->unit_style)) + if (strcmp(sim_field,"units") == 0) { + KIM_SimulatorModel_GetSimulatorFieldLine( + simulatorModel, i, 0, &sim_value); + if (strcmp(sim_value,update->unit_style) != 0) error->all(FLERR,"Incompatible units for KIM Simulator Model"); } } - int sim_model_idx=-1; - for (int i=0; i < sim_fields; ++i) { + bool no_model_definition = true; + for (int i = 0; i < sim_fields; ++i) { KIM_SimulatorModel_GetSimulatorFieldMetadata( - simulatorModel,i,&sim_lines,&sim_field); - if (0 == strcmp(sim_field,"model-defn")) { - if (domain->periodicity[0]&&domain->periodicity[1]&&domain->periodicity[2]) input->one("variable kim_periodic equal 1"); - else if (domain->periodicity[0]&&domain->periodicity[1]&&!domain->periodicity[2]) input->one("variable kim_periodic equal 2"); - else input->one("variable kim_periodic equal 0"); - sim_model_idx = i; - for (int j=0; j < sim_lines; ++j) { + simulatorModel, i, &sim_lines, &sim_field); + if (strcmp(sim_field,"model-defn") == 0) { + if (domain->periodicity[0]&& + domain->periodicity[1]&& + domain->periodicity[2]) + input->one("variable kim_periodic equal 1"); + else if (domain->periodicity[0]&& + domain->periodicity[1]&& + !domain->periodicity[2]) + input->one("variable kim_periodic equal 2"); + else input->one("variable kim_periodic equal 0"); + + // KIM Simulator Model has a Model definition + no_model_definition = false; + + for (int j = 0; j < sim_lines; ++j) { KIM_SimulatorModel_GetSimulatorFieldLine( - simulatorModel,sim_model_idx,j,&sim_value); + simulatorModel, i, j, &sim_value); if (utils::strmatch(sim_value,"^KIM_SET_TYPE_PARAMETERS")) { // Notes regarding the KIM_SET_TYPE_PARAMETERS command // * This is an INTERNAL command. @@ -212,7 +226,7 @@ void KimInteractions::do_setup(int narg, char **arg) } } - if (sim_model_idx < 0) + if (no_model_definition) error->all(FLERR,"KIM Simulator Model has no Model definition"); KIM_SimulatorModel_OpenAndInitializeTemplateMap(simulatorModel); @@ -227,14 +241,9 @@ void KimInteractions::do_setup(int narg, char **arg) // NOTE: all references to arg must appear before calls to input->one() // as that will reset the argument vector. - std::string cmd1("pair_style kim "); - cmd1 += model_name; - - std::string cmd2("pair_coeff * * "); - for (int i=0; i < narg; ++i) { - cmd2 += arg[i]; - cmd2 += " "; - } + auto cmd1 = fmt::format("pair_style kim {}", model_name); + auto cmd2 = + fmt::format("pair_coeff * * {}", fmt::join(arg, arg + narg, " ")); input->one(cmd1); input->one(cmd2); @@ -248,22 +257,25 @@ void KimInteractions::do_setup(int narg, char **arg) void KimInteractions::KIM_SET_TYPE_PARAMETERS(const std::string &input_line) const { - int nocomment; auto words = utils::split_words(input_line); - std::string key = words[1]; + const std::string key = words[1]; + if (key != "pair" && key != "charge") + error->one(FLERR,fmt::format("Unrecognized KEY {} for " + "KIM_SET_TYPE_PARAMETERS command", key)); + std::string filename = words[2]; std::vector species(words.begin()+3,words.end()); if ((int)species.size() != atom->ntypes) error->one(FLERR,"Incorrect args for KIM_SET_TYPE_PARAMETERS command"); - FILE *fp; - fp = fopen(filename.c_str(),"r"); - if (fp == nullptr) { - error->one(FLERR,"Parameter file not found"); + FILE *fp = nullptr; + if (comm->me == 0) { + fp = fopen(filename.c_str(),"r"); + if (fp == nullptr) error->one(FLERR,"Parameter file not found"); } - char line[MAXLINE],*ptr; + char line[MAXLINE], *ptr; int n, eof = 0; while (1) { @@ -279,27 +291,24 @@ void KimInteractions::KIM_SET_TYPE_PARAMETERS(const std::string &input_line) con MPI_Bcast(&n,1,MPI_INT,0,world); MPI_Bcast(line,n,MPI_CHAR,0,world); - nocomment = line[0] != '#'; + if (ptr = strchr(line,'#')) *ptr = '\0'; + if (strspn(line," \t\n\r") == strlen(line)) continue; - if(nocomment) { - words = utils::split_words(line); - if (key == "pair") { - for (int ia = 0; ia < atom->ntypes; ++ia) { - for (int ib = ia; ib < atom->ntypes; ++ib) - if (((species[ia] == words[0]) && (species[ib] == words[1])) - || ((species[ib] == words[0]) && (species[ia] == words[1]))) - input->one(fmt::format("pair_coeff {} {} {}",ia+1,ib+1,fmt::join(words.begin()+2,words.end()," "))); - } - } else if (key == "charge") { - for (int ia = 0; ia < atom->ntypes; ++ia) - if (species[ia] == words[0]) - input->one(fmt::format("set type {} charge {}",ia+1,words[1])); - } else { - error->one(FLERR,"Unrecognized KEY for KIM_SET_TYPE_PARAMETERS command"); + words = utils::split_words(line); + if (key == "pair") { + for (int ia = 0; ia < atom->ntypes; ++ia) { + for (int ib = ia; ib < atom->ntypes; ++ib) + if (((species[ia] == words[0]) && (species[ib] == words[1])) + || ((species[ib] == words[0]) && (species[ia] == words[1]))) + input->one(fmt::format("pair_coeff {} {} {}",ia+1,ib+1, + fmt::join(words.begin()+2,words.end()," "))); } + } else { + for (int ia = 0; ia < atom->ntypes; ++ia) + if (species[ia] == words[0]) + input->one(fmt::format("set type {} charge {}",ia+1,words[1])); } } - fclose(fp); } /* ---------------------------------------------------------------------- */ diff --git a/src/KIM/kim_param.cpp b/src/KIM/kim_param.cpp index 900e13e09c..0927a467bf 100644 --- a/src/KIM/kim_param.cpp +++ b/src/KIM/kim_param.cpp @@ -57,6 +57,7 @@ #include "kim_param.h" +#include "comm.h" #include "error.h" #include "fix_store_kim.h" #include "force.h" @@ -65,8 +66,9 @@ #include "pair_kim.h" #include "variable.h" +#include #include -#include +#include extern "C" { @@ -118,8 +120,11 @@ void get_kim_unit_names( chargeUnit = KIM_CHARGE_UNIT_e; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_fs; - } else if ((strcmp(system, "lj") == 0)) { - error->all(FLERR, "LAMMPS unit_style lj not supported by KIM models"); + } else if (strcmp(system,"lj") == 0 || + strcmp(system,"micro") ==0 || + strcmp(system,"nano")==0) { + error->all(FLERR,fmt::format("LAMMPS unit_style {} not supported " + "by KIM models", system)); } else error->all(FLERR, "Unknown unit_style"); } @@ -240,6 +245,9 @@ void KimParam::command(int narg, char **arg) &pkim); if (kim_error) error->all(FLERR, "Unable to create KIM Portable Model"); + + auto logID = fmt::format("{}_Model", comm->me); + KIM_Model_SetLogID(pkim, logID.c_str()); } } @@ -253,7 +261,7 @@ void KimParam::command(int narg, char **arg) // Parameter name char *paramname = nullptr; // Variable name - char *varname = nullptr; + std::string varname; // Loop over all the arguments for (int i = 1; i < narg;) { @@ -277,15 +285,13 @@ void KimParam::command(int narg, char **arg) if (kim_error) error->all(FLERR, "KIM GetParameterMetadata returned error"); - if (strcmp(paramname, str_name) == 0) - break; + if (strcmp(paramname, str_name) == 0) break; } if (param_index >= numberOfParameters) { - std::string msg("Wrong argument in kim_param get command.\n"); - msg += "This Model does not have the requested '"; - msg += paramname; - msg += "' parameter"; + auto msg = fmt::format("Wrong argument in kim_param get command.\n" + "This Model does not have the requested '{}' " + "parameter", paramname); error->all(FLERR, msg); } @@ -299,60 +305,53 @@ void KimParam::command(int narg, char **arg) // Check to see if the indices range contains // only integer numbers and/or range : if (argtostr.find_first_not_of("0123456789:") != std::string::npos) { - std::string msg("Illegal index_range.\n"); - msg += "Expected integer parameter(s) instead of '"; - msg += argtostr; - msg += "' in index_range"; + auto msg = fmt::format("Illegal index_range.\nExpected integer " + "parameter(s) instead of '{}' in " + "index_range", argtostr); error->all(FLERR, msg); } std::string::size_type npos = argtostr.find(':'); if (npos != std::string::npos) { argtostr[npos] = ' '; - std::stringstream str(argtostr); - str >> nlbound >> nubound; + auto words = utils::split_words(argtostr); + nlbound = atoi(words[0].c_str()); + nubound = atoi(words[1].c_str()); + if (nubound < 1 || nubound > extent || nlbound < 1 || nlbound > nubound) { - std::string msg("Illegal index_range '"); - msg += std::to_string(nlbound) + "-"; - msg += std::to_string(nubound) + "' for '"; - msg += paramname; - msg += "' parameter with the extent of '"; - msg += std::to_string(extent); - msg += "'"; + auto msg = fmt::format("Illegal index_range '{}-{}' for '{}' " + "parameter with the extent of '{}'", + nlbound, nubound, paramname, extent); error->all(FLERR, msg); } } else { - std::stringstream str(argtostr); - str >> nlbound; + nlbound = atoi(argtostr.c_str()); + if (nlbound < 1 || nlbound > extent) { - std::string msg("Illegal index '"); - msg += std::to_string(nlbound) + "' for '"; - msg += paramname; - msg += "' parameter with the extent of '"; - msg += std::to_string(extent); - msg += "'"; + auto msg = fmt::format("Illegal index '{}' for '{}' parameter " + "with the extent of '{}'", nlbound, + paramname, extent); error->all(FLERR, msg); } + nubound = nlbound; } } else { - std::string msg("Wrong number of arguments in "); - msg += "'kim_param get' command.\n"; - msg += "Index range after parameter name is mandatory"; + std::string msg("Wrong number of arguments in 'kim_param get' "); + msg += "command.\nIndex range after parameter name is mandatory"; error->all(FLERR, msg); } int const nvars = nubound - nlbound + 1; - char **varsname = nullptr; + std::vector varsname; if (i < narg) { // Get the variable/variable_base name varname = arg[i++]; } else { - std::string msg("Wrong number of arguments in "); - msg += "'kim_param get' command.\n"; - msg += "The LAMMPS variable name is mandatory"; + std::string msg("Wrong number of arguments in 'kim_param get' "); + msg += "command.\nThe LAMMPS variable name is mandatory"; error->all(FLERR, msg); } @@ -362,56 +361,47 @@ void KimParam::command(int narg, char **arg) if (nvars > 1) { if (i < narg) { if (strcmp(arg[i], "split") == 0) { - varsname = new char *[nvars]; + varsname.resize(nvars); for (int j = 0, k = nlbound; j < nvars; ++j, ++k) { - std::stringstream str; - str << varname << "_" << k; - varsname[j] = const_cast(str.str().c_str()); + varsname[j] = fmt::format("{}_{}", varname, k); } } else if (strcmp(arg[i], "list") == 0) { list_requested = true; - varsname = new char *[1]; + varsname.resize(1); varsname[0] = varname; // Default explicit (optional) formatarg } else if (i - 1 + nvars < narg) { - varsname = new char *[nvars]; + varsname.resize(nvars); --i; - for (int j = 0; j < nvars; ++j, ++i) - varsname[j] = arg[i]; + for (int j = 0; j < nvars; ++j, ++i) varsname[j] = arg[i]; if (i < narg) { - if (strcmp(arg[i], "explicit") == 0) - ++i; + if (strcmp(arg[i], "explicit") == 0) ++i; } } else { - std::string msg("Wrong number of arguments in "); - msg += "'kim_param get' command.\nThe LAMMPS '"; - msg += std::to_string(nvars); - msg += "' variable names or '"; - msg += varname; - msg += " split' is mandatory"; + auto msg = + fmt::format("Wrong number of arguments in 'kim_param get' " + "command.\nThe LAMMPS '{}' variable names or " + "'{} split' is mandatory", nvars, varname); error->all(FLERR, msg); } } else { - std::string msg("Wrong number of arguments in "); - msg += "'kim_param get' command.\nThe LAMMPS '"; - msg += std::to_string(nvars); - msg += "' variable names or '"; - msg += varname; - msg += " split/list' is mandatory"; + auto msg = + fmt::format("Wrong number of arguments in 'kim_param get' " + "command.\nThe LAMMPS '{}' variable names or " + "'{} split/list' is mandatory", nvars, varname); error->all(FLERR, msg); } } else { - varsname = new char *[1]; + varsname.resize(1); if (i < narg) { if (strcmp(arg[i], "split") == 0) { - std::stringstream str; - str << varname << "_" << nlbound; - varsname[0] = const_cast(str.str().c_str()); + varsname[0] = fmt::format("{}_{}", varname, nlbound); ++i; } else { if ((strcmp(arg[i], "list") == 0) || - (strcmp(arg[i], "explicit") == 0)) + (strcmp(arg[i], "explicit") == 0)) ++i; + varsname[0] = varname; } } else { @@ -419,98 +409,90 @@ void KimParam::command(int narg, char **arg) } } - char **varcmd = new char *[3]; - varcmd[1] = const_cast("string"); - if (KIM_DataType_Equal(kim_DataType, KIM_DATA_TYPE_Double)) { if (list_requested) { - std::stringstream str; + std::string str; double V; { kim_error = KIM_Model_GetParameterDouble(pkim, param_index, nlbound - 1, &V); if (kim_error) error->all(FLERR, "KIM GetParameterDouble returned error"); - str << V; + + str = fmt::format("{}", V); } for (int j = 1; j < nvars; ++j) { kim_error = KIM_Model_GetParameterDouble(pkim, param_index, nlbound - 1 + j, &V); if (kim_error) error->all(FLERR, "KIM GetParameterDouble returned error"); - str << " " << V; + + str += fmt::format(" {}", V); } - varcmd[0] = varsname[0]; - varcmd[2] = const_cast(str.str().c_str()); - input->variable->set(3, varcmd); - echo_var_assign(varcmd[0], varcmd[2]); + + auto setcmd = fmt::format("{} string {}", varsname[0], str); + input->variable->set(setcmd); + input->write_echo(fmt::format("variable {}\n", setcmd)); + } else { + double V; for (int j = 0; j < nvars; ++j) { - varcmd[0] = varsname[j]; - double V; kim_error = KIM_Model_GetParameterDouble(pkim, param_index, nlbound - 1 + j, &V); if (kim_error) error->all(FLERR, "KIM GetParameterDouble returned error"); - std::stringstream str; - str << V; - varcmd[2] = const_cast(str.str().c_str()); - input->variable->set(3, varcmd); - echo_var_assign(varcmd[0], varcmd[2]); + + auto setcmd = fmt::format("{} string {}", varsname[j], V); + input->variable->set(setcmd); + input->write_echo(fmt::format("variable {}\n", setcmd)); } } } else if (KIM_DataType_Equal(kim_DataType, KIM_DATA_TYPE_Integer)) { if (list_requested) { - std::stringstream str; + std::string str; int V; { kim_error = KIM_Model_GetParameterInteger(pkim, param_index, nlbound - 1, &V); if (kim_error) error->all(FLERR, "KIM GetParameterInteger returned error"); - str << V; + + str = fmt::format("{}", V); } for (int j = 1; j < nvars; ++j) { kim_error = KIM_Model_GetParameterInteger(pkim, param_index, nlbound - 1 + j, &V); if (kim_error) error->all(FLERR, "KIM GetParameterInteger returned error"); - str << " " << V; + + str += fmt::format(" {}", V); } - varcmd[0] = varsname[0]; - varcmd[2] = const_cast(str.str().c_str()); - input->variable->set(3, varcmd); - echo_var_assign(varcmd[0], varcmd[2]); + + auto setcmd = fmt::format("{} string {}", varsname[0], str); + input->variable->set(setcmd); + input->write_echo(fmt::format("variable {}\n", setcmd)); + } else { + int V; for (int j = 0; j < nvars; ++j) { - varcmd[0] = varsname[j]; - int V; kim_error = KIM_Model_GetParameterInteger(pkim, param_index, nlbound - 1 + j, &V); if (kim_error) error->all(FLERR, "KIM GetParameterInteger returned error"); - std::stringstream str; - str << V; - varcmd[2] = const_cast(str.str().c_str()); - input->variable->set(3, varcmd); - echo_var_assign(varcmd[0], varcmd[2]); + + auto setcmd = fmt::format("{} string {}", varsname[j], V); + input->variable->set(setcmd); + input->write_echo(fmt::format("variable {}\n", setcmd)); } } } else error->all(FLERR, "Wrong parameter type"); - - delete[] varcmd; - delete[] varsname; } // End of loop over all the arguments // Set the parameters } else { - std::string set_cmd("pair_coeff * * "); - set_cmd += atom_type_list; - for (int i = 1; i < narg; ++i) { - set_cmd += " "; - set_cmd += arg[i]; - } - input->one(set_cmd); + auto setcmd = fmt::format("pair_coeff * * {} {}", atom_type_list, + fmt::join(arg + 1, arg + narg, " ")); + input->one(setcmd); } } else error->all(FLERR, "This model has No mutable parameters"); @@ -521,12 +503,3 @@ void KimParam::command(int narg, char **arg) input->write_echo(fmt::format("#=== END kim-param {} =====================" "==================\n",kim_param_get_set)); } - -/* ---------------------------------------------------------------------- */ - -void KimParam::echo_var_assign(const std::string &name, - const std::string &value) const -{ - input->write_echo(fmt::format("variable {} string {}\n", - name, value)); -} diff --git a/src/KIM/kim_param.h b/src/KIM/kim_param.h index e4fc5ce59a..3e20207cca 100644 --- a/src/KIM/kim_param.h +++ b/src/KIM/kim_param.h @@ -77,9 +77,6 @@ public: ~KimParam(); void command(int, char **); - -private: - void echo_var_assign(const std::string &name, const std::string &value) const; }; } // namespace LAMMPS_NS diff --git a/src/KIM/kim_property.cpp b/src/KIM/kim_property.cpp index 88fa16e60a..17d8778c7a 100644 --- a/src/KIM/kim_property.cpp +++ b/src/KIM/kim_property.cpp @@ -100,11 +100,7 @@ void kimProperty::command(int narg, char **arg) error->all(FLERR, msg); } - if (comm->me == 0) { - std::string msg; - msg = "#=== kim-property ===========================================\n"; - input->write_echo(msg); - } + input->write_echo("#=== kim-property ===========================================\n"); // Get the kim_str ptr to the data associated with a kim_property_str // variable diff --git a/src/KIM/kim_query.cpp b/src/KIM/kim_query.cpp index 0b0d5e97ad..e7b308625b 100644 --- a/src/KIM/kim_query.cpp +++ b/src/KIM/kim_query.cpp @@ -63,11 +63,15 @@ #include "info.h" #include "input.h" #include "modify.h" +#include "utils.h" #include "variable.h" #include "version.h" +#include "tokenizer.h" +#include "fmt/format.h" +#include #include -#include +#include #if defined(LMP_KIM_CURL) #include @@ -92,26 +96,28 @@ static size_t write_callback(void *, size_t, size_t, void *); void KimQuery::command(int narg, char **arg) { - char *varname, *function, *value; - if (narg < 2) error->all(FLERR,"Illegal kim_query command"); // check if we had a kim_init command by finding fix STORE/KIM // retrieve model name. - char * model_name; + char *model_name; - int ifix = modify->find_fix("KIM_MODEL_STORE"); + const int ifix = modify->find_fix("KIM_MODEL_STORE"); if (ifix >= 0) { FixStoreKIM *fix_store = (FixStoreKIM *) modify->fix[ifix]; model_name = (char *)fix_store->getptr("model_name"); } else error->all(FLERR,"Must use 'kim_init' before 'kim_query'"); - varname = arg[0]; + char *varname = arg[0]; + bool split = false; - if (0 == strcmp("split",arg[1])) { - if (narg == 2) error->all(FLERR,"Illegal kim_query command"); - if (0 == strcmp("list",arg[2])) - error->all(FLERR,"Illegal kim_query command"); + if (strcmp("split",arg[1]) == 0) { + if (narg == 2) error->all(FLERR,"Illegal kim_query command.\nThe keyword " + "'split' must be followed by the name of " + "the query function"); + if (strcmp("list",arg[2]) == 0) + error->all(FLERR,"Illegal kim_query command.\nThe 'list' keyword " + "can not be used after 'split'"); split = true; arg++; narg--; @@ -119,78 +125,69 @@ void KimQuery::command(int narg, char **arg) // The “list” is the default setting // the result is returned as a space-separated list of values in variable - if (0 == strcmp("list",arg[1])) { - if (narg == 2) error->all(FLERR,"Illegal kim_query command"); - if (split) error->all(FLERR,"Illegal kim_query command"); + if (strcmp("list",arg[1]) == 0) { + if (narg == 2) error->all(FLERR,"Illegal kim_query command.\nThe 'list' " + "keyword must be followed by ('split' " + "and) the name of the query function"); arg++; narg--; } - function = arg[1]; - for (int i = 2; i < narg; ++i) { - if (0 == strncmp("model=",arg[i], 6)) { - error->all(FLERR,"Illegal 'model' key in kim_query command"); - } - } + char *function = arg[1]; + for (int i = 2; i < narg; ++i) { + if (strncmp("model=",arg[i],6) == 0) + error->all(FLERR,"Illegal 'model' key in kim_query command"); + + if (!strchr(arg[i], '=') || !strchr(arg[i], '[') || !strchr(arg[i], ']')) + error->all(FLERR,fmt::format("Illegal query format.\nInput argument of " + "`{}` to kim_query is wrong. The query " + "format is the keyword=[value], where value " + "is always an array of one or more " + "comma-separated items", arg[i])); + } #if defined(LMP_KIM_CURL) - value = do_query(function, model_name, narg-2, arg+2, comm->me, world); + char *value = do_query(function, model_name, narg-2, arg+2, comm->me, world); // check for valid result // on error the content of "value" is a '\0' byte // as the first element, and then the error message // that was returned by the web server - char errmsg[1024]; - if (0 == strlen(value)) { - sprintf(errmsg,"OpenKIM query failed: %s",value+1); - error->all(FLERR,errmsg); - } else if (0 == strcmp(value,"EMPTY")) { - sprintf(errmsg,"OpenKIM query returned no results"); - error->all(FLERR,errmsg); + if (strlen(value) == 0) { + error->all(FLERR,fmt::format("OpenKIM query failed: {}", value+1)); + } else if (strcmp(value,"EMPTY") == 0) { + error->all(FLERR,fmt::format("OpenKIM query returned no results")); } input->write_echo("#=== BEGIN kim-query =========================================\n"); - char **varcmd = new char*[3]; - varcmd[1] = (char *) "string"; - - std::stringstream ss(value); - std::string token; - + ValueTokenizer values(value, ","); if (split) { int counter = 1; - while(std::getline(ss, token, ',')) { - token.erase(0,token.find_first_not_of(" \n\r\t")); // ltrim - token.erase(token.find_last_not_of(" \n\r\t") + 1); // rtrim - std::stringstream splitname; - splitname << varname << "_" << counter++; - varcmd[0] = const_cast(splitname.str().c_str()); - varcmd[2] = const_cast(token.c_str()); - input->variable->set(3,varcmd); - echo_var_assign(splitname.str(), varcmd[2]); + while (values.has_next()) { + auto svalue = values.next_string(); + auto setcmd = fmt::format("{}_{} string {}", varname, counter++, svalue); + input->variable->set(setcmd); + input->write_echo(fmt::format("variable {}\n", setcmd)); } } else { - varcmd[0] = varname; - std::string value_string; - while(std::getline(ss, token, ',')) { - token.erase(0,token.find_first_not_of(" \n\r\t")); // ltrim - token.erase(token.find_last_not_of(" \n\r\t") + 1); // rtrim - if (value_string.size() && token.size()) - value_string += " "; - value_string += token; + auto svalue = values.next_string(); + std::string setcmd = fmt::format("{} string \"{}", varname, svalue); + while (values.has_next()) { + svalue = values.next_string(); + setcmd += fmt::format(" {}", svalue); } - varcmd[2] = const_cast(value_string.c_str());; - input->variable->set(3,varcmd); - echo_var_assign(varname, value_string); + setcmd += "\""; + input->variable->set(setcmd); + input->write_echo(fmt::format("variable {}\n", setcmd)); } input->write_echo("#=== END kim-query ===========================================\n\n"); - delete[] varcmd; delete[] value; #else error->all(FLERR,"Cannot use 'kim_query' command when KIM package " - "is compiled without support for libcurl"); + "is compiled without support for libcurl"); #endif } @@ -201,17 +198,18 @@ void KimQuery::command(int narg, char **arg) size_t write_callback(void *data, size_t size, size_t nmemb, void *userp) { struct WriteBuf *buf = (struct WriteBuf *)userp; - size_t buffer_size = size*nmemb; // copy chunks into the buffer for as long as there is space left if (buf->sizeleft) { - size_t copy_this_much = buf->sizeleft; - if (copy_this_much > buffer_size) - copy_this_much = buffer_size; + const size_t buffer_size = size * nmemb; + const size_t copy_this_much = + buf->sizeleft > buffer_size ? buffer_size : buf->sizeleft; + memcpy(buf->dataptr, data, copy_this_much); buf->dataptr += copy_this_much; buf->sizeleft -= copy_this_much; + return copy_this_much; } return 0; // done @@ -220,16 +218,12 @@ size_t write_callback(void *data, size_t size, size_t nmemb, void *userp) char *do_query(char *qfunction, char * model_name, int narg, char **arg, int rank, MPI_Comm comm) { - char value[512], *retval; + char value[512]; // run the web query from rank 0 only if (rank == 0) { - CURL *handle; - CURLcode res; - // set up and clear receive buffer - struct WriteBuf buf; buf.dataptr = value; buf.sizeleft = 511; @@ -237,19 +231,43 @@ char *do_query(char *qfunction, char * model_name, int narg, char **arg, // create curl web query instance curl_global_init(CURL_GLOBAL_DEFAULT); - handle = curl_easy_init(); + CURL *handle = curl_easy_init(); if (handle) { - std::string url("https://query.openkim.org/api/"); - url += qfunction; - - std::string query(arg[0]); - query += "&model=[\""; - query += model_name; - query += "\"]"; - for (int i=1; i < narg; ++i) { - query += '&'; - query += arg[i]; + auto url = fmt::format("https://query.openkim.org/api/{}", qfunction); + auto query = fmt::format("model=[\"{}\"]", model_name); + for (int i = 0; i < narg; ++i) { + ValueTokenizer values(arg[i], "=[]"); + std::string key = values.next_string(); + std::string val = values.next_string(); + std::string::size_type n = val.find(","); + if (n == std::string::npos) { + if (utils::is_integer(val) || + utils::is_double(val) || + (val.front() == '"' && + val.back() == '"')) { + query += fmt::format("&{}", arg[i]); + } else { + query += fmt::format("&{}=[\"{}\"]", key, val); + } + } else { + query += fmt::format("&{}=[", key); + while (n != std::string::npos){ + std::string sval = val.substr(0, n); + if (utils::is_integer(sval) || + utils::is_double(sval) || + (val.front() == '"' && + val.back() == '"')) { + query += fmt::format("{},", sval); + } else { + query += fmt::format("\"{}\",", sval); + } + val = val.substr(n + 1); + n = val.find(","); + } + if (val.size()) query += fmt::format("\"{}\"]", val); + else query[query.size() - 1]=']'; + } } #if LMP_DEBUG_CURL @@ -274,23 +292,21 @@ char *do_query(char *qfunction, char * model_name, int narg, char **arg, } } - std::string user_agent = std::string("kim_query--LAMMPS/") - + LAMMPS_VERSION - + " (" + Info::get_os_info() + ")"; + std::string user_agent = fmt::format("kim_query--LAMMPS/{} ({})", + LAMMPS_VERSION, Info::get_os_info()); + curl_easy_setopt(handle, CURLOPT_USERAGENT, user_agent.c_str()); - curl_easy_setopt(handle, CURLOPT_URL, url.c_str()); curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(handle, CURLOPT_POSTFIELDS, query.c_str()); - - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION,write_callback); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(handle, CURLOPT_WRITEDATA,&buf); // perform OpenKIM query and check for errors - res = curl_easy_perform(handle); + CURLcode res = curl_easy_perform(handle); if (res != CURLE_OK) { // on error we return an "empty" string but add error message after it - value[0]= '\0'; + value[0] = '\0'; strcpy(value+1,curl_easy_strerror(res)); } curl_easy_cleanup(handle); @@ -302,30 +318,31 @@ char *do_query(char *qfunction, char * model_name, int narg, char **arg, // we must make a proper copy of the query, as the stack allocation // for "value" will go out of scope. a valid query has a '[' as // the first character. skip over it (and the last character ']', too) - // an error messages starts with a '\0' character. copy that and + // an error message starts with a '\0' character. copy that and // the remaining string, as that is the error message. + char *retval; + // a valid query has a '[' as the first character if (value[0] == '[') { - int len = strlen(value)-1; + int len = strlen(value) - 1; if (value[len] == ']') { - retval = new char[len]; value[len] = '\0'; - if (0 == strcmp(value+1, "")) { - strcpy(retval,"EMPTY"); - } else - strcpy(retval,value+1); + retval = new char[len]; + if (strcmp(value+1, "") == 0) strcpy(retval,"EMPTY"); + else strcpy(retval,value+1); } else { retval = new char[len+2]; retval[0] = '\0'; strcpy(retval+1,value); } + // an error message starts with a '\0' character } else if (value[0] == '\0') { int len = strlen(value+1)+2; retval = new char[len]; retval[0] = '\0'; strcpy(retval+1,value+1); + // unknown response type. we should not get here. } else { - // unknown response type. we should not get here. // we return an "empty" string but add error message after it int len = strlen(value)+2; retval = new char[len]; @@ -335,11 +352,3 @@ char *do_query(char *qfunction, char * model_name, int narg, char **arg, return retval; } #endif - -/* ---------------------------------------------------------------------- */ - -void KimQuery::echo_var_assign(const std::string &name, - const std::string &value) const -{ - input->write_echo(fmt::format("variable {} string {}\n",name,value)); -} diff --git a/src/KIM/kim_query.h b/src/KIM/kim_query.h index e1c49ed71d..f2523f5a98 100644 --- a/src/KIM/kim_query.h +++ b/src/KIM/kim_query.h @@ -13,7 +13,8 @@ /* ---------------------------------------------------------------------- Contributing authors: Axel Kohlmeyer (Temple U), - Ryan S. Elliott (UMN) + Ryan S. Elliott (UMN), + Yaser Afshar (UMN) ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- @@ -71,9 +72,6 @@ class KimQuery : protected Pointers { public: KimQuery(class LAMMPS *lmp) : Pointers(lmp) {}; void command(int, char **); - private: - void echo_var_assign(const std::string &name, const std::string &value) - const; }; } diff --git a/src/KIM/pair_kim.cpp b/src/KIM/pair_kim.cpp index 82dae0ded8..d1eae6123b 100644 --- a/src/KIM/pair_kim.cpp +++ b/src/KIM/pair_kim.cpp @@ -67,8 +67,9 @@ #include "neighbor.h" #include "update.h" +#include #include -#include +#include using namespace LAMMPS_NS; @@ -204,8 +205,8 @@ void PairKIM::compute(int eflag, int vflag) KIM_COMPUTE_ARGUMENT_NAME_particleContributing, kim_particleContributing); if (kimerror) - error->all(FLERR, - "Unable to set KIM particle species codes and/or contributing"); + error->all(FLERR,"Unable to set KIM particle species " + "codes and/or contributing"); } // kim_particleSpecies = KIM atom species for each LAMMPS atom @@ -339,7 +340,9 @@ void PairKIM::coeff(int narg, char **arg) // insure I,J args are * * if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0) - error->all(FLERR,"Incorrect args for pair coefficients"); + error->all(FLERR,"Incorrect args for pair coefficients.\nThe first two " + "arguments of pair_coeff command must be * * to span " + "all LAMMPS atom types"); int ilo,ihi,jlo,jhi; utils::bounds(FLERR,arg[0],1,atom->ntypes,ilo,ihi,error); @@ -410,9 +413,8 @@ void PairKIM::coeff(int narg, char **arg) if (supported) { kim_particle_codes[i] = code; } else { - std::string msg("create_kim_particle_codes: symbol not found: "); - msg += lmps_unique_elements[i]; - error->all(FLERR, msg); + error->all(FLERR,fmt::format("GetSpeciesSupportAndCode: symbol not " + "found: {}",lmps_unique_elements[i])); } } // Set the new values for PM parameters @@ -421,11 +423,9 @@ void PairKIM::coeff(int narg, char **arg) int numberOfParameters(0); KIM_Model_GetNumberOfParameters(pkim, &numberOfParameters); - if (!numberOfParameters) { - std::string msg("Incorrect args for pair coefficients \n"); - msg += "This model has No mutable parameters"; - error->all(FLERR, msg); - } + if (!numberOfParameters) + error->all(FLERR,"Incorrect args for pair coefficients\n" + "This model has No mutable parameters"); int kimerror; @@ -456,11 +456,10 @@ void PairKIM::coeff(int narg, char **arg) } if (param_index >= numberOfParameters) { - std::string msg("Wrong argument for pair coefficients.\n"); - msg += "This Model does not have the requested '"; - msg += paramname; - msg += "' parameter"; - error->all(FLERR, msg); + auto msg = fmt::format("Wrong argument for pair coefficients.\n" + "This Model does not have the requested " + "'{}' parameter", paramname); + error->all(FLERR,msg); } // Get the index_range for the requested parameter @@ -472,48 +471,41 @@ void PairKIM::coeff(int narg, char **arg) // Check to see if the indices range contains only integer numbers & : if (argtostr.find_first_not_of("0123456789:") != std::string::npos) { - std::string msg("Illegal index_range.\n"); - msg += "Expected integer parameter(s) instead of '"; - msg += argtostr; - msg += "' in index_range"; - error->all(FLERR, msg); + auto msg = fmt::format("Illegal index_range.\nExpected integer " + "parameter(s) instead of '{}' in " + "index_range", argtostr); + error->all(FLERR,msg); } std::string::size_type npos = argtostr.find(':'); if (npos != std::string::npos) { argtostr[npos] = ' '; - std::stringstream str(argtostr); - str >> nlbound >> nubound; + auto words = utils::split_words(argtostr); + nlbound = atoi(words[0].c_str()); + nubound = atoi(words[1].c_str()); + if (nubound < 1 || nubound > extent || nlbound < 1 || nlbound > nubound) { - std::string msg("Illegal index_range '"); - msg += std::to_string(nlbound) + "-" ; - msg += std::to_string(nubound) + "' for '"; - msg += paramname; - msg += "' parameter with the extent of '"; - msg += std::to_string(extent); - msg += "'"; - error->all(FLERR, msg); + auto msg = fmt::format("Illegal index_range '{}-{}' for '{}' " + "parameter with the extent of '{}'", + nlbound, nubound, paramname, extent); + error->all(FLERR,msg); } } else { - std::stringstream str(argtostr); - str >> nlbound; + nlbound = atoi(argtostr.c_str()); + if (nlbound < 1 || nlbound > extent) { - std::string msg("Illegal index '"); - msg += std::to_string(nlbound) + "' for '"; - msg += paramname; - msg += "' parameter with the extent of '"; - msg += std::to_string(extent); - msg += "'"; - error->all(FLERR, msg); + auto msg = fmt::format("Illegal index '{}' for '{}' parameter " + "with the extent of '{}'", nlbound, + paramname, extent); + error->all(FLERR,msg); } + nubound = nlbound; } } else { - std::string msg = - "Wrong number of arguments for pair coefficients.\n"; - msg += "Index range after parameter name is mandatory"; - error->all(FLERR, msg); + error->all(FLERR,"Wrong number of arguments for pair coefficients.\n" + "Index range after parameter name is mandatory"); } // Parameter values @@ -524,7 +516,7 @@ void PairKIM::coeff(int narg, char **arg) kimerror = KIM_Model_SetParameterDouble(pkim, param_index, nlbound - 1 + j, V); if (kimerror) - error->all(FLERR, "KIM SetParameterDouble returned error"); + error->all(FLERR,"KIM SetParameterDouble returned error"); } } else if (KIM_DataType_Equal(kim_DataType, KIM_DATA_TYPE_Integer)) { for (int j = 0; j < nubound - nlbound + 1; ++j) { @@ -532,25 +524,22 @@ void PairKIM::coeff(int narg, char **arg) kimerror = KIM_Model_SetParameterInteger(pkim, param_index, nlbound - 1 + j, V); if (kimerror) - error->all(FLERR, "KIM SetParameterInteger returned error"); + error->all(FLERR,"KIM SetParameterInteger returned error"); } } else - error->all(FLERR, "Wrong parameter type to update"); + error->all(FLERR,"Wrong parameter type to update"); } else { - std::string msg = - "Wrong number of variable values for pair coefficients.\n"; - msg += "'"; - msg += std::to_string(nubound - nlbound + 1); - msg += "' values are requested for '"; - msg += paramname; - msg += "' parameter."; - error->all(FLERR, msg); + auto msg = fmt::format("Wrong number of variable values for pair " + "coefficients.\n'{}' values are requested " + "for '{}' parameter", nubound - nlbound + 1, + paramname); + error->all(FLERR,msg); } } kimerror = KIM_Model_ClearThenRefresh(pkim); if (kimerror) - error->all(FLERR, "KIM KIM_Model_ClearThenRefresh returned error"); + error->all(FLERR,"KIM KIM_Model_ClearThenRefresh returned error"); } } @@ -842,11 +831,13 @@ void PairKIM::kim_init() else if (!requestedUnitsAccepted) error->all(FLERR,"KIM Model did not accept the requested unit system"); + auto logID = fmt::format("{}_Model", comm->me); + KIM_Model_SetLogID(pkim, logID.c_str()); + // check that the model does not require unknown capabilities kimerror = check_for_routine_compatibility(); if (kimerror) - error->all(FLERR, - "KIM Model requires unknown Routines. Unable to proceed"); + error->all(FLERR,"KIM Model requires unknown Routines. Unable to proceed"); kimerror = KIM_Model_ComputeArgumentsCreate(pkim, &pargs); if (kimerror) { @@ -854,6 +845,9 @@ void PairKIM::kim_init() error->all(FLERR,"KIM ComputeArgumentsCreate failed"); } else kim_init_ok = true; + logID = fmt::format("{}_ComputeArguments", comm->me); + KIM_ComputeArguments_SetLogID(pargs, logID.c_str()); + // determine KIM Model capabilities (used in this function below) set_kim_model_has_flags(); @@ -985,43 +979,46 @@ void PairKIM::set_lmps_flags() error->all(FLERR,"pair_kim does not support hybrid"); // determine unit system and set lmps_units flag - if ((strcmp(update->unit_style,"real")==0)) { + if (strcmp(update->unit_style,"real") == 0) { lmps_units = REAL; lengthUnit = KIM_LENGTH_UNIT_A; energyUnit = KIM_ENERGY_UNIT_kcal_mol; chargeUnit = KIM_CHARGE_UNIT_e; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_fs; - } else if ((strcmp(update->unit_style,"metal")==0)) { + } else if (strcmp(update->unit_style,"metal") == 0) { lmps_units = METAL; lengthUnit = KIM_LENGTH_UNIT_A; energyUnit = KIM_ENERGY_UNIT_eV; chargeUnit = KIM_CHARGE_UNIT_e; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_ps; - } else if ((strcmp(update->unit_style,"si")==0)) { + } else if (strcmp(update->unit_style,"si") == 0) { lmps_units = SI; lengthUnit = KIM_LENGTH_UNIT_m; energyUnit = KIM_ENERGY_UNIT_J; chargeUnit = KIM_CHARGE_UNIT_C; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_s; - } else if ((strcmp(update->unit_style,"cgs")==0)) { + } else if (strcmp(update->unit_style,"cgs") == 0) { lmps_units = CGS; lengthUnit = KIM_LENGTH_UNIT_cm; energyUnit = KIM_ENERGY_UNIT_erg; chargeUnit = KIM_CHARGE_UNIT_statC; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_s; - } else if ((strcmp(update->unit_style,"electron")==0)) { + } else if (strcmp(update->unit_style,"electron") == 0) { lmps_units = ELECTRON; lengthUnit = KIM_LENGTH_UNIT_Bohr; energyUnit = KIM_ENERGY_UNIT_Hartree; chargeUnit = KIM_CHARGE_UNIT_e; temperatureUnit = KIM_TEMPERATURE_UNIT_K; timeUnit = KIM_TIME_UNIT_fs; - } else if ((strcmp(update->unit_style,"lj")==0)) { - error->all(FLERR,"LAMMPS unit_style lj not supported by KIM models"); + } else if (strcmp(update->unit_style,"lj") == 0 || + strcmp(update->unit_style,"micro") == 0 || + strcmp(update->unit_style,"nano") == 0) { + error->all(FLERR,fmt::format("LAMMPS unit_style {} not supported " + "by KIM models", update->unit_style)); } else { error->all(FLERR,"Unknown unit_style"); } @@ -1102,29 +1099,33 @@ void PairKIM::set_kim_model_has_flags() KIM_SUPPORT_STATUS_required)) { std::string msg("KIM Model requires unsupported compute argument: "); msg += KIM_ComputeArgumentName_ToString(computeArgumentName); - error->all(FLERR, msg); + error->all(FLERR,msg); } } - if (KIM_SupportStatus_Equal(kim_model_support_for_energy, - KIM_SUPPORT_STATUS_notSupported)) - error->warning(FLERR,"KIM Model does not provide `partialEnergy'; " - "Potential energy will be zero"); + if (comm->me == 0) { + if (KIM_SupportStatus_Equal(kim_model_support_for_energy, + KIM_SUPPORT_STATUS_notSupported)) + error->warning(FLERR,"KIM Model does not provide 'partialEnergy'; " + "Potential energy will be zero"); - if (KIM_SupportStatus_Equal(kim_model_support_for_forces, - KIM_SUPPORT_STATUS_notSupported)) - error->warning(FLERR,"KIM Model does not provide `partialForce'; " - "Forces will be zero"); + if (KIM_SupportStatus_Equal(kim_model_support_for_forces, + KIM_SUPPORT_STATUS_notSupported)) + error->warning(FLERR,"KIM Model does not provide 'partialForce'; " + "Forces will be zero"); - if (KIM_SupportStatus_Equal(kim_model_support_for_particleEnergy, - KIM_SUPPORT_STATUS_notSupported)) - error->warning(FLERR,"KIM Model does not provide `partialParticleEnergy'; " - "energy per atom will be zero"); + if (KIM_SupportStatus_Equal(kim_model_support_for_particleEnergy, + KIM_SUPPORT_STATUS_notSupported)) + error->warning(FLERR,"KIM Model does not provide " + "'partialParticleEnergy'; " + "energy per atom will be zero"); - if (KIM_SupportStatus_Equal(kim_model_support_for_particleVirial, - KIM_SUPPORT_STATUS_notSupported)) - error->warning(FLERR,"KIM Model does not provide `partialParticleVirial'; " - "virial per atom will be zero"); + if (KIM_SupportStatus_Equal(kim_model_support_for_particleVirial, + KIM_SUPPORT_STATUS_notSupported)) + error->warning(FLERR,"KIM Model does not provide " + "'partialParticleVirial'; " + "virial per atom will be zero"); + } int numberOfComputeCallbackNames; KIM_COMPUTE_CALLBACK_NAME_GetNumberOfComputeCallbackNames( diff --git a/unittest/commands/test_kim_commands.cpp b/unittest/commands/test_kim_commands.cpp index dd7ac09b19..42e8a441bd 100644 --- a/unittest/commands/test_kim_commands.cpp +++ b/unittest/commands/test_kim_commands.cpp @@ -17,6 +17,7 @@ #include "lammps.h" #include "lmppython.h" #include "modify.h" +#include "output.h" #include "utils.h" #include "variable.h" #include "gmock/gmock.h" @@ -82,17 +83,24 @@ TEST_F(KimCommandsTest, kim_init) { if (!LAMMPS::is_installed_pkg("KIM")) GTEST_SKIP(); - TEST_FAILURE(".*ERROR: Illegal kim_init command.*", lmp->input->one("kim_init");); + TEST_FAILURE(".*ERROR: Illegal kim_init command.*", + lmp->input->one("kim_init");); TEST_FAILURE(".*ERROR: Illegal kim_init command.*", lmp->input->one("kim_init LennardJones_Ar real si");); TEST_FAILURE(".*ERROR: LAMMPS unit_style lj not supported by KIM models.*", lmp->input->one("kim_init LennardJones_Ar lj");); + TEST_FAILURE(".*ERROR: LAMMPS unit_style micro not supported by KIM models.*", + lmp->input->one("kim_init LennardJones_Ar micro");); + TEST_FAILURE(".*ERROR: LAMMPS unit_style nano not supported by KIM models.*", + lmp->input->one("kim_init LennardJones_Ar nano");); TEST_FAILURE(".*ERROR: Unknown unit_style.*", lmp->input->one("kim_init LennardJones_Ar new_style");); TEST_FAILURE(".*ERROR: KIM Model name not found.*", lmp->input->one("kim_init Unknown_Model real");); TEST_FAILURE(".*ERROR: Incompatible units for KIM Simulator Model, required units = metal.*", lmp->input->one("kim_init Sim_LAMMPS_LJcut_AkersonElliott_Alchemy_PbAu real");); + // TEST_FAILURE(".*ERROR: KIM Model does not support the requested unit system.*", + // lmp->input->one("kim_init ex_model_Ar_P_Morse real");); if (!verbose) ::testing::internal::CaptureStdout(); lmp->input->one("kim_init LennardJones_Ar real"); @@ -125,6 +133,17 @@ TEST_F(KimCommandsTest, kim_interactions) lmp->input->one("create_atoms 1 box"); if (!verbose) ::testing::internal::GetCapturedStdout(); + TEST_FAILURE(".*ERROR: Illegal kim_interactions command.*", + lmp->input->one("kim_interactions Ar Ar");); + + if (!verbose) ::testing::internal::CaptureStdout(); + lmp->input->one("clear"); + lmp->input->one("lattice fcc 4.4300"); + lmp->input->one("region box block 0 20 0 20 0 20"); + lmp->input->one("create_box 4 box"); + lmp->input->one("create_atoms 4 box"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + TEST_FAILURE(".*ERROR: Illegal kim_interactions command.*", lmp->input->one("kim_interactions Ar Ar");); @@ -172,6 +191,21 @@ TEST_F(KimCommandsTest, kim_interactions) TEST_FAILURE(".*ERROR: Species 'Ar' is not supported by this KIM Simulator Model.*", lmp->input->one("kim_interactions Ar");); + if (!verbose) ::testing::internal::CaptureStdout(); + lmp->input->one("clear"); + lmp->input->one("kim_init Sim_LAMMPS_LJcut_AkersonElliott_Alchemy_PbAu metal"); + lmp->input->one("lattice fcc 4.08"); + lmp->input->one("region box block 0 10 0 10 0 10"); + lmp->input->one("create_box 1 box"); + lmp->input->one("create_atoms 1 box"); + lmp->input->one("kim_interactions Au"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + // ASSERT_EQ(lmp->output->var_kim_periodic, 1); + // TEST_FAILURE(".*ERROR: Incompatible units for KIM Simulator Model.*", + // lmp->input->one("kim_interactions Au");); + + if (!verbose) ::testing::internal::CaptureStdout(); lmp->input->one("clear"); lmp->input->one("kim_init LennardJones_Ar real"); @@ -302,6 +336,133 @@ TEST_F(KimCommandsTest, kim_property) } } +TEST_F(KimCommandsTest, kim_query) +{ + if (!LAMMPS::is_installed_pkg("KIM")) GTEST_SKIP(); + + TEST_FAILURE(".*ERROR: Illegal kim_query command.*", + lmp->input->one("kim_query");); + TEST_FAILURE(".*ERROR: Must use 'kim_init' before 'kim_query'.*", + lmp->input->one("kim_query a0 get_lattice_constant_cubic");); + + if (!verbose) ::testing::internal::CaptureStdout(); + lmp->input->one("clear"); + lmp->input->one("kim_init LennardJones612_UniversalShifted__MO_959249795837_003 real"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + TEST_FAILURE(".*ERROR: Illegal kim_query command.\nThe keyword 'split' " + "must be followed by the name of the query function.*", + lmp->input->one("kim_query a0 split");); + + TEST_FAILURE(".*ERROR: Illegal kim_query command.\nThe 'list' keyword " + "can not be used after 'split'.*", + lmp->input->one("kim_query a0 split list");); + + TEST_FAILURE(".*ERROR: Illegal kim_query command.\nThe 'list' keyword " + "must be followed by \\('split' and\\) the name of the query " + "function.*", lmp->input->one("kim_query a0 list");); + + TEST_FAILURE(".*ERROR: Illegal 'model' key in kim_query command.*", + lmp->input->one("kim_query a0 get_lattice_constant_cubic " + "model=[MO_959249795837_003]");); + + TEST_FAILURE(".*ERROR: Illegal query format.\nInput argument of `crystal` " + "to kim_query is wrong. The query format is the " + "keyword=\\[value\\], where value is always an array of one " + "or more comma-separated items.*", + lmp->input->one("kim_query a0 get_lattice_constant_cubic " + "crystal");); + + TEST_FAILURE(".*ERROR: Illegal query format.\nInput argument of `" + "crystal=fcc` to kim_query is wrong. The query format is the " + "keyword=\\[value\\], where value is always an array of one " + "or more comma-separated items.*", + lmp->input->one("kim_query a0 get_lattice_constant_cubic " + "crystal=fcc");); + + TEST_FAILURE(".*ERROR: Illegal query format.\nInput argument of `" + "crystal=\\[fcc` to kim_query is wrong. The query format is " + "the keyword=\\[value\\], where value is always an array of " + "one or more comma-separated items.*", + lmp->input->one("kim_query a0 get_lattice_constant_cubic " + "crystal=[fcc");); + + TEST_FAILURE(".*ERROR: Illegal query format.\nInput argument of `" + "crystal=fcc\\]` to kim_query is wrong. The query format is " + "the keyword=\\[value\\], where value is always an array of " + "one or more comma-separated items.*", + lmp->input->one("kim_query a0 get_lattice_constant_cubic " + "crystal=fcc]");); + + std::string squery("kim_query a0 get_lattice_constant_cubic "); + squery += "crystal=[\"fcc\"] species=\"Al\",\"Ni\" units=[\"angstrom\"]"; + + TEST_FAILURE(".*ERROR: Illegal query format.\nInput argument of `species=" + "\"Al\",\"Ni\"` to kim_query is wrong. The query format is " + "the keyword=\\[value\\], where value is always an array of " + "one or more comma-separated items.*", + lmp->input->one(squery);); + + squery = "kim_query a0 get_lattice_constant_cubic "; + squery += "crystal=[\"fcc\"] species=\"Al\",\"Ni\", units=[\"angstrom\"]"; + + TEST_FAILURE(".*ERROR: Illegal query format.\nInput argument of `species=" + "\"Al\",\"Ni\",` to kim_query is wrong. The query format is " + "the keyword=\\[value\\], where value is always an array of " + "one or more comma-separated items.*", + lmp->input->one(squery);); + + squery = "kim_query a0 get_lattice_constant_cubic crystal=[fcc] " + "species=[Al]"; + TEST_FAILURE(".*ERROR: OpenKIM query failed:.*", lmp->input->one(squery);); + + squery = "kim_query a0 get_lattice_constant_cubic crystal=[fcc] " + "units=[\"angstrom\"]"; + TEST_FAILURE(".*ERROR: OpenKIM query failed:.*", lmp->input->one(squery);); + + // if (!verbose) ::testing::internal::CaptureStdout(); + // lmp->input->one("clear"); + // lmp->input->one("kim_init EAM_Dynamo_Mendelev_2007_Zr__MO_848899341753_000 metal"); + + // squery = "kim_query latconst split get_lattice_constant_hexagonal "; + // squery += "crystal=[\"hcp\"] species=[\"Zr\"] units=[\"angstrom\"]"; + // lmp->input->one(squery); + // if (!verbose) ::testing::internal::GetCapturedStdout(); + + // ASSERT_TRUE((std::string(lmp->input->variable->retrieve("latconst_1")) == + // std::string("3.234055244384789"))); + // ASSERT_TRUE((std::string(lmp->input->variable->retrieve("latconst_2")) == + // std::string("5.167650199630013"))); + + // if (!verbose) ::testing::internal::CaptureStdout(); + // lmp->input->one("clear"); + // lmp->input->one("kim_init EAM_Dynamo_Mendelev_2007_Zr__MO_848899341753_000 metal"); + + // squery = "kim_query latconst list get_lattice_constant_hexagonal "; + // squery += "crystal=[hcp] species=[Zr] units=[angstrom]"; + // lmp->input->one(squery); + // if (!verbose) ::testing::internal::GetCapturedStdout(); + + // ASSERT_TRUE((std::string(lmp->input->variable->retrieve("latconst")) == + // std::string("3.234055244384789 5.167650199630013"))); + + // squery = "kim_query latconst list get_lattice_constant_hexagonal "; + // squery += "crystal=[bcc] species=[Zr] units=[angstrom]"; + // TEST_FAILURE(".*ERROR: OpenKIM query failed:.*", lmp->input->one(squery);); + + // if (!verbose) ::testing::internal::CaptureStdout(); + // lmp->input->one("clear"); + // lmp->input->one("kim_init EAM_Dynamo_ErcolessiAdams_1994_Al__MO_123629422045_005 metal"); + + // squery = "kim_query alpha get_linear_thermal_expansion_coefficient_cubic "; + // squery += "crystal=[fcc] species=[Al] units=[1/K] temperature=[293.15] "; + // squery += "temperature_units=[K]"; + // lmp->input->one(squery); + // if (!verbose) ::testing::internal::GetCapturedStdout(); + + // ASSERT_TRUE((std::string(lmp->input->variable->retrieve("alpha")) == + // std::string("1.654960564704273e-05"))); +} } // namespace LAMMPS_NS int main(int argc, char **argv)