From 408eea806957d89a7cfd63e8cdcecaffa07f81ff Mon Sep 17 00:00:00 2001
From: Raimon Tolosana-Delgado <tolosa53@fwg206.ad.fz-rossendorf.de>
Date: Tue, 29 Sep 2020 08:42:26 +0200
Subject: [PATCH] reattempt to make openMP work multiplatform

---
 DESCRIPTION      |    2 +-
 cran-comments.md |   79 ++-
 src/gmGeostats.c | 1583 +++++++++++++++++++++++-----------------------
 3 files changed, 825 insertions(+), 839 deletions(-)

diff --git a/DESCRIPTION b/DESCRIPTION
index 8157af9..075e0b9 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -50,7 +50,7 @@ Description: Support for geostatistical analysis of multivariate data,
          The methods mainly follow Tolosana-Delgado, Mueller and van den
          Boogaart (2018) <doi:10.1007/s11004-018-9769-3>.
 License: CC BY-SA 4.0 | GPL (>=2)
-URL: https://gitlab.hzdr.de/tolosa53/gmgeostats
+URL: https://gitlab.hzdr.de/geomet/gmGeostats
 Copyright: (C) 2020 by Helmholtz-Zentrum Dresden-Rossendorf and Edith Cowan University;
          gsi.DS code by Hassan Talebi
 RoxygenNote: 7.1.0
