Skip to content

Commit

Permalink
Merge pull request #141 from mabruzzo/grackle_num_params
Browse files Browse the repository at this point in the history
Add ability to query the number of parameters of a given type
  • Loading branch information
brittonsmith committed Apr 4, 2023
2 parents 276ed6c + 38644f9 commit d5a0839
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 51 deletions.
6 changes: 6 additions & 0 deletions doc/source/Reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ initialization functions discussed in :ref:`internal_functions`.
Dynamic Configuration Functions
+++++++++++++++++++++++++++++++
.. c:function:: size_t grackle_num_params(const char* type_name)
Returns the number of parameters of a given type that are stored as members of the :c:data:`chemistry_data` struct.
The argument is expected to be ``"int"``, ``"double"``, or ``"string"``.
This will return ``0`` for any other argument
The following functions are used to provide dynamic access to members of the :c:data:`chemistry_data` struct. They will return ``NULL`` when ``my_chemistry`` is ``NULL``, ``param_name`` isn't a known parameter, or the ``param_name`` is not associated with the type mentioned in the function name.
.. c:function:: int* local_chemistry_data_access_int(chemistry_data *my_chemistry, const char* param_name);
Expand Down
115 changes: 64 additions & 51 deletions src/clib/dynamic_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,97 +20,110 @@
#include <string.h>
#include "grackle_chemistry_data.h"

// The following enum is only used internally
enum param_type {INT_PARAM, DOUBLE_PARAM, STRING_PARAM};
// initialize _int_param_l, _double_param_l & _string_param_l. They are sized
// lists that respectively hold entries for each int, double, and string field
// in chemistry_data. These are only used internally
typedef struct { const size_t offset; const char * name; } param_entry;
typedef struct { const size_t len; const param_entry * entries; } param_list;

// initialize _param_list, which holds an entry for each field in
// chemistry_data. This is only used internally
#define INIT_PAR_LIST(ENTRIES) {sizeof(ENTRIES) / sizeof(param_entry), ENTRIES}

typedef struct {
const enum param_type type;
const size_t offset;
const char * name;
} param_entry;
#define _LIST_INT_INT(FIELD) {offsetof(chemistry_data, FIELD), #FIELD},
#define _LIST_INT_DOUBLE(FIELD) /* ... */
#define _LIST_INT_STRING(FIELD) /* ... */

