RFcircembed.alt.2004.modified.cc
/*
Authors
Martin Schlather, martin.schlather@cu.lu

Simulation of a random field by circulant embedding
(see Wood and Chan, or Dietrich and Newsam for the theory )

Copyright (C) 2001 -- 2004 Martin Schlather,

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#define Real double

/********************************************************************/
#define FC1(METHOD,FCT,PARAM)\
actcov=0;\
{ int v;\
for (v=0; v<key->ncov; v++) {\
if ((key->method[v]==METHOD) && (key->left[v])) {\
/* Variance==0 is not eliminated anymore !!! -- maybe this could be improved */\
/*	&& (key->param[v][VARIANCE]>0)) {   */\
/* do not remove the parenths around METHOD!*/\
key->left[v] = false;\
assert((key->covnr[v] >= 0) && (key->covnr[v] < currentNrCov));\
assert(key->param[v][VARIANCE] >= 0.0);\
covnr[actcov] = key->covnr[v];\
if (CovList[covnr[actcov]].FCT==NULL)\
{Xerror=ERRORNOTDEFINED; goto ErrorHandling;}\
memcpy(PARAM[actcov], key->param[v], sizeof(Real) * key->totalparam);\
if (actcov>0) { /* actcov>0 not v>0 since next line actcov-1 -- check not for all v*/\
if ((multiply[actcov-1] = key->op[v-1]) && key->method[v-1] != METHOD){\
if (GENERAL_PRINTLEVEL>0) \
PRINTF("severe error - contact author. %d %d %d %d (%s) %d (%s)\n",\
v, key->op[v-1], key->ncov, key->method[v-1],\
METHODNAMES[key->method[v-1]],\
METHOD, METHODNAMES[METHOD]);\
Xerror=ERRORMETHODMIX; goto ErrorHandling;\
}\
}\

#define FC2\
actcov++;\
}\
}}\
if (actcov==0) { /* no covariance for the considered method found */\
else Xerror=NOERROR_ENDOFLIST;\
goto ErrorHandling;\
}

#define FIRSTCHECK_COV(METHOD,FCT,PARAM)\
unsigned short int actcov;\
int multiply[MAXCOV];\
int covnr[MAXCOV];\
FC1(METHOD,FCT,PARAM)\
if (!key->anisotropy)\
assert(fabs(key->param[v][SCALE] * key->param[v][INVSCALE]-1.0) < EPSILON);\
FC2

#define FIRSTCHECK_COV_ANISO(METHOD, FCT, PARAM, TIMEEXCEPTION)\
Real store_param[TOTAL_PARAM];\
long bytes;\
/* if (key->Time) bytes = key->timespacedim * (key->timespacedim-1); */\
/* else */\
bytes = sizeof(Real) * key->timespacedim * key->timespacedim;\
FC1(METHOD,FCT,PARAM)\
if (key->anisotropy) {\
bool equal;\
int w, endfor;\
endfor = key->totalparam;\
if (key->Time && TIMEEXCEPTION) endfor -= key->timespacedim;\
Real f_epsilon = 1e-15;\
if (actcov>0) {\
/* check whether the multiplicative construction are consistent, */\
/* i.e. that the SPATIAL part of the anisotropy matrices are */\
/* multiplicatives of each other (more precisely, the remaining ones*/\
/* are multiplicatives of the first.) */\
/* The time part of the matrix must be of the form (0,..,0,*).*/\
/* A further goal of this part is the collection of additive blocks */\
/* that have the same anisotropy matrix structure, in order to minimise */\
/* the simulation time */\
assert(nonzero_pos>0);\
quotient[actcov] = PARAM[actcov][nonzero_pos] / store_param[nonzero_pos];\
equal = true;\
for (w=ANISO; w<endfor; w++) {\
equal &= fabs(store_param[w] * quotient[actcov]\
- PARAM[actcov][w]) <\
(fabs(PARAM[actcov][w]) + 1.0*(PARAM[actcov][w]==0.0)) *f_epsilon;\
}\
if (!equal) { /* even not equal up to a multiplicative constant */\
if (multiply[actcov-1]) { Xerror=ERRORANISOMIX; goto ErrorHandling; }\
else { /* ???? nur additive ********* */\
key->left[v]=true;\
actcov--;\
}\
}\
} else {\
memcpy(&(store_param[ANISO]), &(PARAM[actcov][ANISO]), bytes);\
nonzero_pos=ANISO;\
quotient[0] = 1.0;\
while ((nonzero_pos<endfor) && (PARAM[actcov][nonzero_pos]==0))\
nonzero_pos++;\
if (nonzero_pos>=endfor) { Xerror=ERRORTRIVIAL; goto ErrorHandling; }\
}\
} else {\
assert(fabs(key->param[v][SCALE] * key->param[v][INVSCALE]-1.0)\
< EPSILON);\
}\
FC2

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "RFsimu.h"
#include <assert.h>
#include <R_ext/Applic.h>

