/*------------------------------------------------------------------------- * Function: ensure_data_read_fails * * Purpose: Tests not reading data * * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ static herr_t ensure_data_read_fails(hid_t did) { int **check = NULL; herr_t ret = FAIL; if (allocate_and_init_2D_array(&check, sizes_g, NULL) < 0) TEST_ERROR; /* Read the dataset back (should fail) */ H5E_BEGIN_TRY { ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, *check); } H5E_END_TRY if(ret >= 0) TEST_ERROR; free_2D_array(&check); PASSED(); return SUCCEED; error: free_2D_array(&check); return FAIL; } /* end ensure_data_read_fails() */
/*------------------------------------------------------------------------- * Function: test_read_data * * Purpose: Tests reading data and compares values * * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ static herr_t test_read_data(hid_t did, int *origin_data) { int **check = NULL; int *data_p = origin_data; size_t i, j; /* Local index variables */ if (allocate_and_init_2D_array(&check, sizes_g, NULL) < 0) TEST_ERROR; /* Read the dataset back */ if (H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, *check) < 0) TEST_ERROR; /* Check that the values read are the same as the values written */ for(i = 0; i < sizes_g[0]; i++) for(j = 0; j < sizes_g[1]; j++) { if(*data_p != check[i][j]) TEST_ERROR data_p++; } free_2D_array(&check); PASSED(); return SUCCEED; error: free_2D_array(&check); return FAIL; } /* end test_read_data() */
/*------------------------------------------------------------------------- * Function: allocate_and_init_2D_array * * Purpose: Initialize an array as a pseudo 2D array and copy in some * initial values. * * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ static herr_t allocate_and_init_2D_array(int ***arr, const hsize_t *sizes, int **initial_values) { size_t r, c; /* Data rows and columns */ size_t i; /* Iterator */ size_t n_bytes; /* # of bytes to copy */ r = (size_t)sizes[0]; c = (size_t)sizes[1]; /* Allocate and set up pseudo-2D array */ if (NULL == (*arr = (int **)HDcalloc(r, sizeof(int *)))) TEST_ERROR; if (NULL == ((*arr)[0] = (int *)HDcalloc(r * c, sizeof(int)))) TEST_ERROR; for (i = 0; i < r; i++) (*arr)[i] = (**arr + c * i); /* Copy over the data elements */ if (initial_values) { n_bytes = r * c * sizeof(int); HDmemcpy((*arr)[0], initial_values[0], n_bytes); } return SUCCEED; error: free_2D_array(arr); return FAIL; } /* end allocate_and_init_2D_array() */
/*------------------------------------------------------------------------- * Function: ensure_filter_works * * Purpose: Tests writing entire data and partial data with filters * * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ static herr_t ensure_filter_works(hid_t fid, const char *name, hid_t dcpl_id) { hid_t did = -1; /* Dataset ID */ hid_t dxpl_id = -1; /* Dataset xfer property list ID */ hid_t write_dxpl_id = -1; /* Dataset xfer property list ID for writing */ hid_t sid = -1; /* Dataspace ID */ void *tconv_buf = NULL; /* Temporary conversion buffer */ int **orig = NULL; /* Data written to the dataset */ int **read = NULL; /* Data read from the dataset */ size_t r, c; /* Data rows and columns */ size_t hs_r, hs_c, hs_offr, hs_offc; /* Hypserslab sizes and offsets */ size_t i, j; /* Local index variables */ int n = 0; /* Value written to point array */ hbool_t are_same; /* Output from dataset compare function */ int ***save_array = NULL; /* (Global) array where the final data go */ /* initialize */ r = (size_t)sizes_g[0]; c = (size_t)sizes_g[1]; /* Create the data space */ if ((sid = H5Screate_simple(2, sizes_g, NULL)) < 0) TEST_ERROR; /* Allocate memory for the data buffers * We're using the hacky way of doing 2D arrays that uses a * single data buffer but which allows normal 2D access. */ if (allocate_and_init_2D_array(&orig, sizes_g, NULL) < 0) TEST_ERROR; if (allocate_and_init_2D_array(&read, sizes_g, NULL) < 0) TEST_ERROR; /* Create a small conversion buffer to test strip mining. We * might as well test all we can! */ if ((dxpl_id = H5Pcreate(H5P_DATASET_XFER)) < 0) TEST_ERROR; if (NULL == (tconv_buf = HDcalloc((size_t)1000, sizeof(char)))) TEST_ERROR; if (H5Pset_buffer(dxpl_id, (size_t)1000, tconv_buf, NULL) < 0) TEST_ERROR; if ((write_dxpl_id = H5Pcopy(dxpl_id)) < 0) TEST_ERROR; TESTING(" filters (setup)"); /* Check if all the filters are available */ if (H5Pall_filters_avail(dcpl_id) != TRUE) TEST_ERROR; /* Create the dataset */ if ((did = H5Dcreate2(fid, name, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) TEST_ERROR; PASSED(); /*---------------------------------------------------------------------- * STEP 1: Read uninitialized data. It should be zero. *---------------------------------------------------------------------- */ TESTING(" filters (uninitialized read)"); if (H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl_id, *read) < 0) TEST_ERROR; /* The input buffer was calloc'd and has not been initialized yet */ if (compare_2D_arrays(orig, read, sizes_g, &are_same) < 0) TEST_ERROR; if (FALSE == are_same) TEST_ERROR; PASSED(); /*---------------------------------------------------------------------- * STEP 2: Test filters by setting up a chunked dataset and writing * to it. *---------------------------------------------------------------------- */ TESTING(" filters (write)"); n = 0; for (i = 0; i < r; i++) for (j = 0; j < c; j++) orig[i][j] = n++; if (H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, write_dxpl_id, *orig) < 0) TEST_ERROR; PASSED(); /*---------------------------------------------------------------------- * STEP 3: Try to read the data we just wrote. *---------------------------------------------------------------------- */ TESTING(" filters (read)"); /* Read the dataset back */ if (H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl_id, *read) < 0) TEST_ERROR; /* Check that the values read are the same as the values written */ if (compare_2D_arrays(orig, read, sizes_g, &are_same) < 0) TEST_ERROR; if (FALSE == are_same) TEST_ERROR; PASSED(); /*---------------------------------------------------------------------- * STEP 4: Write new data over the top of the old data. The new data is * random thus not very compressible, and will cause the chunks to move * around as they grow. We only change values for the left half of the * dataset although we rewrite the whole thing. *---------------------------------------------------------------------- */ TESTING(" filters (modify)"); for (i = 0; i < r; i++) for (j = 0; j < c / 2; j++) orig[i][j] = (int)HDrandom() % RANDOM_LIMIT; if (H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, write_dxpl_id, *orig) < 0) TEST_ERROR; /* Read the dataset back and check it */ if (H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl_id, *read) < 0) TEST_ERROR; /* Check that the values read are the same as the values written */ if (compare_2D_arrays(orig, read, sizes_g, &are_same) < 0) TEST_ERROR; if (FALSE == are_same) TEST_ERROR; PASSED(); /*---------------------------------------------------------------------- * STEP 5: Close the dataset and then open it and read it again. This * insures that the filters message is picked up properly from the * object header. *---------------------------------------------------------------------- */ TESTING(" filters (re-open)"); if (H5Dclose(did) < 0) TEST_ERROR; if ((did = H5Dopen2(fid, name, H5P_DEFAULT)) < 0) TEST_ERROR; if (H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl_id, *read) < 0) TEST_ERROR; /* Check that the values read are the same as the values written */ if (compare_2D_arrays(orig, read, sizes_g, &are_same) < 0) TEST_ERROR; if (FALSE == are_same) TEST_ERROR; PASSED(); /*---------------------------------------------------------------------- * STEP 6: Test partial I/O by writing to and then reading from a * hyperslab of the dataset. The hyperslab does not line up on chunk * boundaries (we know that case already works from above tests). *---------------------------------------------------------------------- */ TESTING(" filters (partial I/O)"); hs_r = (size_t)hs_sizes_g[0]; hs_c = (size_t)hs_sizes_g[1]; hs_offr = (size_t)hs_offsets_g[0]; hs_offc = (size_t)hs_offsets_g[1]; for (i = 0; i < hs_r; i++) for (j = 0; j < hs_c; j++) orig[hs_offr + i][hs_offc + j] = (int)HDrandom() % RANDOM_LIMIT; if (H5Sselect_hyperslab(sid, H5S_SELECT_SET, hs_offsets_g, NULL, hs_sizes_g, NULL) < 0) TEST_ERROR; /* Use the "read" DXPL because partial I/O on corrupted data test * needs to ignore errors during writing */ if (H5Dwrite(did, H5T_NATIVE_INT, sid, sid, dxpl_id, *orig) < 0) TEST_ERROR; if (H5Dread(did, H5T_NATIVE_INT, sid, sid, dxpl_id, *read) < 0) TEST_ERROR; /* Check that the values read are the same as the values written */ if (compare_2D_arrays(orig, read, sizes_g, &are_same) < 0) TEST_ERROR; if (FALSE == are_same) TEST_ERROR; PASSED(); /* Save the data written to the file for later comparison when the file * is reopened for read test. */ if (!HDstrcmp(name, DSET_DEFLATE_NAME)) save_array = &orig_deflate_g; else if (!HDstrcmp(name, DSET_FILTER1_NAME)) save_array = &orig_dynlib1_g; else if (!HDstrcmp(name, DSET_FILTER2_NAME)) save_array = &orig_dynlib2_g; else if (!HDstrcmp(name, DSET_FILTER3_NAME)) save_array = &orig_dynlib4_g; else TEST_ERROR; if (allocate_and_init_2D_array(save_array, sizes_g, orig) < 0) TEST_ERROR; /* Clean up and exit */ if (H5Dclose(did) < 0) TEST_ERROR; if (H5Sclose(sid) < 0) TEST_ERROR; if (H5Pclose(dxpl_id) < 0) TEST_ERROR; if (H5Pclose(write_dxpl_id) < 0) TEST_ERROR; free_2D_array(&orig); free_2D_array(&read); HDfree(tconv_buf); return SUCCEED; error: /* Clean up objects used for this test */ H5E_BEGIN_TRY { H5Dclose(did); H5Sclose(sid); H5Pclose(dxpl_id); H5Pclose(write_dxpl_id); } H5E_END_TRY /* NULLs are okay here */ free_2D_array(&orig); free_2D_array(&read); if (tconv_buf) HDfree(tconv_buf); return FAIL; } /* end ensure_filter_works() */
/*------------------------------------------------------------------------- * Function: main * * Purpose: Tests the plugin module (H5PL) * * Return: EXIT_SUCCESS/EXIT_FAILURE * *------------------------------------------------------------------------- */ int main(void) { char filename[FILENAME_BUF_SIZE]; hid_t fid = -1; hid_t old_ff_fapl_id = -1; hid_t new_ff_fapl_id = -1; unsigned new_format; int nerrors = 0; /*******************************************************************/ /* ENSURE THAT WRITING TO DATASETS AND CREATING GROUPS WORKS */ /*******************************************************************/ /* Test with old & new format groups */ for (new_format = FALSE; new_format <= TRUE; new_format++) { hid_t my_fapl_id; /* Testing setup */ h5_reset(); /* Get a VFD-dependent filename */ if ((old_ff_fapl_id = h5_fileaccess()) < 0) TEST_ERROR; /* Turn off the chunk cache, so all the chunks are immediately written to disk */ if (disable_chunk_cache(old_ff_fapl_id) < 0) TEST_ERROR; /* Fix up the filename for the VFD */ h5_fixname(FILENAME[0], old_ff_fapl_id, filename, sizeof(filename)); /* Set the FAPL for the type of format */ if (new_format) { HDputs("\nTesting with new file format:"); /* Copy the file access property list and set the latest file format on it */ if ((new_ff_fapl_id = H5Pcopy(old_ff_fapl_id)) < 0) TEST_ERROR; if (H5Pset_libver_bounds(new_ff_fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) TEST_ERROR; my_fapl_id = new_ff_fapl_id; } else { HDputs("Testing with old file format:"); my_fapl_id = old_ff_fapl_id; } /* Create the file for this test */ if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, my_fapl_id)) < 0) TEST_ERROR; /* Test creating datasets and writing to them using plugin filters */ nerrors += (test_dataset_write_with_filters(fid) < 0 ? 1 : 0); /* Test creating groups using dynamically-loaded plugin filters */ nerrors += (test_creating_groups_using_plugins(fid) < 0 ? 1 : 0); if (H5Fclose(fid) < 0) TEST_ERROR; /* Close FAPLs */ if (H5Pclose(old_ff_fapl_id) < 0) TEST_ERROR; if (new_format) { if (H5Pclose(new_ff_fapl_id) < 0) TEST_ERROR; } /* Restore the default error handler (set in h5_reset()) */ h5_restore_err(); /*******************************************************************/ /* ENSURE THAT READING FROM DATASETS AND OPENING GROUPS WORKS */ /*******************************************************************/ HDputs("\nTesting reading data with with dynamic plugin filters:"); /* Close the library so that all loaded plugin libraries are unloaded */ h5_reset(); if ((old_ff_fapl_id = h5_fileaccess()) < 0) TEST_ERROR; /* Set the FAPL for the type of format */ if (new_format) { /* Copy the file access property list and set the latest file format on it */ if ((new_ff_fapl_id = H5Pcopy(old_ff_fapl_id)) < 0) TEST_ERROR; if (H5Pset_libver_bounds(new_ff_fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) TEST_ERROR; my_fapl_id = new_ff_fapl_id; } else my_fapl_id = old_ff_fapl_id; /* Reopen the file for testing data reading */ if ((fid = H5Fopen(filename, H5F_ACC_RDONLY, my_fapl_id)) < 0) TEST_ERROR; /* Read the data with filters */ nerrors += (test_dataset_read_with_filters(fid) < 0 ? 1 : 0); /* Test creating groups using dynamically-loaded plugin filters */ nerrors += (test_opening_groups_using_plugins(fid) < 0 ? 1 : 0); /* Close FAPLs */ if (H5Pclose(old_ff_fapl_id) < 0) TEST_ERROR; if (new_format) { if (H5Pclose(new_ff_fapl_id) < 0) TEST_ERROR; } /* Restore the default error handler (set in h5_reset()) */ h5_restore_err(); /*******************************************************************/ /* ENSURE THAT DISABLING FILTER PLUGINS VIA THE FILTER FLAGS WORKS */ /*******************************************************************/ /* Close the library so that all loaded plugin libraries are unloaded */ h5_reset(); if ((old_ff_fapl_id = h5_fileaccess()) < 0) TEST_ERROR; /* Set the FAPL for the type of format */ if (new_format) { /* Copy the file access property list and set the latest file format on it */ if ((new_ff_fapl_id = H5Pcopy(old_ff_fapl_id)) < 0) TEST_ERROR; if (H5Pset_libver_bounds(new_ff_fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) TEST_ERROR; my_fapl_id = new_ff_fapl_id; } else my_fapl_id = old_ff_fapl_id; /* Reopen the file for testing data reading */ if ((fid = H5Fopen(filename, H5F_ACC_RDONLY, my_fapl_id)) < 0) TEST_ERROR; /* When filters are disabled, make sure we can't read data from a * dataset that requires a filter plugin. */ nerrors += (test_no_read_when_plugins_disabled(fid) < 0 ? 1 : 0); if (H5Fclose(fid) < 0) TEST_ERROR; /*********************/ /* CLEAN UP */ /*********************/ /* Close FAPLs */ if (new_format) { if (H5Pclose(new_ff_fapl_id) < 0) TEST_ERROR; } else { /* Restore the default error handler (set in h5_reset()) */ h5_restore_err(); if (H5Pclose(old_ff_fapl_id) < 0) TEST_ERROR; } /* Free up saved arrays */ free_2D_array(&orig_deflate_g); free_2D_array(&orig_dynlib1_g); free_2D_array(&orig_dynlib2_g); free_2D_array(&orig_dynlib4_g); } /* end for */ h5_cleanup(FILENAME, old_ff_fapl_id); /************************************/ /* TEST THE FILTER PLUGIN API CALLS */ /************************************/ /* Test the APIs for access to the filter plugin path table */ nerrors += (test_path_api_calls() < 0 ? 1 : 0); if (nerrors) TEST_ERROR; HDprintf("All plugin tests passed.\n"); HDexit(EXIT_SUCCESS); error: H5E_BEGIN_TRY { H5Fclose(fid); H5Pclose(old_ff_fapl_id); H5Pclose(new_ff_fapl_id); } H5E_END_TRY /* Free up saved arrays (NULLs okay) */ free_2D_array(&orig_deflate_g); free_2D_array(&orig_dynlib1_g); free_2D_array(&orig_dynlib2_g); free_2D_array(&orig_dynlib4_g); nerrors = MAX(1, nerrors); HDprintf("***** %d PLUGIN TEST%s FAILED! *****\n", nerrors, 1 == nerrors ? "" : "S"); HDexit(EXIT_FAILURE); } /* end main() */
void rec_build_history(REC_COSMOPARAMS *param, HRATEEFF *rate_table, TWO_PHOTON_PARAMS *twog_params, double *xe_output, double *Tm_output) { long iz; double **logfminus_hist; double *logfminus_Ly_hist[3]; double H, z, z_prev, dxedlna_prev, z_prev2, dxedlna_prev2, dTmdlna_prev, dTmdlna_prev2; double Delta_xe; /* history of photon occupation numbers */ logfminus_hist = create_2D_array(NVIRT, param->nz); logfminus_Ly_hist[0] = create_1D_array(param->nz); /* Ly-alpha */ logfminus_Ly_hist[1] = create_1D_array(param->nz); /* Ly-beta */ logfminus_Ly_hist[2] = create_1D_array(param->nz); /* Ly-gamma */ z = param->zstart; /********* He II + III Saha phase *********/ Delta_xe = 1.; /* Delta_xe = xHeIII */ for(iz=0; iz<param->nz && Delta_xe > 1e-9; iz++) { z = (1.+param->zstart)*exp(-param->dlna*iz) - 1.; xe_output[iz] = rec_sahaHeII(param->nH0,param->T0,param->fHe,z, &Delta_xe); Tm_output[iz] = param->T0 * (1.+z); } /******* He I + II post-Saha phase *********/ Delta_xe = 0.; /* Delta_xe = xe - xe(Saha) */ for (; iz<param->nz && Delta_xe < 5e-4; iz++) { z = (1.+param->zstart)*exp(-param->dlna*iz) - 1.; xe_output[iz] = xe_PostSahaHe(param->nH0,param->T0,param->fHe, rec_HubbleConstant(param,z), z, &Delta_xe); Tm_output[iz] = param->T0 * (1.+z); } /****** Segment where we follow the helium recombination evolution, Tm fixed to steady state *******/ z_prev2 = (1.+param->zstart)*exp(-param->dlna*(iz-3)) - 1.; dxedlna_prev2 = (xe_output[iz-2] - xe_output[iz-4])/2./param->dlna; z_prev = (1.+param->zstart)*exp(-param->dlna*(iz-2)) - 1.; dxedlna_prev = (xe_output[iz-1] - xe_output[iz-3])/2./param->dlna; Delta_xe = 1.; /* Difference between xe and H-Saha value */ for(; iz<param->nz && (Delta_xe > 1e-4 || z > 1650.); iz++) { rec_get_xe_next1(param, z, xe_output[iz-1], xe_output+iz, rate_table, FUNC_HEI, iz-1, twog_params, logfminus_hist, logfminus_Ly_hist, &z_prev, &dxedlna_prev, &z_prev2, &dxedlna_prev2); z = (1.+param->zstart)*exp(-param->dlna*iz) - 1.; Tm_output[iz] = rec_Tmss(xe_output[iz], param->T0*(1.+z), rec_HubbleConstant(param, z), param->fHe, param->nH0*cube(1.+z), energy_injection_rate(param,z)); /* Starting to populate the photon occupation number with thermal values */ update_fminus_Saha(logfminus_hist, logfminus_Ly_hist, xe_output[iz], param->T0*(1.+z)*kBoltz, param->nH0*cube(1.+z)*1e-6, twog_params, param->zstart, param->dlna, iz, z, 0); Delta_xe = fabs(xe_output[iz]- rec_saha_xe_H(param->nH0, param->T0, z)); } /******* Hydrogen post-Saha equilibrium phase *********/ Delta_xe = 0.; /*Difference between xe and Saha value */ for(; iz<param->nz && Delta_xe < 5e-5; iz++) { z = (1.+param->zstart)*exp(-param->dlna*iz) - 1.; H = rec_HubbleConstant(param,z); xe_output[iz] = xe_PostSahaH(param->nH0*cube(1.+z)*1e-6, H, kBoltz*param->T0*(1.+z), rate_table, twog_params, param->zstart, param->dlna, logfminus_hist, logfminus_Ly_hist, iz, z, &Delta_xe, MODEL, energy_injection_rate(param,z)); Tm_output[iz] = rec_Tmss(xe_output[iz], param->T0*(1.+z), H, param->fHe, param->nH0*cube(1.+z), energy_injection_rate(param,z)); } /******* Segment where we follow the hydrogen recombination evolution with two-photon processes Tm fixed to steady state ******/ z_prev2 = (1.+param->zstart)*exp(-param->dlna*(iz-3)) - 1.; dxedlna_prev2 = (xe_output[iz-2] - xe_output[iz-4])/2./param->dlna; z_prev = (1.+param->zstart)*exp(-param->dlna*(iz-2)) - 1.; dxedlna_prev = (xe_output[iz-1] - xe_output[iz-3])/2./param->dlna; for(; iz<param->nz && 1.-Tm_output[iz-1]/param->T0/(1.+z) < 5e-4 && z > 700.; iz++) { rec_get_xe_next1(param, z, xe_output[iz-1], xe_output+iz, rate_table, FUNC_H2G, iz-1, twog_params, logfminus_hist, logfminus_Ly_hist, &z_prev, &dxedlna_prev, &z_prev2, &dxedlna_prev2); z = (1.+param->zstart)*exp(-param->dlna*iz) - 1.; Tm_output[iz] = rec_Tmss(xe_output[iz], param->T0*(1.+z), rec_HubbleConstant(param, z), param->fHe, param->nH0*cube(1.+z)*1e-6, energy_injection_rate(param,z)); } /******* Segment where we follow the hydrogen recombination evolution with two-photon processes AND Tm evolution ******/ dTmdlna_prev2 = rec_dTmdlna(xe_output[iz-3], Tm_output[iz-3], param->T0*(1.+z_prev2), rec_HubbleConstant(param, z_prev2), param->fHe, param->nH0*cube(1.+z_prev2), energy_injection_rate(param,z_prev2)); dTmdlna_prev = rec_dTmdlna(xe_output[iz-2], Tm_output[iz-2], param->T0*(1.+z_prev), rec_HubbleConstant(param, z_prev), param->fHe, param->nH0*cube(1.+z_prev), energy_injection_rate(param,z_prev)); for(; iz<param->nz && z > 700.; iz++) { rec_get_xe_next2(param, z, xe_output[iz-1], Tm_output[iz-1], xe_output+iz, Tm_output+iz, rate_table, FUNC_H2G, iz-1, twog_params, logfminus_hist, logfminus_Ly_hist, &z_prev, &dxedlna_prev, &dTmdlna_prev, &z_prev2, &dxedlna_prev2, &dTmdlna_prev2); z = (1.+param->zstart)*exp(-param->dlna*iz) - 1.; } /***** Segment where we follow Tm as well as xe *****/ /* Radiative transfer effects switched off here */ for(; iz<param->nz && z>20.; iz++) { rec_get_xe_next2(param, z, xe_output[iz-1], Tm_output[iz-1], xe_output+iz, Tm_output+iz, rate_table, FUNC_HMLA, iz-1, twog_params, logfminus_hist, logfminus_Ly_hist, &z_prev, &dxedlna_prev, &dTmdlna_prev, &z_prev2, &dxedlna_prev2, &dTmdlna_prev2); z = (1.+param->zstart)*exp(-param->dlna*iz) - 1.; } /*** For z < 20 use Peeble's model. The precise model does not metter much here as 1) the free electron fraction is basically zero (~1e-4) in any case and 2) the universe is going to be reionized around that epoch Tm is still evolved explicitly ***/ for(; iz<param->nz; iz++) { rec_get_xe_next2(param, z, xe_output[iz-1], Tm_output[iz-1], xe_output+iz, Tm_output+iz, rate_table, FUNC_PEEBLES, iz-1, twog_params, logfminus_hist, logfminus_Ly_hist, &z_prev, &dxedlna_prev, &dTmdlna_prev, &z_prev2, &dxedlna_prev2, &dTmdlna_prev2); z = (1.+param->zstart)*exp(-param->dlna*iz) - 1.; } /* Cleanup */ free_2D_array(logfminus_hist, NVIRT); free(logfminus_Ly_hist[0]); free(logfminus_Ly_hist[1]); free(logfminus_Ly_hist[2]); }