Derived Field

Definition of Derived Field

When the field is not part of the iterative process or, we want to provide a specific C function to generate data during in situ Python analysis, we can set field_type to "derived_func". Derived field data will be generated by our input C function derived_func, whenever yt or Python needs them.

Derived Field Function

Derived functions must have prototype:

void DerivedFunc(const int list_len, const long *list_gid, const char *field_name, yt_array *data_array);
  • derived_func(const int, const long*, const char*, yt_array*): generate field data of that grid when input a list grid id.

    • const int list_len: number of gid in list_gid.

    • const long *list_gid: a list of grid id that this function needs to prepare.

    • const char *field_name: target field data name to prepare.

    • yt_array *data_array: write generated data to the pointer in this array in the same order in list_gid without ghost cell.

Derived function derived_func generates data and stores in yt_array array data member data_ptr without ghost cell. Make sure your function writes the data in x-address alters first orientation (which is [z][y][x]), if contiguous_in_x is set to true. Write the data in z-address alters first orientation (which is [x][y][z]), if contiguous_in_x is set to false.

yt_array

  • Usage: a struct used in derived function and get particle attribute function.

  • Data Member:

    • long gid: grid id.

    • long data_length: length of data_ptr.

    • void *data_ptr: data pointer where you should write in field data of this grid.

Example

Field InvDens is a derived field and is reciprocal of density field Dens. derived_func_InvDens first gets level, grid dimensions and density data of the grid, and it generates data and stores them in data_array.

// get pointer of the array where we should put data to
yt_field *field_list;
yt_get_FieldsPtr(&field_list);

// Reciprocal of density field "InvDens"
field_list[1].field_name = "InvDens";
field_list[1].field_type = "derived_func";
field_list[1].contiguous_in_x = true;
field_list[1].field_dtype = (typeid(real) == typeid(float)) ? YT_FLOAT : YT_DOUBLE;
field_list[1].derived_func = derived_func_InvDens;

void derived_func_InvDens(const int list_len, const long *gid_list, const char *field_name, yt_array *data_array) {
    // loop over gid_list, and fill in grid data inside data_array.
    for (int lid = 0; lid < list_len; lid++) {
        // =================================================
        // libyt: [Optional] Use libyt look up grid info API
        // =================================================
        int level, dim[3];
        yt_getGridInfo_Level(gid_list[lid], &level);
        yt_getGridInfo_Dimensions(gid_list[lid], &dim);
    
        // =============================================================
        // libyt: [Optional] Use libyt API to get data pointer passed in
        // =============================================================
        // the label "Dens" we used here should be same as yt_get_FieldsPtr (libyt step 4)
        yt_data dens_data;
        yt_getGridInfo_FieldData(gid_list[lid], "Dens", &dens_data);
        
        // generate and fill in data in [z][y][x] order, since we set this field contiguous_in_x = true
        int index, index_with_ghost_cell;
        for (int k = 0; k < dim[2]; k++) {
            for (int j = 0; j < dim[1]; j++) {
                for (int i = 0; i < dim[0]; i++) {
                index = k * dim[1] * dim[0] + j * dim[0] + i;
                index_with_ghost_cell =  (k + GHOST_CELL) * (dim[1] + GHOST_CELL * 2) * (dim[0] + GHOST_CELL * 2)
                                       + (j + GHOST_CELL) * (dim[0] + GHOST_CELL * 2)
                                       + (i + GHOST_CELL);
                
                // write generated data in data_array allocated by libyt.
                ((real *) data_array[lid].data_ptr)[index] = 1.0 / ((real *) dens_data.data_ptr)[index_with_ghost_cell];
                }
            }
        }
    }
}