#ifdef doubleReal
ce_param CIRCEMBED={false, false, TRIVIALSTARTEGY, -1e-7, 1e-3, 3, 10000000.0, 0, 0, 0, 0};
#else
ce_param CIRCEMBED={false, false, TRIVIALSTARTEGY, -1e-5, 1e-3, 3, 10000000.0, 0, 0, 0, 0};
#endif

typedef struct CE_storage {
int m[MAXDIM],halfm[MAXDIM],nn[MAXDIM],cumm[MAXDIM+1]; /* !!!! **** */
param_type param; /* only used in local CE */
double *c,*d;
Real *local, factor; /* only used in local CE */
FFT_storage FFT;
long totalpoints;
} CE_storage;

void FFT_destruct(FFT_storage *FFT)
{
if (FFT->iwork!=NULL) {free(FFT->iwork); FFT->iwork=NULL;}
if (FFT->work!=NULL) {free(FFT->work); FFT->work=NULL;} //?
}

void FFT_NULL(FFT_storage *FFT)
{
FFT->work = NULL;
FFT->iwork = NULL;
}

void CE_destruct(void **S)
{
if (*S!=NULL) {
CE_storage *x;
x = *((CE_storage**)S);
if (x->c!=NULL) free(x->c);
if (x->d!=NULL) free(x->d);
if (x->local!=NULL) free(x->local);
FFT_destruct(&(x->FFT));
free(*S);
*S = NULL;
}
}

/*********************************************************************/
/*           CIRCULANT EMBEDDING METHOD (1994) ALGORITHM             */
/*  (it will always be refered to the paper of Wood & Chan 1994)     */
/*********************************************************************/

void SetParamCircEmbed( int *action, int *force, Real *tolRe, Real *tolIm,
int *trials, int *mmin, int *userfft, int *strategy,
Real *maxmem)
{
SetParamCE(action, force, tolRe, tolIm, trials, mmin, userfft, strategy,
maxmem, &CIRCEMBED, "CIRCEMBED");
}

int fastfourier(double *data, int *m, int dim, bool first, bool inverse,
FFT_storage *FFT)
/* this function is taken from the fft function by Robert Gentleman
and Ross Ihaka, in R */
{
int inv, nseg, n,nspn,i,maxf,maxp,Xerror;
if (first) {
int maxmaxf,maxmaxp;
nseg = maxmaxf =  maxmaxp = 1;
/* do whole loop just for Xerror checking and maxmax[fp] .. */

for (i = 0; i<dim; i++) {
if (m[i] > 1) {
fft_factor(m[i], &maxf, &maxp);
if (maxf == 0) {Xerror=ERRORFOURIER; goto ErrorHandling;}
if (maxf > maxmaxf) maxmaxf = maxf;
if (maxp > maxmaxp) maxmaxp = maxp;
nseg *= m[i];
}
}

if ((FFT->work = (double*) malloc(4 * maxmaxf * sizeof(double)))==NULL) {
Xerror=ERRORMEMORYALLOCATION; goto ErrorHandling;
}
if ((FFT->iwork = (int*) malloc( maxmaxp  * sizeof(int)))==NULL) {
Xerror=ERRORMEMORYALLOCATION; goto ErrorHandling;
}
FFT->nseg = nseg;
//  nseg = LENGTH(z); see loop above
}
inv = (inverse) ? 2 : -2;
n = 1;
nspn = 1;
nseg = FFT->nseg;
for (i = 0; i < dim; i++) {
if (m[i] > 1) {
nspn *= n;
n = m[i];
nseg /= n;
fft_factor(n, &maxf, &maxp);
fft_work(&(data[0]), &(data[1]), nseg, n, nspn, inv, FFT->work,FFT->iwork);
}
}
return 0;
ErrorHandling:
FFT_destruct(FFT);
return Xerror;
}

