/* numerics.hh - This file is part of MUSIC - a code to generate multi-scale initial conditions for cosmological simulations Copyright (C) 2010 Oliver Hahn This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef __NUMERICS_HH #define __NUMERICS_HH #ifdef WITH_MPI #ifdef MANNO #include #else #include #endif #endif #include #include #include #include #include "general.hh" real_t integrate( double (* func) (double x, void * params), double a, double b, void *params=NULL); struct Base_interp { int n, mm, jsav, cor, dj; const double *xx, *yy; Base_interp(std::vector &x, const double *y, int m) : n(x.size()), mm(m), jsav(0), cor(0), dj(0), xx(&x[0]), yy(y) { dj = std::min(1,(int)pow((double)n,0.25)); } double interp(double x) { int jlo = cor ? hunt(x) : locate(x); return rawinterp(jlo,x); } virtual ~Base_interp() { } int locate(const double x); int hunt(const double x); double virtual rawinterp(int jlo, double x) = 0; }; class Spline_interp : public Base_interp { protected: std::vector y2; void sety2( const double *xv, const double *yv, double yp1, double ypn) { int i,k; double p,qn,sig,un; //int n=y2.size(); std::vector u(n-1,0.0); if (yp1 > 0.99e99) y2[0]=u[0]=0.0; else { y2[0] = -0.5; u[0]=(3.0/(xv[1]-xv[0]))*((yv[1]-yv[0])/(xv[1]-xv[0])-yp1); } for (i=1;i 0.99e99) qn=un=0.0; else { qn=0.5; un=(3.0/(xv[n-1]-xv[n-2]))*(ypn-(yv[n-1]-yv[n-2])/(xv[n-1]-xv[n-2])); } y2[n-1]=(un-qn*u[n-2])/(qn*y2[n-2]+1.0); for (k=n-2;k>=0;k--) y2[k]=y2[k]*y2[k+1]+u[k]; } public: Spline_interp( std::vector &xv, std::vector &yv, double yp1=1e99, double ypn=1.e99 ) : Base_interp( xv, &yv[0], xv.size() ), y2( xv.size(), 0.0 ) { sety2( &xv[0], &yv[0], yp1, ypn ); } virtual ~Spline_interp() { } double rawinterp( int jl, double x ) { int klo=jl,khi=jl+1; double y,h,b,a; h=xx[khi]-xx[klo]; if (h == 0.0) throw("Bad input to routine splint"); a=(xx[khi]-x)/h; b=(x-xx[klo])/h; y=a*yy[klo]+b*yy[khi]+((a*a*a-a)*y2[klo] +(b*b*b-b)*y2[khi])*(h*h)/6.0; return y; } }; #if 1 inline unsigned locate( const double x, const std::vector vx ) { long unsigned ju,jm,jl; bool ascnd=(vx[vx.size()-1]>=vx[0]); jl = 0; ju = vx.size()-1; while( ju-jl > 1 ) { jm = (ju+jl)>>1; if( (x >= vx[jm]) == ascnd ) jl = jm; else ju = jm; } return std::max((long unsigned)0,std::min((long unsigned)(vx.size()-2),(long unsigned)jl)); } #else inline unsigned locate( const real_t x, const std::vector vx ) { unsigned i=0; while( vx[i]0)i=i-1; return i; } #endif inline real_t linint( const double x, const std::vector& xx, const std::vector& yy ) { unsigned i = locate(x,xx); /* if(i==xx.size()-1) //--i; return 0.0; if( x=xx[xx.size()-1] ) return yy[yy.size()-1]; double a = 1.0/(xx[i+1]-xx[i]); double dy = (yy[i+1]-yy[i])*a; double y0 = (yy[i]*xx[i+1]-xx[i]*yy[i+1])*a; return dy*x+y0; } /* inline float linint( float x, const std::vector& xx, const std::vector& yy ) { int i=0; while( xx[i]0)i=i-1; float dy = (yy[i+1]-yy[i])/(xx[i+1]-xx[i]); float y0 = (yy[i]*xx[i+1]-xx[i]*yy[i+1])/(xx[i+1]-xx[i]); return dy*x+y0; } */ #endif