Beispiel #1
0
/*-------------------------------------------------------------------------
 * 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() */
Beispiel #2
0
/*-------------------------------------------------------------------------
 * 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() */
Beispiel #3
0
/*-------------------------------------------------------------------------
 * 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() */
Beispiel #4
0
/*-------------------------------------------------------------------------
 * 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() */
Beispiel #5
0
/*-------------------------------------------------------------------------
 * 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() */
Beispiel #6
0
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]);

}