int fastfourier(double *data, int *m, int dim, bool first, FFT_storage *FFT){
return fastfourier(data, m, dim, first, !first, FFT);
}

int internal_init_circ_embed(Real *steps, bool anisotropy,
int *covnr, int *op, param_type param,
int *nn, int *m, int *cumm, int *halfm,
int dim, int actcov,
CovFctType CovFct,
ce_param* cepar,
FFT_storage *FFT,
long *twoRealmtot,
double **cc)
{
double *c;
Real hx[MAXDIM], totalm;
int  Xerror,trials,index[MAXDIM],dummy;
long mtot=-1,i,k,twoi;
bool positivedefinite, cur_crit, critical, Critical[MAXDIM];

c=NULL;
if (GENERAL_PRINTLEVEL>=5) PRINTF("calculating the Fourier transform\n");

/* cumm[i+1]=\prod_{j=0}^i m[j]
cumm is used for fast transforming the matrix indices into an
index of the vector (the way the matrix is stored) corresponding
to the matrix                   */
/* calculate the dimensions of the matrix C, eq. (2.2) in W&C */

// ("CE missing strategy for matrix entension in case of anisotropic fields ! %d \n", cepar->userfft); Namely if in case the field is not quadratic or the covariance function does not have the same range in all directions!

totalm = 1.0;
for (i=0;i<dim;i++){ // size of matrix at the beginning
int factor;
if (cepar->userfft) {
factor = (cepar->mmin[i] > -2) ? 2 : -cepar->mmin[i];
m[i] =  factor * NiceFFTNumber((unsigned long) nn[i]);
} else {
factor = (cepar->mmin[i] > -1) ? 1 : -cepar->mmin[i];
m[i]= factor *
(1 << (1 + (int) ceil(log((Real) nn[i]) * INVLOG2 - EPSILON1000)));
}
if (m[i]<cepar->mmin[i]) {m[i]=cepar->mmin[i];}
totalm *= (Real) m[i];
}

// printf("%f\n", cepar->maxmem);
if (totalm > cepar->maxmem) {
sprintf(ERRORSTRING_OK, "%f", cepar->maxmem);
sprintf(ERRORSTRING_WRONG,"%f", totalm);
Xerror=ERRORMAXMEMORY;
goto ErrorHandling;
}

positivedefinite = false;
/* Eq. (3.12) shows that only j\in I(m) [cf. (3.2)] is needed,
so only the first two rows of (3.9) (without the taking the
modulus of h in the first row)
The following variable index' corresponds to h(l) in the following
way: index[l]=h[l]        if 0<=h[l]<=m[l]/2
index[l]=h[l]-m[l]   if m[l]/2+1<=h[l]<=m[l]-1
Then h[l]=(index[l]+m[l]) mod m[l] !!
*/

trials=0;
while (!positivedefinite && (trials<cepar->trials)){
trials++;
cumm[0]=1;
for(i=0;i<dim;i++){
halfm[i]=m[i]/2;
index[i]=1-halfm[i];
cumm[i+1]=cumm[i] * m[i]; // only relevant up to i<dim-1 !!
}

mtot=cumm[dim-1] * m[dim-1];
if (GENERAL_PRINTLEVEL>=2) {
for (i=0;i<dim;i++) PRINTF("m[%d]=%d, ",i,m[i]);
PRINTF("mtot=%d\n ",mtot);
}
*twoRealmtot = 2 * sizeof(double) * mtot;

// for the following, see the paper by Wood and Chan!
// meaning of following variable c, see eq. (3.8)
if ((c = (double*) malloc(*twoRealmtot)) == 0) {
Xerror=ERRORMEMORYALLOCATION; goto ErrorHandling;
}

// first determine whether there are odd covariance functions
critical = false;
for (k=0; k<dim; k++) Critical[k]=false;
for (i=0; i<actcov; i++) {
if (CovList[covnr[i]].isotropic==ANISOTROPIC) {
if (!CovList[covnr[i]].even) {
for(k=0; k<dim; k++) {
Critical[k] |= CovList[covnr[i]].odd[k];
}
}
}
}
// ***  critical odd not used yet

for(i=0; i<dim; i++){index[i]=0;}

for (i=0; i<mtot; i++){
cur_crit = false;
for (k=0; k<dim; k++) {
hx[k] = steps[k] *
(Real) ((index[k] <= halfm[k]) ? index[k] : index[k] - m[k]);
cur_crit |= (index[k]==halfm[k]);
}
dummy=i << 1;

//// ------------- -------------
c[dummy] = (critical && cur_crit) ?  0.0 :
CovFct(hx, dim, covnr, op, param, actcov, anisotropy);

c[dummy+1] = 0.0;
k=0; while( (k<dim) && (++(index[k]) >= m[k])) {
index[k]=0;
k++;
}
assert( (k<dim) || (i==mtot-1));
}

if (GENERAL_PRINTLEVEL>6) PRINTF("FFT...");
if ((Xerror=fastfourier(c, m, dim, true, FFT))!=0) goto ErrorHandling;
if (GENERAL_PRINTLEVEL>6) PRINTF("finished\n");

// check if positive definite. If not: enlarge and restart
if (!cepar->force || (trials<cepar->trials)) {
i=0; twoi=0;
// 16.9. < cepar.tol.im  changed to <=
while ((i<mtot) && (positivedefinite=(c[twoi]>=cepar->tol_re) &&
(fabs(c[twoi+1])<=cepar->tol_im)))
{i++; twoi+=2;}
if (!positivedefinite) {
if (GENERAL_PRINTLEVEL>=2)
PRINTF(" nonpos %d  %f %f \n",i,c[twoi],c[twoi+1]);
FFT_destruct(FFT);
free(c); c=NULL;

totalm = 1.0;
switch (cepar->strategy) {
case 0 :
for (i=0;i<dim;i++) { /* enlarge uniformly in each direction, maybe
this should be modified if the grid has
different sizes in different directions */
m[i] <<= 1;
totalm *= (Real) m[i];
}
break;
case 1 :
Real cc, maxcc, hx[MAXDIM];
int maxi;
maxi = -1;
maxcc = RF_NEGINF;
for (i=0; i<dim; i++) hx[i] = 0.0;
for (i=0; i<dim; i++) {
hx[i] = steps[i] * m[i];
cc = fabs(CovFct(hx , dim, covnr, op, param, actcov, anisotropy));
if (GENERAL_PRINTLEVEL>2) PRINTF("%d cc=%e (%e)",i,cc,hx[i]);
if (cc>maxcc) {
maxcc = cc;
maxi = i;
}
hx[i] = 0.0;
}
assert(maxi>=0);
m[maxi] <<= 1;
for (i=0;i<dim; i++) totalm *= (Real) m[i];
break;
default:
assert(false);
}
if (totalm>cepar->maxmem) {
sprintf(ERRORSTRING_OK, "%f", cepar->maxmem);
sprintf(ERRORSTRING_WRONG,"%f", totalm);
Xerror=ERRORMAXMEMORY;
goto ErrorHandling;
}
//	assert(false);
}
} else {if (GENERAL_PRINTLEVEL>=2) PRINTF("forced\n");}
}
assert(mtot>0);

if (GENERAL_PRINTLEVEL>4) {  // delete this part later on
Real cc, maxcc, hx[MAXDIM];
int maxi;
maxcc = RF_NEGINF;
for (i=0; i<dim; i++) hx[i] = 0.0;
for (i=0; i<dim; i++) {
hx[i] = steps[i] * m[i];
cc = fabs(CovFct(hx , dim, covnr, op, param, actcov, anisotropy));
if (cc>maxcc) {
maxcc = cc;
maxi = i;
}
hx[i] = 0.0;
}
}

if (positivedefinite || cepar->force) {
// correct theoretically impossible values, that are still within
// tolerance CIRCEMBED.tol_re/CIRCEMBED.tol_im
Real r, imag;
r = imag = 0.0;
for(i=0,twoi=0;i<mtot;i++) {
if (c[twoi] > 0.0) {
c[twoi] = sqrt(c[twoi]);
} else {
if (c[twoi] < r) r = c[twoi];
c[twoi] = 0.0;
}
{
register Real a;
if ((a=fabs(c[twoi+1])) > imag) imag = a;
}
c[twoi+1] = 0.0;
twoi+=2;
}
if (GENERAL_PRINTLEVEL>1) {
if (r<0.0 || imag>0.0) {
PRINTF("using approximating circulant embedding:\n");
if (r<0.0) PRINTF("\tsmallest real part has been %e \n", r);
if (imag>0.0)
PRINTF("\tlargest modulus of the imaginary part has been %e \n", imag);
}
}
} else {Xerror=ERRORFAILED;goto ErrorHandling;}
if (GENERAL_PRINTLEVEL>=10) {
for (i=0;i<2*mtot;i++) {PRINTF("%f ",c[i]);} PRINTF("\n");
}
*cc = c;
return NOERROR;

ErrorHandling:
if (c!=NULL) {free(c);}
return Xerror;
}