static const param_entry _param_list[] =
{
#define ENTRY(FIELD, TYPE, DEFAULT_VAL) \
{ TYPE ## _PARAM, offsetof(chemistry_data, FIELD), #FIELD },
#define _LIST_DOUBLE_INT(FIELD) /* ... */
#define _LIST_DOUBLE_DOUBLE(FIELD) {offsetof(chemistry_data, FIELD), #FIELD},
#define _LIST_DOUBLE_STRING(FIELD) /* ... */

#define _LIST_STRING_INT(FIELD) /* ... */
#define _LIST_STRING_DOUBLE(FIELD) /* ... */
#define _LIST_STRING_STRING(FIELD) {offsetof(chemistry_data, FIELD), #FIELD},

static const param_entry _int_param_entries[] = {
#define ENTRY(FIELD, TYPE, DEFAULT_VAL) _LIST_INT_ ## TYPE(FIELD)
#include "grackle_chemistry_data_fields.def"
#undef ENTRY
};
static const param_list _int_param_l = INIT_PAR_LIST(_int_param_entries);

static const param_entry _double_param_entries[] = {
#define ENTRY(FIELD, TYPE, DEFAULT_VAL) _LIST_DOUBLE_ ## TYPE(FIELD)
#include "grackle_chemistry_data_fields.def"
#undef ENTRY
};
static const param_list _double_param_l = INIT_PAR_LIST(_double_param_entries);

// This is only used internally
static const size_t _n_params = sizeof(_param_list) / sizeof(param_entry);
static const param_entry _string_param_entries[] = {
#define ENTRY(FIELD, TYPE, DEFAULT_VAL) _LIST_STRING_ ## TYPE(FIELD)
#include "grackle_chemistry_data_fields.def"
#undef ENTRY
};
static const param_list _string_param_l = INIT_PAR_LIST(_string_param_entries);


// define functions for accessing field values
// - local_chemistry_data_access_double
// - local_chemistry_data_access_int
// - local_chemistry_data_access_double
// - local_chemistry_data_access_string
//
// The current implementation has O(N) complexity where N is the number of
// fields of chemistry_data. Since configuration just happens once, this
// probably doesn't need to be very fast...
// fields of a given type in chemistry_data. Since configuration just happens
// once, this probably doesn't need to be very fast...
//
// A faster implementation that does a lot less work at runtime is definitely
// possible (it would just involve more code).
// possible (it would just involve more code).


// retrieves a pointer to the field of my_chemistry that's named ``name``.
//
// This returns a NULL pointer if: my_chemistry is NULL, the field doesn't
// exist, or the field doesn't have the specified type
static void* _get_field_ptr(chemistry_data* my_chemistry, const char* name,
enum param_type type)
const param_list my_param_l)
{
if (my_chemistry == NULL) { return NULL; }

for (size_t param_index = 0; param_index < _n_params; param_index++){
const param_entry* entry = _param_list + param_index;
if ((strcmp(entry->name, name) == 0) & (entry->type == type)){
for (size_t param_index = 0; param_index < my_param_l.len; param_index++){
const param_entry* entry = my_param_l.entries + param_index;
if (strcmp(entry->name, name) == 0) {
return (void*)( (char*)my_chemistry + entry->offset );
}
}
return NULL;
}

double* local_chemistry_data_access_double(chemistry_data* my_chemistry,
const char* param_name)
{ return (double*)_get_field_ptr(my_chemistry, param_name, DOUBLE_PARAM); }

int* local_chemistry_data_access_int(chemistry_data* my_chemistry,
const char* param_name)
{ return (int*)_get_field_ptr(my_chemistry, param_name, INT_PARAM); }
{ return (int*)_get_field_ptr(my_chemistry, param_name, _int_param_l); }

double* local_chemistry_data_access_double(chemistry_data* my_chemistry,
const char* param_name)
{ return (double*)_get_field_ptr(my_chemistry, param_name, _double_param_l); }

char** local_chemistry_data_access_string(chemistry_data* my_chemistry,
const char* param_name)
{ return (char**)_get_field_ptr(my_chemistry, param_name, STRING_PARAM); }
{ return (char**)_get_field_ptr(my_chemistry, param_name, _string_param_l); }

// define functions for accessing the names of chemistry_data
// - param_name_double
// - param_name_int
// define functions for accessing the names of chemistry_data:
// param_name_int, param_name_double, param_name_string
//
// These are primarily needed for testing purposes and can be used for
// serialization. The current implementation is slow. A faster alternative
// would define separate lists for int parameters and double parameters
// serialization.

// returns the name of the ``i``th parameter of the specified type. This returns
// NULL when there are ``i`` or fewer parameters of the specified type
static const char* _param_name(size_t i, enum param_type type)
{
size_t type_count = 0; // # of parameters of type that have been encountered
for (size_t param_index = 0; param_index < _n_params; param_index++){
if (_param_list[param_index].type != type){
continue;
} else if (type_count == i){
return _param_list[param_index].name;
} else {
type_count++;
}
}
return NULL;
static const char* _param_name(size_t i, const param_list my_param_list)
{ return (i < my_param_list.len) ? my_param_list.entries[i].name : NULL; }

const char* param_name_int(size_t i) {return _param_name(i,_int_param_l);}
const char* param_name_double(size_t i) {return _param_name(i,_double_param_l);}
const char* param_name_string(size_t i) {return _param_name(i,_string_param_l);}

// function to query the number of parameters of chemistry_data of a given type
size_t grackle_num_params(const char* type_name){
if (strcmp(type_name, "int") == 0) { return _int_param_l.len; }
else if (strcmp(type_name, "double") == 0) { return _double_param_l.len; }
else if (strcmp(type_name, "string") == 0) { return _string_param_l.len; }
return 0;
}

const char* param_name_double(size_t i){ return _param_name(i, DOUBLE_PARAM); }
const char* param_name_int(size_t i){ return _param_name(i, INT_PARAM); }
const char* param_name_string(size_t i){ return _param_name(i, STRING_PARAM); }
2 changes: 2 additions & 0 deletions src/clib/grackle.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const char* param_name_int(size_t i);
const char* param_name_double(size_t i);
const char* param_name_string(size_t i);

size_t grackle_num_params(const char* type_name);

int solve_chemistry(code_units *my_units,
grackle_field_data *my_fields,
double dt_value);
Expand Down

0 comments on commit d5a0839

Please sign in to comment.