/* Author: G. Jungman * RCS: $Id: dht_transform.c,v 1.3 1999/04/20 17:00:23 jungman Exp $ */ #include #include #include #include #include #include "gsl_dht.h" /* Handle internal allocation for a given length. */ static int dht_transform_allocator(gsl_dht_transform * t, size_t size) { t->j = (double *)malloc((size+2)*sizeof(double)); if(t->j == 0) { return GSL_ENOMEM; } t->Jjj = (double *)malloc(size*(size+1)/2 * sizeof(double)); if(t->Jjj == 0) { free(t->j); return GSL_ENOMEM; } t->J2 = (double *)malloc((size+1)*sizeof(double)); if(t->J2 == 0) { free(t->Jjj); free(t->j); return GSL_ENOMEM; } return GSL_SUCCESS; } /* Handle internal calculation of Bessel zeros. */ static int dht_bessel_zeros(gsl_dht_transform * t) { size_t s; gsl_sf_result z; int stat_z = 0; t->j[0] = 0.0; for(s=1; s < t->size + 2; s++) { stat_z += gsl_sf_bessel_zero_Jnu_impl(t->nu, s, &z); t->j[s] = z.val; } if(stat_z != 0) { return GSL_EFAILED; } else { return GSL_SUCCESS; } } gsl_dht_transform * gsl_dht_transform_new(size_t size, double nu, double xmax) { if(size == 0) { GSL_ERROR_RETURN("gsl_dht_transform_new: size == 0", GSL_EDOM, 0); } else if(nu < 0.0) { GSL_ERROR_RETURN("gsl_dht_transform_new: nu < 0.0", GSL_EDOM, 0); } else if(xmax <= 0.0) { GSL_ERROR_RETURN("gsl_dht_transform_new: xmax <= 0.0", GSL_EDOM, 0); } else { gsl_dht_transform * t = (gsl_dht_transform *)malloc(sizeof(gsl_dht_transform)); if(t == 0) { GSL_ERROR_RETURN("gsl_dht_transform_new: out of memory", GSL_ENOMEM, 0); } else { t->nu = -1.0; /* Make it clear that this needs to be calculated. */ t->size = size; if(dht_transform_allocator(t, size) != GSL_SUCCESS) { free(t); GSL_ERROR_RETURN("gsl_dht_transform_new: alloc failed", GSL_ENOMEM, 0); } else { if(gsl_dht_transform_recalc_impl(t, nu, xmax) != GSL_SUCCESS) { free(t->J2); free(t->Jjj); free(t->j); free(t); GSL_ERROR_RETURN("gsl_dht_transform_new: recalc failed", GSL_EFAILED, 0); } } return t; } } } int gsl_dht_transform_recalc_impl(gsl_dht_transform * t, double nu, double xmax) { if(xmax <= 0.0 || nu < 0.0) { return GSL_EDOM; } else { size_t n, m; int stat_bz = GSL_SUCCESS; int stat_J = 0; double jN; if(nu != t->nu) { /* Recalculate Bessel zeros if necessary. */ t->nu = nu; stat_bz = dht_bessel_zeros(t); } jN = t->j[t->size+1]; t->xmax = xmax; t->kmax = jN / xmax; t->J2[0] = 0.0; for(m=1; msize+1; m++) { gsl_sf_result J; stat_J += gsl_sf_bessel_Jnu_impl(nu + 1.0, t->j[m], &J); t->J2[m] = J.val * J.val; } /* J_nu(j[n] j[m] / j[N]) = Jjj[n(n-1)/2 + m - 1], 1 <= n,m <= size */ for(n=1; nsize+1; n++) { for(m=1; m<=n; m++) { double arg = t->j[n] * t->j[m] / jN; gsl_sf_result J; stat_J += gsl_sf_bessel_Jnu_impl(nu, arg, &J); t->Jjj[n*(n-1)/2 + m - 1] = J.val; } } if(stat_J != 0) { return GSL_EFAILED; } else { return stat_bz; } } } double gsl_dht_transform_x_sample(const gsl_dht_transform * t, int n) { return t->j[n+1]/t->j[t->size+1] * t->xmax; } double gsl_dht_transform_k_sample(const gsl_dht_transform * t, int n) { return t->j[n+1] / t->xmax; } void gsl_dht_transform_free(gsl_dht_transform * t) { if(t != 0) { free(t->J2); free(t->Jjj); free(t->j); free(t); } } int gsl_dht_transform_apply(const gsl_dht_transform * t, double * f_in, double * f_out) { const double jN = t->j[t->size + 1]; const double r = t->xmax / jN; size_t m; size_t i; for(m=0; msize; m++) { double sum = 0.0; double Y; for(i=0; isize; i++) { /* Need to find max and min so that we * address the symmetric Jjj matrix properly. * FIXME: we can presumably optimize this * by just running over the elements of Jjj * in a deterministic manner. */ size_t m_local; size_t n_local; if(i < m) { m_local = i; n_local = m; } else { m_local = m; n_local = i; } Y = t->Jjj[n_local*(n_local+1)/2 + m_local] / t->J2[i+1]; sum += Y * f_in[i]; } f_out[m] = sum * 2.0 * r*r; } return GSL_SUCCESS; } int gsl_dht_transform_recalc_e(gsl_dht_transform * t, double nu, double xmax) { int status = gsl_dht_transform_recalc_impl(t, nu, xmax); if(status != GSL_SUCCESS) { GSL_ERROR("gsl_dht_transform_recalc_e", status); } return status; }