int init_circ_embed(key_type * key, int m)
{
param_type param;
int Xerror, d, start_param[MAXDIM], index_dim[MAXDIM];
long twoRealmtot;
double *c;
Real steps[MAXDIM];
CE_storage *s;

if (!key->grid) {Xerror=ERRORMETHODNOTALLOWED;goto ErrorHandling;}
SET_DESTRUCT(CE_destruct);

if ((key->S[m]=malloc(sizeof(CE_storage)))==0){
Xerror=ERRORMEMORYALLOCATION; goto ErrorHandling;
}
s =  (CE_storage*)key->S[m];
s->c =NULL;
s->d =NULL;
s->local=NULL;
FFT_NULL(&(s->FFT));
key->destruct[m] = CE_destruct;

FIRSTCHECK_COV(CircEmbed,cov,param);
{
int timespacedim,v;
bool no_last_comp;
cov_fct *cov;
// are methods and parameters fine ?
for (v=0; v<actcov; v++) {
GetTrueDim(key->anisotropy, key->timespacedim, param[v],
&timespacedim, &no_last_comp, start_param, index_dim);
cov = &(CovList[covnr[v]]);
if ((key->Time) && !no_last_comp && (cov->isotropic==SPACEISOTROPIC))
{timespacedim--;}
else
if ((cov->check!=NULL) &&
((Xerror=cov->check(param[v], timespacedim, CircEmbed)))!=0)
goto ErrorHandling;
}
}
for (d=0; d<key->timespacedim; d++) {
s->nn[d]=key->length[d];
steps[d]=key->x[d][XSTEP];
}

if ((Xerror=internal_init_circ_embed(steps,
key->anisotropy,
covnr, multiply, param,
s->nn, s->m, s->cumm, s->halfm,
key->timespacedim, actcov,
CovFct,
&CIRCEMBED,
&(s->FFT),
&twoRealmtot,&c))!=0)
goto ErrorHandling;

// here: never replace GENERAL_STORING by key->storing
// since, in MaxStable process sampling, GENERAL_STORING is set to true
// whatever the value of GENERAL_STORING has been!
if (GENERAL_STORING) {
if ((s->d=(double *)malloc(twoRealmtot))==0){
Xerror=ERRORMEMORYALLOCATION;goto ErrorHandling;} //d
}
s->c=c;
return 0;

ErrorHandling:
return Xerror;
}

