@@ -290,33 +290,41 @@ XC_Functional_Libxc::init_func(const std::vector<int> &func_id,
290290 funcs.push_back ({}); // create placeholder
291291 xc_func_init (&funcs.back (), id, xc_polarized); // instantiate the XC term
292292
293- // search for external parameters
294- const std::vector<double > in_built_ext_params = in_built_xc_func_ext_params (id, hybrid_alpha, hse_omega);
295- const std::vector<double > external_ext_params = external_xc_func_ext_params (id);
296- // for temporary use, I name their size as n1 and n2
297- const int n1 = in_built_ext_params.size ();
298- const int n2 = external_ext_params.size ();
293+ // Search for external parameters. User-supplied parameters take precedence
294+ // over ABACUS built-in overrides.
295+ const std::vector<double > in_built_ext_params
296+ = in_built_xc_func_ext_params (id, hybrid_alpha, hse_omega);
297+ const std::vector<double > external_ext_params
298+ = external_xc_func_ext_params (id);
299+ const std::vector<double >& requested_ext_params
300+ = external_ext_params.empty () ? in_built_ext_params : external_ext_params;
299301
300- // #ifdef __DEBUG // will the following assertion cause performance issue?
301- // assert the number of parameters should be either zero or the value from
302- // libxc function xc_func_info_get_n_ext_params, this is to avoid the undefined
303- // behavior of illegal memory access
304- const xc_func_info_type* info = xc_func_get_info (&funcs.back ());
305- const int nref = xc_func_info_get_n_ext_params (info);
306- assert ((n1 == 0 ) || (n1 == nref) || (n2 == 0 ) || (n2 == nref));
307- // #endif
302+ if (!requested_ext_params.empty ())
303+ {
304+ const xc_func_info_type* info = xc_func_get_info (&funcs.back ());
305+ const int nref = xc_func_info_get_n_ext_params (info);
308306
309- // external overwrites in-built if the same functional id is found in both maps
310- const double * xc_func_ext_params =
311- (n2 > 0 ) ? external_ext_params.data () :
312- (n1 > 0 ) ? in_built_ext_params.data () :
313- nullptr ; // nullptr if no external parameters are found
307+ // xc_func_set_ext_params() reads exactly nref entries. Never pass a
308+ // shorter buffer: Libxc may append new parameters in a newer release
309+ // (GGA_C_PBE gained _tscale in Libxc 7.1).
310+ if (requested_ext_params.size () > static_cast <std::size_t >(nref))
311+ {
312+ ModuleBase::WARNING_QUIT (
313+ " XC_Functional_Libxc::init_func" ,
314+ " Too many external parameters for Libxc functional id "
315+ + std::to_string (id) + " : got "
316+ + std::to_string (requested_ext_params.size ())
317+ + " , expected at most " + std::to_string (nref) + " ." );
318+ }
314319
315- // if there are no external parameters, do nothing, otherwise we set
316- if (xc_func_ext_params != nullptr )
317- {
318- // set the external parameters
319- xc_func_set_ext_params (&funcs.back (), const_cast <double *>(xc_func_ext_params));
320+ // Missing trailing parameters retain Libxc's own defaults. This is
321+ // backward- and forward-compatible when Libxc appends parameters.
322+ std::vector<double > complete_ext_params (
323+ nref, static_cast <double >(XC_EXT_PARAMS_DEFAULT ));
324+ std::copy (requested_ext_params.begin (),
325+ requested_ext_params.end (),
326+ complete_ext_params.begin ());
327+ xc_func_set_ext_params (&funcs.back (), complete_ext_params.data ());
320328 }
321329 }
322330 return funcs;
0 commit comments