-
C routines called as symbols and not name strings non-ASCII characters removed class checks doe with `inherits()`
C routines called as symbols and not name strings non-ASCII characters removed class checks doe with `inherits()`
gmGeostats.c 25.23 KiB
/*
* SPDX-FileCopyrightText: 2020 Helmholtz-Zentrum Dresden-Rossendorf
* <support@boogaart.de>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
// attention: comment this if not compiling
#include <stdio.h>
#ifdef _OPENMP
#include <omp.h>
#endif
#define USE_FC_LEN_T
#include <Rinternals.h>
#define inR // attention: this must be uncommented if not compiling
#ifdef inR
#include <R.h>
#include <Rmath.h>
#include <R_ext/BLAS.h>
#include <R_ext/Lapack.h>
#endif
#ifndef FCONE
# define FCONE
#endif
#define maxIntervals 1000
short int binBuf[maxIntervals];
double doubleBuf[maxIntervals];
/* int intBuf[maxIntervals];*/
/* massive use of functions to verify: min, max, abs, sqrt, cos, sin */
/* particularly needed: to build the meta-function that calls fbandXXXX
* functions, from line 328 */
typedef void (*vgramDensityFunctionPtr)(int d,double *,double *);
typedef double (*vgramFunctionPtr)(double,const double *);
typedef void (*bandSimFunctionPtr)(int m,const double *,double *,double,const double *);
/* invBitExp2
inverts the sequence of the bits.
this is used for the generation of almost equally space directions in 2D
Lantuejoul (2002), page 194
*/
double invBitExp2(int i) {
int bit = 1;
int inv = 0;
while(i) {
inv <<=1;
inv |= (i&1);
i>>=1;
bit<<=1;
}
return ((double)inv)/bit;
}
/* invBitExp
inverts the sequence of the digits in b-adict representation.
this is used for the generation of almost equally space directions in 3D
Lantuejoul (2002), page 194
*/
double invBitExp(int i,int b) {
int bit = 1;
int inv = 0;
while(i) {
inv *=b;
inv += (i%b);
i/=b;
bit*=b;
}
return ((double)inv)/bit;
}
/*
Gaussian covariance function
*/
double cGauss(double h,const double *extra) {
return exp(-(h*h));
}
/*
Spherical covariance function
*/
double cSph(double h,const double *extra) {
return( h<1 ? 1-1.5*h+0.5*(h*h*h): 0 );
}
/*
Exponential covariance function
*/
double cExp(double h,const double *extra) {
return exp(-h);
}
/*
Switcher for covariance functions
*/
vgramFunctionPtr cgramFunctions[]={
cGauss,cSph,cExp
};
static R_NativePrimitiveArgType CcalcCgram_t[] = {
/* dimX LDX X dimY LDY Y dimC C Nugget nCgr typeCgr A Sill moreC ijEq*/
INTSXP,INTSXP,REALSXP,INTSXP,INTSXP,REALSXP,INTSXP,REALSXP,REALSXP,INTSXP,INTSXP,REALSXP,REALSXP,REALSXP,LGLSXP
};
void CcalcCgram(
const int *dimX,
const int *LDX,
const double *X,
const int *dimY,
const int *LDY,
const double *Y,
const int *dimC,
double *C,
const double *Nugget, /* d x d*/
const int *nCgrams, /* 1 */
const int *typeCgram, /* length=nCgrams */
const double *A, /* nCgrams x m x m sqrt inverse Matrices */
const double *Sill, /* nCgrams x d x d*/
const double *moreCgramData, /* n x ?*/
const int *ijEqual
) {
int d=dimC[0];
int nX=dimC[1];
int nY=dimC[3];
int m =dimX[1];
int ldx = *LDX;
int ldy = *LDY;
if( dimC[2]!=d )
error("CcalcVgram: Expected covariance dimensions not compatible");
if( dimX[0]!=nX )
error("CcalcVgram: Output does not fit input size for X");
if( dimY[0]!=nY )
error("CcalcVgram: Output does not fit input size for Y");
if( dimY[1]!=m )
error("CcalcVgram: Column dimensions of X and Y do not fit");
if( m<1 || m>3)
error("Can not handel spatial dimensions outside 1-3");
int outBufSize=d*d*nX*nY;
int i,j,k,lx,ly,s; /* 20220424: ev removed */
double delta[3];
double v[3];
double h2,h,val;
for(i=0;i<outBufSize;i++)
C[i]=0.0;
if( *ijEqual ) {
if( nX!=nY )
error("CcalcVgram: ijEqual and rows of X and Y don't fit");
for(lx=0;lx<nX;lx++) {
for(i=0;i<d;i++)
for(j=0;j<d;j++)
C[i+d*(lx+nX*(j+d*lx))]=Nugget[i+d*j];
}
}
for(s=0;s<*nCgrams;s++) { // structure s
for(lx=0;lx<nX;lx++) // sample index on dataset X
for(ly=0;ly<nY;ly++) { // sample index on dataset Y
for(j=0;j<m;j++) // geographic coordinate index
delta[j]=Y[ly+ldy*j]-X[lx+ldx*j]; // compute spatial lags between the selected locations
h2=0;
for(j=0;j<m;j++) {
v[j]=0;
for(k=0;k<m;k++) {
v[j]+=A[s+*nCgrams * (j+m*k)]*delta[k];
}
h2+=v[j]*v[j];
}
h=sqrt(h2);
val=(*(cgramFunctions[typeCgram[s]]))(h,moreCgramData+s);
for(i=0;i<d;i++)
for(j=0;j<d;j++)
C[i+d*(lx+nX*(j+d*ly))] += val*Sill[s+*nCgrams*(i+d*j)];
}
}
}
/* BEGIN deprecated function ? */
/*
vsdfGauss (vector for spatial density function )
generates a vector of independent random normals in a vector
*/
void vsdfGauss(int d,double *extra,double *omega) {
int i;
for(i=0;i<d;i++)
omega[i]=norm_rand();
}
/* END deprecated function ? */
/*
fbandGauss
generates a sinus function with random phase and random frequence on
a band for a gaussian covariance structure.
This is a mixture of turning bands and spectral simulation.
*/
void fbandGauss(int n, /* number of locations */
const double *projs, /* projected locations */
double *band, /* output */
double range, /* projected range */
const double *extra /* extra parameter (unused), for consistency with other covariances */
){
/* Extract a freq. from the 1D Gaussian density along the unitdirection
* where projs were calculated. Evaluate a wave of random phase at the
* projs points. Return that wave */
int i;
double phase,amp,omega,d1,o1,o2,o3;
/* omega = norm_rand() * M_SQRT2 / range * M_SQRT_3; /* sqrt(3) needed to produce effective range*/
// chi(3) distributed radial frequency, with random sign
o1 = norm_rand();
o2 = norm_rand();
o3 = norm_rand();
omega = sqrt(o1*o1 + o2*o2 + o3*o3) * sign(o1);
omega = omega * M_SQRT2 / range * M_SQRT_3; /* sqrt(3) needed to produce effective range*/
phase = unif_rand() * M_2PI;
amp = M_SQRT2; /* Lantuejoul (2002), page 191 */
for(i=0;i<n;i++) {
d1 = phase + projs[i]*omega; // projs, *projs==projs[0], projs[i]==*(projs+i)
d1 = sin(d1);
band[i] = amp*d1;
}
}
// IS THIS RIGHT??
void fbandSph(int n, /* number of locations */
const double *projs, /* projected locations */
double *band, /* output */
double range, /* projected range */
const double *extra /* extra parameter (unused), for consistency with other covariances */
){
int i,j,nIntervals;
double t,x0,x1,effrange;
/* Lantuejoul (2002), page 197 */
/* Find the smallest proj; select a uniform point "x0" left from it at
* most "range" away. Domain = (x0, max(projs)) */
x0 = projs[0]; /* does min exist?? */
x1 = projs[0];
effrange = range;
// effrange = range *2.0; // this was an attempt to get reasonable range fitting
for(i=1;i<n;i++) {
if( projs[i]>x1 )
x1=projs[i];
else if( projs[i]<x0 )
x0=projs[i];
}
x0 += -unif_rand() * effrange;
nIntervals = (int) ceil((x1-x0)/effrange);
if( nIntervals > maxIntervals )
error("fbandSph: Exceeded maxIntervals");
for(i=0;i<nIntervals;i++)
binBuf[i] = unif_rand()<0.5?1:-1;
for(i=0;i<n;i++) {
t=(projs[i]-x0)/effrange;
j=(unsigned int)floor(t);
//band[i]=binBuf[j]*(t-j-0.5)*M_SQRT_3;
band[i]=binBuf[j]*(t-j-0.5)*2.0*M_SQRT_3;
}
}
int bsearchDouble(double x,int n,double *s) {
int j0=0;
int j1=n-1;
int j;
while(j1-j0>1) {
/* We know s[j0] <= x < s[j1] */
j = (j0+j1)/2;
if( x < s[j] )
j1=j;
else
j0=j;
}
return(j0);
}
void fbandExp(int n, /* number of locations */
const double *projs, /* projected locations */
double *band, /* output */
double range, /* projected range */
const double *extra /* extra parameter (unused), for consistency with other covariances */
){
int i,j,ns;
double d1,x0,x1,sign;
/* Lantuejoul (2002), page 196 */
/* Find the smallest proj; select a random exponential point "x0" left
* from it with lambda "2range" away. Domain = (x0, max(projs)) */
sign = unif_rand()>0.5? 1 : -1; /* start + or - randomly */
x0 = projs[0];
x1 = projs[0];
for(i=1;i<n;i++) {
if( projs[i]>x1 )
x1=projs[i];
else if( projs[i]<x0 )
x0=projs[i];
}
x0 -= 2*range*exp_rand();
/* Partition the domain with a Poisson point process of lambda=2range. */
ns = 0;
doubleBuf[0] = x0;
while( doubleBuf[ns]<x1 ){
if( ns>=maxIntervals )
error("fbandExp: too small range; merge with nugget?");
doubleBuf[ns+1] = doubleBuf[ns] + 2*range*exp_rand();
ns ++;
}
/* Assign values*/
for(i=0;i<n;i++){
j=bsearchDouble(projs[i],ns,doubleBuf);
d1 = (doubleBuf[j+1] + doubleBuf[j])/2; /* midpoint */
d1 = projs[i] - d1;
band[i] = d1>0 ? sign : -sign; /* -1 if projs[i]<midpoint; +1 otherwise */
}
}
bandSimFunctionPtr bandSim[]={
fbandGauss,fbandSph,fbandExp
};
void getUnitvec(
int dimX, /* m = 2 or 3 */
int ip, /* number of the band being simulated */
double *unitvec /* out: m x 1*/
) {
/* weak discrepancy sequence of pseudorandom directions in 2D or 3D:
* Lantuejoul (2002), page 194, after Freulon (1992) */
/* 20220424: removed int i; */
double d1,d2,d3;
if(dimX>3)
error("no expression for unit vectors in dimension larger than 3");
if( dimX==3) {
d1=invBitExp2(ip)*2*M_PI;
d2=invBitExp(ip,3);
d3 = sqrt(1-d2*d2);
unitvec[2] = d2;
unitvec[0] = cos(d1)*d3;
unitvec[1] = sin(d1)*d3;
} else if( dimX==2 ) {
Rprintf("Warning: gmGeostatsC.getUnitvec in 2D is incompatible with spherical variograms");
d1=invBitExp2(ip);
unitvec[0] = cos(d1*M_PI);
unitvec[1] = sin(d1*M_PI);
} else if( dimX== 1) {
unitvec[0]=1;
}
}
static R_NativePrimitiveArgType getUnitvecR_t[] = { /* INTSXP,REALSXP */
/* dimX, iP, unitvec */
INTSXP,INTSXP,REALSXP
};
void getUnitvecR(int * dimX,
int * ip,
double *unitvec
) {
getUnitvec(*dimX,*ip,unitvec);
}
static R_NativePrimitiveArgType CMVTurningBands_t[] = { /* INTSXP,REALSXP */
/* dimX, X, dimZ Z nBands sqrtNug nCgram typeCgr A sqrtSill moreCgr */
INTSXP,REALSXP,INTSXP,REALSXP,INTSXP,REALSXP,INTSXP,INTSXP,REALSXP,REALSXP,REALSXP
};
void CMVTurningBands(
const int *dimX, /* n,m */
const double *X,
const int *dimZ, /*d,n,nsim */
double *Z, /* Output Simulation transposed*/
const int *nBands,
const double *sqrtNugget, /* d x d*/
const int *nCgrams, /* 1 */
const int *typeCgram, /* length=nCgrams */
const double *A, /* nCgrams x m x m sqrt inverse Matrices */
const double *sqrtSill, /* nCgrams x d x d*/
const double *moreCgramData /* n x ?*/
) {
const int maxCgramType=2;
const int nsim=dimZ[2];
int i,j,k,s,ss,ev;
double d1,d2; /* 20220424: removed ,d3; */
const double sqrtNBands=sqrt((double) *nBands);
double phase; /* 20220424: removed ,amp; */
const int n=dimX[0];
const int m=dimX[1];
const int d=dimZ[0];
double projs[n];
double band[n];
double v[3];
double omega[3];
int sim;
Rprintf("Starting calculations\n");
if( m<1 || m>3 )
error("CMVTurningBands: illegal X column dimension");
if( dimZ[1]!=n )
error("CMVTurningBands: Z and X do not fit in dimension");
#ifdef inR
GetRNGstate();
#endif
/*setting Z to 0*/
for(sim=0;sim<nsim;sim++) {
for(i=0;i<n;i++)
for(j=0;j<d;j++)
Z[d*i+j]=0.0;
for(s=0;s<*nBands;s++){/* band */
getUnitvec(3, s+1, &(omega[0])); /* obtain a direction; always in 3D, in order for the spherical variogram to be correct */
//getUnitvec(m, s+1, omega); /* obtain a direction */
for(ss=0;ss< *nCgrams;ss++) { /* variogram structure */
if( typeCgram[ss]<0 || typeCgram[ss] > maxCgramType )
error("CMVTurningBands: Unknown variogram type");
/* project all data onto the direction */
for(i=0;i<n;i++){ /* location */
for(j=0;j<m;j++) {
v[j]=0;
for(k=0;k<m;k++)
v[j]+=A[ss+ *nCgrams *(j+m*k)]*X[i+n*k];
}
projs[i]=0;
for(j=0;j<m;j++){ /* spatial dimension */
projs[i]+=omega[j]*v[j];
}
}
/* for each eigenvalue, ... */
for(ev=0;ev<d;ev++) { /* eigenvector */
/* ... obtain a curve at all proj points following the covariance model */
(*bandSim[typeCgram[ss]])(n,projs,band,1.0,moreCgramData+ss);
/* this function takes the projs and returns on band the the curve */
/* ... multiply the eigenvector by the curve, and accumulate */
#ifdef _OPENMP
#pragma omp parallel for \
if(!omp_in_parallel()&&0) \
num_threads(omp_get_num_procs()) \
default(shared) private(i,j,d2)
for(i=0;i<n;i++){ /* location */
for(j=0;j<d;j++){ /* variable */
d2 = sqrtSill[ss + *nCgrams *(j+d*ev)]*band[i];
Z[d*i+j]+=d2;
}
}
#else
for(i=0;i<n;i++){ /* location */
for(j=0;j<d;j++){ /* variable */
d2 = sqrtSill[ss + *nCgrams *(j+d*ev)]*band[i];
Z[d*i+j]+=d2;
}
}
#endif
}
}
}
/* Rescale*/
for(i=0;i<n;i++)
for(j=0;j<d;j++)
Z[d*i+j] /= sqrtNBands; // Lantuejoul 2002 p.193
/* Nugget */
for(i=0;i<n;i++)
for(j=0;j<d;j++) {
d1 = norm_rand();
for(k=0;k<d;k++)
Z[d*i+k] += d1*sqrtNugget[k+d*j]; /*check*/
}
Z+=d*n;
}
#ifdef inR
PutRNGstate();
#endif
}
static R_NativePrimitiveArgType CCondSim_t[] = { /* INTSXP,REALSXP */
/* dimZin Zin Cinv dimX, X, dimZ Z nBands sqrtNugget nugget nCgrams typeCgr A sqrtSill sill moreCgr cbuf dbuf */
INTSXP,REALSXP,REALSXP,INTSXP,REALSXP,INTSXP,REALSXP,INTSXP,REALSXP,REALSXP,INTSXP,INTSXP,REALSXP,REALSXP,REALSXP,REALSXP,REALSXP,REALSXP
};
void CCondSim(
const int *dimZin, /* IN: d, nin */
const double *Zin, /*IN: nin x d Randomfield data to condition to */
const double *Cinv,/*IN: (nin * d) x (nin x d) inverse of Covariance*/
const int *dimX, /* IN: n, m */
const double *X, /* IN: All Lokations, first nin conditioning */
const int *dimZ, /* IN: d, n,nsim */
double *Z, /* OUT: t() Output Simulation */
const int *nBands, /* IN: Desired number of Bands*/
const double *sqrtNugget, /* IN: d x d */
const double *nugget, /* IN: dxd */
const int *nCgrams, /* IN: number of variograms */
const int *typeCgram, /* IN: type of each variogram,length=nCgrams */
/* 0=Gauss, 1=Spherical, 2=Exponential */
const double *A, /* IN: Anisotropy matrices, nCgrams x m x m inverse Matrices */
const double *sqrtSill, /* IN: nCgrams x d x d*/
const double *sill, /* IN: nCgrams x d x d*/
const double *moreCgramData, /* nGrams x 1 Extraparamter*/
double *cbuf, /* BUF: Buffer of length d*d*nin */
double *dbuf /* BUF: Buffer of length d*nin*nsim */
) {
/* 20220424 removed: , const int maxCgramType=2; */
const int n=dimX[0];
const int m=dimX[1];
const int d=dimZin[0];
const int nin = dimZin[1];
const int nsim= dimZ[2];
const int nd=n*d;
const char No='N';
const char Transposed='T';
const int dmnin=d*nin;
const int oneI=1;
const int zeroI = 0;
const double zero=0.0;
const double one=1.0;
const double minus1=-1.0;
int i,j,k; /* 20220424 removed: ,s,ss,ev,l; */
int sim,shift;
/* 20220424 removed: double d1,d2,d3,cv; */
const int dimXin[2] = {nin,m};
const int dimXout[2] = {1,m};
const int dimCbuf[4] = {d,nin,d,1};
// Unconditional Simulation
Rprintf("starting unconditional simulation (%d)\n",nsim);
CMVTurningBands(dimX,
X,
dimZ,
Z,
nBands,
sqrtNugget,
nCgrams,
typeCgram,
A,
sqrtSill,
moreCgramData
);
Rprintf("unconditional simulation done (%d)\n",nsim);
Rprintf("starting conditioning by dual kriging\n");
/* Kriging from simulated using Cinv */
// Create differenes of obs and sim
#ifdef _OPENMP
#pragma omp parallel \
if(!omp_in_parallel()) \
num_threads(omp_get_num_procs()) \
default(shared) private(i,j,sim,shift,k)
{
#pragma omp parallel for
for(int sim=0;sim<nsim;sim++) {
int shift=nd*sim;
for(int i=0;i<nin;i++)
for(int j=0;j<d;j++){
int k=d*i+j;
Z[k+shift]-=Zin[k];
}
}
}
#else
for(int sim=0;sim<nsim;sim++) {
int shift=nd*sim;
for(int i=0;i<nin;i++)
for(int j=0;j<d;j++){
int k=d*i+j;
Z[k+shift]-=Zin[k];
}
}
#endif
/* Z[hinten] -= \hat{Z[hinten]}(Z[vorn]) = cov(hinten,vorn)%*% Cinv %*% Z[vorn] */
/* dbuf = Cinv %*% Z[vorn]
Cinv in R ^ d*nin x d*nin
Z[vorn] in R^d*nin
*/
// Dual Kriging preparation
#ifdef _OPENMP
#pragma omp parallel for \
if(!omp_in_parallel()&&0) \
num_threads(omp_get_num_procs()) \
default(shared) private(sim)
for(sim=0;sim<nsim;sim++) {
F77_NAME(dgemv)(&No,
&dmnin,
&dmnin,
&one,
Cinv,
&dmnin,
Z+nd*sim,
&oneI,
&zero,
dbuf+dmnin*sim,
&oneI FCONE);
}
#else
for(sim=0;sim<nsim;sim++) {
F77_NAME(dgemv)(&No,
&dmnin,
&dmnin,
&one,
Cinv,
&dmnin,
Z+nd*sim,
&oneI,
&zero,
dbuf+dmnin*sim,
&oneI FCONE);
}
#endif
// /* points in*/
//for(i=0;i<nin;i++)
//for(j=0;j<m;j++)
//Xin[m*i+j] = X[m*i+j];
// /* points out*/
//for(i=nin;i<n;i++)
//for(j=0;j<m;j++)
//Xout[m*(i-nin)+j] = X[m*i+j];
/* fill cbuf*/
// ******** Iterate over points
for(i=nin;i<n;i++) {
CcalcCgram(
dimXin,
&n,
X,
dimXout,
&n,
X+i,
dimCbuf,
cbuf,
nugget, /* d x d*/
nCgrams, /* 1 */
typeCgram, /* length=nCgrams */
A, /* nCgrams x m x m sqrt inverse Matrices */
sill, /* nCgrams x d x d*/
moreCgramData,
&zeroI
);
//for(l=0;l<nin;l++) { /* points in*/
//for(j=0;j<d;j++) /* koor point in */
//for(k=0;k<d;k++) /* koor point out */
//cbuf[j+d*(k+d*l)]=0.0; /* geeignet d*d*nin, nugget no */
//for(s=0;s<*nCgrams;s++) { /* structure */
//d1=0;
//for(j=0;j<m;j++) /* spatial dimension */
//for(k=0;k<m;k++) /* spatial dimension */
//d1+=A[s + *nCgrams *(j+m*k)]*omega[j]*omega[k]; /* check */
//cv=(*cgramFunctions[typeCgram[s]])(sqrt(d1),moreCgramData+s);
//for(j=0;j<d;j++) /* koor point in */
//for(k=0;k<d;k++) /* koor point out */
//cbuf[j+d*(k+d*l)]+=cv*sill[s+*nCgrams*(j+d*k)];
//}
//}
/* Z[,i] += t(cbuf(d*nin,d)) %*% dbuf(d*nin) */
#ifdef _OPENMP
#pragma omp parallel for \
if(!omp_in_parallel()&&0) \
num_threads(omp_get_num_procs()) \
default(shared) private(sim)
for(sim=0;sim<nsim;sim++) {
F77_NAME(dgemv)(&Transposed,
&dmnin,
&d,
&minus1,
cbuf,
&dmnin,
dbuf+dmnin*sim,
&oneI,
&one,
Z+i*d+nd*sim,
&oneI FCONE);
}
#else
for(sim=0;sim<nsim;sim++) {
F77_NAME(dgemv)(&Transposed,
&dmnin,
&d,
&minus1,
cbuf,
&dmnin,
dbuf+dmnin*sim,
&oneI,
&one,
Z+i*d+nd*sim,
&oneI FCONE);
}
#endif
}
}
//anaV(v1,m,mx,i*h,dimY,y,sigma0,sigma1);
extern void anaV(double *v, // velocity of a datum
const int m, // number of variables
const double *x, // location of the datum
const double t, // time moment
const int *dimY, // dimension of the data nodes
const double *y, // data nodes
const double *wY, // weights of the data nodes
const double sigma0, // parameter sigma0
const double sigma1 // parameter sigma1
) {
size_t nY=dimY[1]; // number of data nodes
double sigmat=sigma0+t*(sigma1-sigma0); // deviation at this moment
double sigmaD=(sigma1-sigma0);
for(int i=0;i<m;i++){ // initialize velocity
v[i]=0;
}
double ws=0; // sum of weights
for(int j=0;j<nY;j++) { // loop on number of data nodes
// double d=0;
double dz[m];
double s2=0;
for(int i=0;i<m;i++) {
const double ddz=(x[i]-(1-t)*y[m*j+i])/sigmat;
dz[i]=ddz;
s2+=ddz*ddz;
}
double w=exp(-s2/2.0)*wY[j]; // weighting
ws+=w;
for(int i=0;i<m;i++)
v[i]+=w*(sigmaD*dz[i]-y[m*j+i]);
}
for(int i=0;i<m;i++){
v[i]/=ws;
}
}
static R_NativePrimitiveArgType anaForwardC_t[] = { /* INTSXP,REALSXP */
/* dimX, x, dimY y wY stepsp sigma0p sigma1p */
INTSXP,REALSXP,INTSXP,REALSXP,REALSXP,INTSXP, REALSXP, REALSXP
};
extern void anaForwardC(const int *dimX,
double *x,
const int *dimY,
const double *y,
const double *wY, // weights of the data nodes
const int *stepsp,
const double *sigma0p,
const double *sigma1p
) {
const double sigma0=*sigma0p;
const double sigma1=*sigma1p;
const size_t steps=*stepsp;
const size_t m=dimX[0];
const size_t nx=dimX[1];
// const size_t ny=dimY[1];
const double h=((double)1.0)/steps;
if( dimY[0]!=m )
error("anaForwardC: x and y have different number of variables / rows");
#ifdef _OPENMP
#pragma omp parallel for
for(size_t i=0;i<nx;i++) {
double v1[m];
double v2[m];
double xx[m];
double *mx=x+m*i;
for(size_t s=0;s<steps;s++) {
// v1
anaV(v1,m,mx,s*h,dimY,y,wY,sigma0,sigma1);
// xx=x+h*v1
for(int j=0;j<m;j++)
xx[j]=mx[j]+h*v1[j];
// v2
anaV(v2,m,xx,(s+1)*h,dimY,y,wY,sigma0,sigma1);
// x+=0.5*h*(v1+v2)
for(int j=0;j<m;j++)
mx[j]+=0.5*h*(v1[j]+v2[j]);
}
}
#else
for(size_t i=0;i<nx;i++) {
double v1[m];
double v2[m];
double xx[m];
double *mx=x+m*i;
for(size_t s=0;s<steps;s++) {
// v1
anaV(v1,m,mx,s*h,dimY,y,wY,sigma0,sigma1);
// xx=x+h*v1
for(int j=0;j<m;j++)
xx[j]=mx[j]+h*v1[j];
// v2
anaV(v2,m,xx,(s+1)*h,dimY,y,wY,sigma0,sigma1);
// x+=0.5*h*(v1+v2)
for(int j=0;j<m;j++)
mx[j]+=0.5*h*(v1[j]+v2[j]);
}
}
#endif
}
static R_NativePrimitiveArgType anaBackwardC_t[] = { /* INTSXP,REALSXP */
/* dimX, x, dimY y wY stepsp sigma0p sigma1p */
INTSXP,REALSXP,INTSXP,REALSXP,REALSXP,INTSXP, REALSXP, REALSXP
};
extern void anaBackwardC(const int *dimX,
double *x,
const int *dimY,
const double *y,
const double *wY, // weights of the data nodes
const int *stepsp,
const double *sigma0p,
const double *sigma1p
) {
const double sigma0=*sigma0p;
const double sigma1=*sigma1p;
const size_t steps=*stepsp;
const size_t m=dimX[0];
const size_t nx=dimX[1];
// const size_t ny=dimY[1];
const double h=((double)1.0)/steps;
if( dimY[0]!=m )
error("anaBackwardC: x and y have different number of variables / rows");
#ifdef _OPENMP
#pragma omp parallel for
for(size_t i=0;i<nx;i++) {
double v1[m];
double v2[m];
double xx[m];
double *mx=x+m*i;
for(size_t s=0;s<steps;s++) {
// v1
anaV(v1,m,mx,1-s*h,dimY,y,wY,sigma0,sigma1);
// xx=x-h*v1
for(int j=0;j<m;j++)
xx[j]=mx[j]-h*v1[j];
// v2
anaV(v2,m,xx,1-(s+1)*h,dimY,y,wY,sigma0,sigma1);
// x+=0.5*h*(v1+v2)
for(int j=0;j<m;j++)
mx[j]-=0.5*h*(v1[j]+v2[j]);
}
}
#else
for(size_t i=0;i<nx;i++) {
double v1[m];
double v2[m];
double xx[m];
double *mx=x+m*i;
for(size_t s=0;s<steps;s++) {
// v1
anaV(v1,m,mx,1-s*h,dimY,y,wY,sigma0,sigma1);
// xx=x-h*v1
for(int j=0;j<m;j++)
xx[j]=mx[j]-h*v1[j];
// v2
anaV(v2,m,xx,1-(s+1)*h,dimY,y,wY,sigma0,sigma1);
// x+=0.5*h*(v1+v2)
for(int j=0;j<m;j++)
mx[j]-=0.5*h*(v1[j]+v2[j]);
}
}
#endif
}
/* ======================================
* EXPORT FUNCTIONS TO R
* ======================================
*/
static R_CMethodDef cMethods[] = {
{"CcalcCgram", (DL_FUNC) &CcalcCgram, 15, CcalcCgram_t},
{"CMVTurningBands", (DL_FUNC) &CMVTurningBands, 11, CMVTurningBands_t},
{"CCondSim", (DL_FUNC) & CCondSim, 18, CCondSim_t},
{"anaForwardC", (DL_FUNC) &anaForwardC, 8, anaForwardC_t},
{"anaBackwardC", (DL_FUNC) &anaBackwardC, 8, anaBackwardC_t},
{"getUnitvecR", (DL_FUNC) &getUnitvecR, 3, getUnitvecR_t},
{NULL, NULL, 0}
};
//{"CMVTurningBands2", (DL_FUNC) &CMVTurningBands2, 11, CMVTurningBands2_t},
void R_init_gmGeostats(DllInfo *info)
{
R_registerRoutines(info, cMethods, NULL, NULL, NULL);
R_useDynamicSymbols(info, FALSE);
R_forceSymbols(info, TRUE);
}