void internal_do_circ_embed(int *nn, int *m, int *cumm, int *halfm,
double *c, double *d, int Ntot, int dim,
Real *res )
/*
implemented here only for rotationsinvariant covariance functions
for arbitrary dimensions;
(so it works only for even covariance functions in the sense of
Wood and Chan,p. 415, although they have suggested a more general
algorithm;)

Warning! If GENERAL_STORUNG==false when calling init_circ_embed
and GENERAL_STORUNG==true when calling do_circ_embed, the
complete programme will fail, since the initialization depends on
the value of GENERAL_STORUNG
*/
{
int  i, j, k, HalfMp1[MAXDIM], HalfMaM[2][MAXDIM], index[MAXDIM];
Real XX,YY,invsqrtmtot;
bool first, free[MAXDIM+1], noexception;
long mtot;

mtot=cumm[dim-1] * m[dim-1];
for (i=0; i<dim; i++) {
HalfMp1[i] =  ((m[i] % 2)==1) ? -1 : halfm[i];
HalfMaM[0][i] = halfm[i];
HalfMaM[1][i] = m[i] - 1;
}

//if there are doubts that the algorithm below reaches all elements
//of the matrix, uncomment the lines containing the variable xx
//
//bool *xx; xx = (bool*) malloc(sizeof(bool) * mtot);
//for (i=0; i<mtot;i++) xx[i]=true;

invsqrtmtot = 1/sqrt((Real)mtot);

if (GENERAL_PRINTLEVEL>=10) PRINTF("Creating Gaussian variables... \n");
/* now the Gaussian r.v. have to defined and multiplied with sqrt(FFT(c))*/

for (i=0; i<dim; i++) {
index[i]=0;
free[i] = false;
}
free[MAXDIM] = false;
for(;;) {
i = j = 0;
noexception = false;
for (k=0; k<dim; k++) {
i += cumm[k] * index[k];
if ((index[k]==0) || (index[k]==HalfMp1[k])) {
j += cumm[k] * index[k];
} else {
noexception = true; // not case 2 in prop 3 of W&C
j += cumm[k] * (m[k] - index[k]);
}
}
if (GENERAL_PRINTLEVEL>=10) PRINTF("cumm...");
i <<= 1; // since we have to index imaginary numbers
j <<= 1;
if (noexception) { // case 3 in prop 3 of W&C
XX = GAUSS_RANDOM(INVSQRTTWO);
YY = GAUSS_RANDOM(INVSQRTTWO);
d[i] = d[i+1] = c[i];   d[i] *= XX;  d[i+1] *= YY;
d[j] = d[j+1] = c[j];   d[j] *= XX;  d[j+1] *= -YY;
} else { // case 2 in prop 3 of W&C
d[i]   = c[i] * GAUSS_RANDOM(1.0);
d[i+1] = 0;
}

if (GENERAL_PRINTLEVEL>=10) PRINTF("k=%d ", k);

/*
this is the difficult part.
We have to run over roughly half the points, but we should
not run over variables twice (time lost)
Due to case 2, we must include halfm.

idea is:
for (i1=0 to halfm[dim-1])
if (i1==0) or (i1==halfm[dim-1]) then endfor2=halfm[dim-2]
else endfor2=m[dim-2]
for (i2=0 to endfor2)
if ((i1==0) or (i1==halfm[dim-1])) and
((i2==0) or (i2==halfm[dim-2]))
then endfor3=halfm[dim-3]
else endfor3=m[dim-3]
for (i3=0 to endfor3)
....

i.e. the first one that is not 0 or halfm (regarded from dim-1 to 0)
runs over 0..halfm, all the others over 0..m

this is realised in the following allowing for arbitrary value of dim

free==true   <=>   endfor==m[]
*/
k=0;
if (++index[k]>HalfMaM[free[k]][k]) {
// in case k increases the number of indices that run over 0..m increases
free[k] = true;
index[k]= 0;
k++;
while((k<dim) && (++index[k]>HalfMaM[free[k]][k])) {
free[k] = true;
index[k]= 0;
k++;
}
if (k>=dim) break;
// except the very last (new) number is halfm and the next index is
// restricted to 0..halfm
// then k decreases as long as the index[k] is 0 or halfm
if (!free[k] && (index[k]==halfm[k])){//index restricted to 0..halfm?
// first: index[k] is halfm? (test on ==0 is superfluent)
k--;
while ( (k>=0) && ((index[k]==0) || (index[k]==halfm[k]))) {
// second and following: index[k] is 0 or halfm?
free[k] = false;
k--;
}
}
}
}

fastfourier(d, m, dim, false, FFT_heap);

/* now we correct the result of the fastfourier transformation
by the factor 1/sqrt(mtot) and read the relevant matrix out of
the large vector c */
first = true;
for(i=0;i<dim;i++){index[i]=0;}

#define RESULT(OP)\
for (i=0;i<Ntot;i++){ \
j=0; for (k=0; k<dim; k++){j+=cumm[k] * index[k];} \
res[i] OP d[2*j]*invsqrtmtot; \
if ((fabs(d[2*j+1])>CIRCEMBED.tol_im) && \
((GENERAL_PRINTLEVEL>=2 && first) || GENERAL_PRINTLEVEL>=6)){ \
PRINTF("IMAGINARY PART <> 0, %e\n",d[2*j+1]); first=false; \
} \
k=0; while((k<dim) && (++index[k]>=nn[k])) {index[k++]=0;} \
}
}