diff --git a/cran-comments.md b/cran-comments.md
index db02f8b..f066d45 100644
--- a/cran-comments.md
+++ b/cran-comments.md
@@ -1,40 +1,39 @@
-## Test environments
-
-* Linux: Ubuntu 18.04.4LTS  (local)
-  - R 3.4.4 (production)
-  - R devel 2020-07-28 r78930 (test)
-  - R patched 4.0.2 r78930 (test)
-* Windows 7 Enterprise (test)
-  - R 3.5.1 (test)
-* MacOS x86_64-apple-darwin15.6.0 (64-bit) (test)
-  - R 3.6.1 (2019-07-05)
-
-## R CMD check results
-
-0 errors | 0 warnings | 0 notes
-
-
-## This is a resubmission
-
-```
-Dear maintainer,
-
-Please see the problems shown on
-<https://cran.r-project.org/web/checks/check_results_gmGeostats.html>.
-
-Please correct before 2020-10-03 to safely retain your package on CRAN.
-
-The CRAN Team
-```
-
-... the sympthom being an error while #include <omp.h> in r-release-macos-x86_64, we identified the problem as a lack of appropriate linkage of OpenMP. 
-
-Solution: 
-1.- the header inclusion and all usages of #pragma directives were enclosed in conditional structures
-#ifdef _OPENMP 
- ...
-#endif 
-
-2. `$(SHLIB_OPENMP_CFLAGS)` was added to PKG_CFLAGS and PKG_LIBS fields in Makevars files
-
-3.- as mentioned in `Test environments`, the new code was tested under MacOS as well.
+  ## Test environments
+  
+  * Linux: Ubuntu 18.04.4LTS  (local)
+    - R 3.4.4 (production)
+    - R devel 2020-07-28 r78930 (test)
+    - R patched 4.0.2 r78930 (test)
+  * Windows 7 Enterprise (test)
+    - R 3.5.1 (test)
+  
+  
+  ## R CMD check results
+  
+  0 errors | 0 warnings | 0 notes
+  
+  
+  ## This is a resubmission
+  
+  ```
+  Dear maintainer,
+  
+  Please see the problems shown on
+  <https://cran.r-project.org/web/checks/check_results_gmGeostats.html>.
+  
+  Please correct before 2020-10-03 to safely retain your package on CRAN.
+  
+  The CRAN Team
+  ```
+  
+  ... the sympthom being an error while #include <omp.h> in r-release-macos-x86_64, we identified the problem as a lack of appropriate linkage of OpenMP. 
+  
+  Solution: 
+  1.- the header inclusion and all usages of #pragma directives were enclosed in conditional structures
+  #ifdef _OPENMP 
+   ...
+  #endif 
+  
+  2. `$(SHLIB_OPENMP_CFLAGS)` was added to PKG_CFLAGS and PKG_LIBS fields in Makevars files
+  
+  NOTE: we do not have access to any MacOS machine to test that our solution is effective. Our apologies if this is not working!
\ No newline at end of file
diff --git a/src/gmGeostats.c b/src/gmGeostats.c
index 403bfec..1690f98 100644
--- a/src/gmGeostats.c
+++ b/src/gmGeostats.c
@@ -1,798 +1,785 @@
-/*
- * 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>
-#include <Rinternals.h>
-
-#ifdef _OPENMP
-#include <omp.h>
-#endif
-
-#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
-
-#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;
-}
-
-
-/* invBitExp2
- 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,REALSXP,REALSXP,REALSXP,REALSXP,INTSXP
-};
-
-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,ev,lx,ly,s;
-  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;   
-  omega = norm_rand()  * M_SQRT2 / 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,effrange;
-  /* 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 */
-  effrange = range;  /*  ATTENTION: 3*range, but range is inverted ??? */
-  x0 = projs[0];  /* does min exist?? */
-  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*effrange*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*effrange*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) */			  
-  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)*M_2_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 ) {
-    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 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,d3;
-  const double sqrtNBands=sqrt((double) *nBands);
-  double phase,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) 
-#endif
-    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;  
-    }	  
-    }
-  }
-  }
-    } 
-    /* 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 */
-) {
-  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,s,ss,ev,l;
-  int sim,shift;
-  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	      
-#endif
-      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];
-          }
-      }
-    }
-  /* 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)
-#endif
-    for(sim=0;sim<nsim;sim++) {
-      F77_NAME(dgemv)(&No,
-               &dmnin,
-               &dmnin,
-               &one,
-               Cinv,
-               &dmnin,
-               Z+nd*sim,
-               &oneI,
-               &zero,
-               dbuf+dmnin*sim,
-               &oneI);
-    }
-    // /* 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)
-#endif
-        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);
-        }
-        
-    }
-}
-
-
-
-//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 
-#endif
-  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]);
-    }
-  }
-  
-}
-
-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 
-#endif
-  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]);
-    }
-    
-  }
-  
-}
-
-
-
-
-
-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},
-  {NULL, NULL, 0}
-};
-
-
-void R_init_compositions(DllInfo *info)
-{
-  R_registerRoutines(info, cMethods, NULL, NULL, NULL);
-  R_useDynamicSymbols(info, FALSE);
-  R_forceSymbols(info, TRUE);
-}
-
+/*
+ * 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>
+#include <Rinternals.h>
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+#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
+
+#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;
+}
+
+
+/* invBitExp2
+ 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,REALSXP,REALSXP,REALSXP,REALSXP,INTSXP
+};
+
+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,ev,lx,ly,s;
+  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;   
+  omega = norm_rand()  * M_SQRT2 / 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,effrange;
+  /* 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 */
+  effrange = range;  /*  ATTENTION: 3*range, but range is inverted ??? */
+  x0 = projs[0];  /* does min exist?? */
+  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*effrange*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*effrange*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) */			  
+  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)*M_2_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 ) {
+    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 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,d3;
+  const double sqrtNBands=sqrt((double) *nBands);
+  double phase,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 */
+#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;  
+    }	  
+    }
+  }
+  }
+    } 
+    /* 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 */
+) {
+  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,s,ss,ev,l;
+  int sim,shift;
+  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
+#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];
+          }
+      }
+    }
+  /* 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
+#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);
+    }
+    // /* 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) */
+#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);
+        }
+        
+    }
+}
+
+
+
+//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");
+#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]);
+    }
+  }
+  
+}
+
+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");
+#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]);
+    }
+    
+  }
+  
+}
+
+
+
+
+
+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},
+  {NULL, NULL, 0}
+};
+
+
+void R_init_compositions(DllInfo *info)
+{
+  R_registerRoutines(info, cMethods, NULL, NULL, NULL);
+  R_useDynamicSymbols(info, FALSE);
+  R_forceSymbols(info, TRUE);
+}
+
-- 
GitLab