# 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`](./yt_get_fieldsptr.md#yt_field) to `"derived_func"`. Derived field data will be generated by our input C function [`derived_func`](#derived-field-function), whenever `yt` or Python needs them. ## Derived Field Function Derived functions must have prototype: ```c 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`. ```cpp // 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]; } } } } } ```