void do_circ_embed(key_type *key, bool add, int m, Real *res ){
double *d;
CE_storage *s;
s = (CE_storage*)key->S[m];
if (s->d==NULL) {d=s->c;} /* overwrite the intermediate
result directly (algorithm
allows for that) */
else {
assert(key->storing);
d=s->d;
}
assert(key->active);

internal_do_circ_embed(s->nn, s->m, s->cumm, s->halfm,
s->c, d, key->totalpoints,
}

// hinr?! nicht doppeltes Feld generieren, sondern 1faches?
// da sowieso nur 1/3 verwandt wird??
// nein. an sich schon doppeltes Feld; aber bei kompakten Traeger [0,1], muss
// maxabstand der Punkte nur 1/2 betragen (durch Verdoppelung der Matrix
// wird range erreicht oder so aehnlich).
// --> beruecksichtigung bei lokaler simuation

// ?? was hatten die folgenden Kommentare zu bedeuten?
// for future development : make sure that the directions are set up correctly!
// make sure that internal_init is called with a quadratic scheme
// make sure that the relevant part is cut out correctly

int init_circ_embed_local(key_type *key, int m)
{
assert(false);
}

void do_circ_embed_local(key_type *key, bool add, int m, Real *res )
{
assert(false);
}

int init_circ_embed_intrinsic(key_type * key, int m){assert(false);}
void do_circ_embed_intrinsic(key_type *key, bool add, int m, double *res ){
assert(false);}
int init_circ_embed_cutoff(key_type * key, int m){assert(false);}
int FirstCheck_Cov(key_type *key, SimulationType Method, param_type param,
bool No_Multiply, int *covnr, int *multiply,
unsigned short int *actcov){assert(false);}
void SetParamLocal( int *action, double *cutoff_a, double *intrinsic_r){}
`