/*
 * Copyright (C) 1996-2011 Daniel Waggoner and Tao Zha
 *
 * This free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * It 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.
 *
 * If you did not received a copy of the GNU General Public License
 * with this software, see <http://www.gnu.org/licenses/>.
 */

#include "dw_switch.h"
#include "dw_switchio.h"
#include "dw_metropolis_theta.h"
#include "dw_rand.h"
#include "dw_error.h"
#include "dw_ascii.h"
#include "dw_parse_cmd.h"
#include "dw_array.h"
#include "dw_metropolis_simulation.h"
#include "dw_std.h"

#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>

#include <time.h>

/* Undefine to use wall time instead of process time */
//#define WALL_TIME

//=======================

int Simulate(int burn_in, int draws, int thin, int period, TStateModel *model, FILE *f_out)
{
#ifdef WALL_TIME
  time_t time;
#else
   clock_t begin_time;
#endif
  int i, j, check, ntheta, nq;
  TVector theta, q;

  // Initialization
  ntheta=NumberFreeParametersTheta(model);
  nq=NumberFreeParametersQ(model);
  if (ntheta) theta=CreateVector(ntheta);
  if (nq) q=CreateVector(nq);

  // Burn-in
  ResetCounts_metropolis_theta(model->metropolis_theta);
  ResetMetropolisHastingsCounts_q(model); 
  if (burn_in > 0)
    { 
      printf("(0 / %d)   Beginning burn in.\n",burn_in);
#ifdef WALL_TIME
      begin_time=time((time_t*)NULL);
#else
      begin_time=clock();
#endif
      for (check=period, i=1; i <= burn_in; i++)
	{
	  DrawAll(model); 

	  if (i == check)
	    {
	      check+=period;
#ifdef WALL_TIME
	      printf("(%d / %d)  Total Elapsed Time: %d seconds\n",i,burn_in,(int)(time((time_t*)NULL) - begin_time));
#else
	      printf("(%d / %d)  Total Elapsed Time: %lf seconds\n",i,burn_in,((double)(clock() - begin_time))/CLOCKS_PER_SEC);
#endif
	    }
	}
#ifdef WALL_TIME
      printf("(%d / %d)   Elapsed Time: %d seconds\n",burn_in,burn_in,(int)(time((time_t*)NULL) - begin_time));
#else
      printf("(%d / %d)   Elapsed Time: %lf seconds\n",burn_in,burn_in,((double)(clock() - begin_time))/CLOCKS_PER_SEC);
#endif
    }

  // Simulate
  if (draws > 0)
    { 
      printf("(0 / %d)   Beginning simulation.\n",draws);
#ifdef WALL_TIME
      begin_time=time((time_t*)NULL);
#else
      begin_time=clock();
#endif
      for (check=period, i=1; i <= draws; i++)
	{
	  for (j=thin; j > 0; j--) DrawAll(model);

	  fprintf(f_out,"%le %le",LogPosterior_StatesIntegratedOut(model),LogLikelihood_StatesIntegratedOut(model));
	  if (ntheta) 
	    {
	      ConvertThetaToFreeParameters(model,pElementV(theta));
	      for (j=0; j < ntheta; j++) fprintf(f_out," %le",ElementV(theta,j));
	    }
	  if (nq)
	    {
	      ConvertQToFreeParameters(model,pElementV(q));
	      for (j=0; j < nq; j++) fprintf(f_out," %le",ElementV(q,j));
	    }
	  fprintf(f_out,"\n");

	  if (i == check)
	    {
	      check+=period;
#ifdef WALL_TIME
	      printf("(%d / %d)  Total Elapsed Time: %d seconds\n",i,draws,(int)(time((time_t*)NULL) - begin_time));
#else
	      printf("(%d / %d)  Total Elapsed Time: %lf seconds\n",i,draws,((double)(clock() - begin_time))/CLOCKS_PER_SEC);
#endif
	    }
	}
#ifdef WALL_TIME
      printf("(%d / %d)   Elapsed Time: %d seconds\n",draws,draws,(int)(time((time_t*)NULL) - begin_time));
#else
      printf("(%d / %d)   Elapsed Time: %lf seconds\n",draws,draws,((double)(clock() - begin_time))/CLOCKS_PER_SEC);
#endif
    }

  // Clean up
  if (ntheta) FreeVector(theta);
  if (nq) FreeVector(q);
  return 0;
}

void SetupDirections(TVector *direction, int n)
{
  /******************************************************************************/
  // indexes 1 and 2 are extremely negatively correlated
  PRECISION b;
  InitializeVector(direction[1]=CreateVector(n),0.0);
  InitializeVector(direction[2]=CreateVector(n),0.0);
  b=1.0/sqrt(2);
  ElementV(direction[1],1)=b;
  ElementV(direction[1],2)=-b;
  ElementV(direction[2],1)=b;
  ElementV(direction[2],2)=b;
/******************************************************************************/

/******************************************************************************
  // indexes 1 and 2 are extremely negatively correlated
  // index 21 and sum of 1 and 2 are positively correlated
  PRECISION a, b, r;
  if (n > 21)
    {
      InitializeVector(direction[1]=CreateVector(n),0.0);
      InitializeVector(direction[2]=CreateVector(n),0.0);
      InitializeVector(direction[21]=CreateVector(n),0.0);
      b=1.0/sqrt(2);
      a=0.02;
      r=1.0/sqrt(1+2*a*a);
      ElementV(direction[1],1)=b;
      ElementV(direction[1],2)=-b;

      ElementV(direction[2],1)=b*r;
      ElementV(direction[2],2)=b*r;
      ElementV(direction[2],21)=-2.0*a*b*r;

      ElementV(direction[21],1)=a*r;
      ElementV(direction[21],2)=a*r;
      ElementV(direction[21],21)=r;
    }
  else
    {
      printf("Error SetupDirections(): dimension not large enough\n");
      dw_exit(0);
    }
/******************************************************************************/
}

int WriteMetropolisThetaInfo(char *filename, char *tag, int type, PRECISION center_s, int period_s, int max_period_s, 
				    PRECISION center_a, int period_a, int max_period_a, int ndraws, int elapsed_time, 
				    TStateModel *model)
{
  FILE *f_out;
  time_t ltime=time((time_t*)NULL);

  if (!(f_out=fopen(filename,"wt")))
    {
      printf("Unable to create %s for output\n",filename);
      return 0;
    }

  fprintf(f_out,"//== Calibration info ==//\n");

  switch(type)
    {
    case HESSIAN_CALIBRATION | TWO_PASS: fprintf(f_out,"type - hessian two pass calibration\n"); break;
    case DIAGONAL_CALIBRATION | TWO_PASS: fprintf(f_out,"type - diagonal two pass calibration\n"); break;
    case VARIANCE_CALIBRATION | TWO_PASS: fprintf(f_out,"type - variance two pass calibration\n"); break;
    case SPECIAL_CALIBRATION | TWO_PASS: fprintf(f_out,"type - special two pass calibration (call SetupDirections())\n"); break;
    case DIAGONAL_CALIBRATION | PRIOR_CALIBRATION: fprintf(f_out,"type - diagonal calibration of prior\n"); break;
    default: fprintf(f_out,"type - unknown\n"); break;
    }

  if (type & TWO_PASS)
    {
      fprintf(f_out,"target acceptance rate single variable - %lf\n",center_s);
      fprintf(f_out,"initial period single variable - %d\n",period_s);
      fprintf(f_out,"maximum period single variable - %d\n",max_period_s);
      fprintf(f_out,"target acceptance rate overall - %lf\n",center_a);
      fprintf(f_out,"initial period overall - %d\n",period_a);
      fprintf(f_out,"maximum period overall - %d\n",max_period_a);
    }
  else
    {
      fprintf(f_out,"target acceptance rate - %lf\n",center_a);
      fprintf(f_out,"initial period - %d\n",period_a);
      fprintf(f_out,"maximum period - %d\n",max_period_a);
    }

  fprintf(f_out,"total draws - %d\n",ndraws);
  fprintf(f_out,"elapsed time - %d seconds\n",elapsed_time);
  fprintf(f_out,"end time - %s\n",ctime(&ltime));
  if (tag)
    fprintf(f_out,"file tag - %s\n",tag);
  else
    fprintf(f_out,"No file tag\n");


  fprintf(f_out,"\n");

  Write_metropolis_theta(f_out,(char*)NULL,(char*)NULL,model->metropolis_theta);

  fclose(f_out);

  return 1;
}

/*
   Returns 1 if metropolis_theta parameters properly set and 0 otherwise.  See dw_Simulate() for 
   command line options.
*/
int SetUpMetropolisSimulation(int n_args, char **args, char *tag, TStateModel *model, int default_period)
{  
  TMetropolis_theta *metropolis=model->metropolis_theta;
  FILE *f_in;
  int i, ndraws, ntheta, nq, period_s, max_period_s, period_a, max_period_a, 
    begin_time, end_time, free_filename_metropolis=0, free_filename_hessian=0;
  PRECISION center_s, center_a;
  char *filename_variance, *filename_hessian, *filename_metropolis, *id, *fmt;
  TMatrix hessian=(TMatrix)NULL, hessian_theta=(TMatrix)NULL, posterior_draws=(TMatrix)NULL,
    variance=(TMatrix)NULL, X=(TMatrix)NULL;
  TVector mean=(TVector)NULL, x=(TVector)NULL, theta=(TVector)NULL;

  // Get Sizes
  ntheta=NumberFreeParametersTheta(model);
  nq=NumberFreeParametersQ(model);

  // Input/output file name for metropolis_theta info
  if (!(filename_metropolis=dw_ParseString_String(n_args,args,"af",(char*)NULL)))
    {
      if (!tag)
	{
	  printf("No adaptive filename (-af) or tag (-t) specified\n");
	  return 0;
	}
      fmt="metropolis_theta_%s.out";
      sprintf(filename_metropolis=(char*)dw_malloc(strlen(fmt) + strlen(tag) - 1),fmt,tag);
      free_filename_metropolis=1;
    }

  // First try: read info from adpative file if -diagonal, -hessian, -variance, -special are not specified
  if ((dw_FindArgument_String(n_args,args,"diagonal") == -1) && (dw_FindArgument_String(n_args,args,"variance") == -1)
      && (dw_FindArgument_String(n_args,args,"hessian") == -1) && (dw_FindArgument_String(n_args,args,"special") == -1))
    if (Read_metropolis_theta((FILE*)NULL,filename_metropolis,(char*)NULL,metropolis))
      {
	// Cleanup and return
	if (free_filename_metropolis) dw_free(filename_metropolis);
	return READ_METROPOLIS_INFO;
      }
    else
      printf("Unable to open %s.  Attempting calibration\n",filename_metropolis);
  else 
    printf("Starting recalibration\n");

  // Setup calibration parameters
  center_s=dw_ParseFloating_String(n_args,args,"cs",0.20);
  center_a=dw_ParseFloating_String(n_args,args,"ca",0.25);
  period_s=dw_ParseInteger_String(n_args,args,"ps",default_period);
  period_a=dw_ParseInteger_String(n_args,args,"pa",default_period);
  max_period_s=dw_ParseInteger_String(n_args,args,"mps",8*period_s);
  max_period_a=dw_ParseInteger_String(n_args,args,"mpa",16*period_a);

  // Second try: Read parameter draws and calibrate using variance directions if -variance is specified
  if (filename_variance=dw_ParseString_String(n_args,args,"variance",(char*)NULL))
    {
      if (!(posterior_draws=dw_ReadPosteriorDraws((FILE*)NULL,filename_variance,(char*)NULL,ntheta+nq)))
	{
	  printf("Unable to read posterior draws file - %s.\n",filename_variance);
	  return 0;
	}
      InitializeMatrix(variance=CreateMatrix(ntheta,ntheta),0.0);
      X=CreateMatrix(ntheta,ntheta);
      InitializeVector(mean=CreateVector(ntheta),0.0);
      x=CreateVector(ntheta+nq+2);
      theta=CreateVector(ntheta);
      for (i=RowM(posterior_draws)-1; i >= 0; i--)
	{
	  RowVector(x,posterior_draws,i);
	  SubVector(theta,x,2,ntheta);
	  AddVV(mean,mean,theta);
	  OuterProduct(X,theta,theta);
	  AddMM(variance,variance,X);
	}
      ProductVS(mean,mean,1.0/(PRECISION)RowM(posterior_draws));
      ProductMS(variance,variance,1.0/(PRECISION)RowM(posterior_draws));
      SubtractMM(variance,variance,OuterProduct(X,mean,mean));

      // Initializing scale and directions using hessian
      Setup_metropolis_theta_variance(metropolis,variance);
      Setup_metropolis_theta_blocks_single(metropolis);

      // Calibrating
      begin_time=(int)time((time_t*)NULL);
      ndraws=Calibrate_metropolis_theta_two_pass(model,center_s,period_s,max_period_s,center_a,period_a,max_period_a,1);
      end_time=(int)time((time_t*)NULL);

      // Print Metropolis info
      WriteMetropolisThetaInfo(filename_metropolis,tag,VARIANCE_CALIBRATION | TWO_PASS,center_s,period_s,max_period_s,
			       center_a,period_a,max_period_a,ndraws,end_time-begin_time,model);

      // Clean up and return
      FreeMatrix(posterior_draws);
      FreeMatrix(variance);
      FreeMatrix(X);
      FreeVector(x);
      FreeVector(mean);
      FreeVector(theta);
      if (free_filename_metropolis) dw_free(filename_metropolis);
      return VARIANCE_CALIBRATION | TWO_PASS;
    }

  // Third try: Read hessian and calibrate using hessian directions if -hessian is specified
  if (dw_FindArgument_String(n_args,args,"hessian") != -1)
    {
      if (!(filename_hessian=dw_ParseString_String(n_args,args,"hf",(char*)NULL)))
	{
	  if (!tag)
	    {
	      printf("No hessian filename (-hf) or tag (-t) specified\n");
	      return 0;
	    }
	  fmt="outdataout_%s.prn";
	  sprintf(filename_hessian=(char*)dw_malloc(strlen(fmt) + strlen(tag) - 1),fmt,tag);
	  free_filename_hessian=1;
	}
      if (f_in=fopen(filename_hessian,"rt"))
	{
	  // Use correct hessian identifier
	  //id="%--- Hessian matrix at the log posterior peak ---";
	  id="Hessian = [";
	  if (dw_SetFilePosition(f_in,id))
	    {
	      if (dw_ReadMatrix(f_in,hessian=CreateMatrix(ntheta+nq,ntheta+nq)))
		{
		  hessian_theta=SubMatrix((TMatrix)NULL,hessian,0,0,ntheta,ntheta);

		  // Initializing scale and directions using hessian
		  Setup_metropolis_theta_hessian(metropolis,hessian_theta);
		  Setup_metropolis_theta_blocks_single(metropolis);
 
		  // Calibrating
		  begin_time=(int)time((time_t*)NULL);
		  ndraws=Calibrate_metropolis_theta_two_pass(model,center_s,period_s,max_period_s,center_a,period_a,max_period_a,1);
		  end_time=(int)time((time_t*)NULL);

		  // Print Metropolis info
		  WriteMetropolisThetaInfo(filename_metropolis,tag,HESSIAN_CALIBRATION | TWO_PASS,center_s,period_s,max_period_s,
					   center_a,period_a,max_period_a,ndraws,end_time-begin_time,model);

		  // Clean up and return
		  FreeMatrix(hessian_theta);
		  FreeMatrix(hessian);
		  if (free_filename_hessian) dw_free(filename_hessian);
		  if (free_filename_metropolis) dw_free(filename_metropolis);
		  fclose(f_in);
		  return HESSIAN_CALIBRATION | TWO_PASS;
		}
	      else
		printf("Unable to read hessian matrix after %s in %s.\n",id,filename_hessian);
	      FreeMatrix(hessian);
	    }
	  else
	    printf("Unable to find %s in %s.\n",id,filename_hessian);
	  fclose(f_in);
	}
      else
	printf("Unable to open %s.\n",filename_hessian);
      if (free_filename_hessian) dw_free(filename_hessian);
      if (free_filename_metropolis) dw_free(filename_metropolis);
      return 0;
    }

  // Last try: Use diagonal
  // Initializing scale and directions
  Setup_metropolis_theta_diagonal(metropolis);
  Setup_metropolis_theta_blocks_single(metropolis);

  // Special handling of directions?
  if (dw_FindArgument_String(n_args,args,"special") != -1)
    SetupDirections(metropolis->direction,metropolis->n_parameters);
 
  // Calibrating
  begin_time=(int)time((time_t*)NULL);
  ndraws=Calibrate_metropolis_theta_two_pass(model,center_s,period_s,max_period_s,center_a,period_a,max_period_a,1);
  end_time=(int)time((time_t*)NULL);

  // Print Metropolis info
  WriteMetropolisThetaInfo(filename_metropolis,tag,DIAGONAL_CALIBRATION | TWO_PASS,center_s,period_s,max_period_s,
			   center_a,period_a,max_period_a,ndraws,end_time-begin_time,model);

  // Clean up and return
  if (free_filename_metropolis) dw_free(filename_metropolis);
  return ((dw_FindArgument_String(n_args,args,"special") != -1) ? SPECIAL_CALIBRATION : DIAGONAL_CALIBRATION) | TWO_PASS;
}

//****************************************************************************//
//**************************** Simulation Main  *****************************//
//****************************************************************************//
/*
   Command line parameters

    General parameters
     -t : filename tag
     -ft : filename tag - supersedes -t
     -outtag : filename tag - supersedes -t and -ft

    Adaptive jump ratio parameters
     -cs <real>: target acceptance rate for single variable calibrations (default = 0.20)
     -ca <real> : target acceptance rate for overall calibrations (default = 0.25)
     -ps <integer> : the initial period for the single variable calibrations (default = 20)
     -pa <integer> : the initial period for the overall calibrations (default = 20)
     -mps <integer> : the maximum period for the single variable calibrations (default = 8*ps)
     -mpa <integer> : the maximum period for the overall calibrations (default = 16*mps)
     -diagonal : Forces calibration using two-pass diagonal, even if calibration has alread been performed.
                 This is the default option.
     -hessian : Forces calibration using two-pass hessian, even if calibration has already been performed.
     -variance <filename> : Forces calibration using two-pass variance, even if calibration has already
                            been performed.  Reads draws from filename.
     -special : Forces calibration using two-pass with custom directions (calls SetupDirections()), even if 
                calibration has already been performed.
     -af <filename> : file for storing the calibrated metropolis parameters. (default = metropolis_theta_<tag>.out)
     -hf <filename> : file containing the hessian matrix. (default = outdataout_<tag>.prn)

    Simulation parameters
     -ndraws : number of draws to save (default = 1000)
     -burnin : number of burn-in draws (default = 0.1 * ndraws)
     -thin : thinning factor.  Total number of draws made is thin*ndraws + burnin (default = 1)
     -of <filename> : output filename (default = simulation_<tag>.out)
     -random <filename> : Reads previous simulation output and randomly selects a starting value. 
     -database : Saves draws to database - not currently implemented 
   
   Attempts to setup metropolis parameters from command line for simulating theta. Note if none of -diagonal,
   -hessian, or -special are specified, the default behavior is to first look for calibration file and it is
   not present to use the two-pass diagonal method.
*/
void dw_simulate_command_line(int n_args, char **args, TStateModel *model, TVector start_value, int generator_init)
{
  FILE *f_out, *f_start;
  char *tag, *default_filename, *filename, *fmt;
  int j, row, ndraws, burn_in, thin, default_period=20, n_theta=NumberFreeParametersTheta(model), n_q=NumberFreeParametersQ(model);
  TMatrix draws;
  TVector draw;
  PRECISION logposterior, loglikelihood;

  // Initialize generator
  dw_initialize_generator(generator_init);

  // Get tag from command line
  tag=dw_ParseString(n_args,args,'t',(char*)NULL);
  tag=dw_ParseString_String(n_args,args,"ft",tag);
  tag=dw_ParseString_String(n_args,args,"outtag",tag);
  
  // Set maximum posterior and write initial value
  model->max_log_posterior=logposterior=LogPosterior_StatesIntegratedOut(model);
  loglikelihood=LogLikelihood_StatesIntegratedOut(model);
  if (model->max_posterior_theta) ConvertThetaToFreeParameters(model,pElementV(model->max_posterior_theta));
  if (model->max_posterior_q) ConvertQToFreeParameters(model,pElementV(model->max_posterior_q));
  fmt="simulation_startmax_%s.out";
  sprintf(filename=(char*)dw_malloc(strlen(fmt) + strlen(tag) - 1),fmt,tag);
  if (!(f_start=fopen(filename,"wt")))
    printf("Unable to open %s\n",filename);
  else
    {
      fprintf(f_start,"%.14le %.14le",logposterior,loglikelihood);
      if (model->max_posterior_theta) 
	for (j=0; j < n_theta; j++) fprintf(f_start," %.14le",ElementV(model->max_posterior_theta,j));
      if (model->max_posterior_q)
	dw_PrintVector(f_start,model->max_posterior_q," %.14le");
      else
	fprintf(f_start,"\n");
    }
  dw_free(filename);

  // Push starting value into model 
  if (start_value)
    {
      if (n_theta) ConvertFreeParametersToTheta(model,pElementV(start_value));
      if (n_q) ConvertFreeParametersToQ(model,pElementV(start_value)+n_theta);
      logposterior=LogPosterior_StatesIntegratedOut(model);
      loglikelihood=LogLikelihood_StatesIntegratedOut(model);
      if (f_start)
	{
	  fprintf(f_start,"%.14le %.14le",logposterior,loglikelihood);
	  dw_PrintVector(f_start,start_value," %.14le");
	}
      if (logposterior > model->max_log_posterior)
	{
	  model->max_log_posterior=logposterior;
	  if (model->max_posterior_theta) ConvertThetaToFreeParameters(model,pElementV(model->max_posterior_theta));
	  if (model->max_posterior_q) ConvertQToFreeParameters(model,pElementV(model->max_posterior_q));
	}
    }

  // Random starting values
  if (filename=dw_ParseString_String(n_args,args,"random",(char*)NULL))
    if (draws=dw_ReadPosteriorDraws((FILE*)NULL,filename,(char*)NULL,n_theta+n_q))
      {
	row=(int)floor(dw_uniform_rnd()*RowM(draws));
	if (row >= RowM(draws)) row=RowM(draws);
	draw=RowVector((TVector)NULL,draws,row);
	if (n_theta) ConvertFreeParametersToTheta(model,pElementV(draw)+2);
	if (n_q) ConvertFreeParametersToQ(model,pElementV(draw)+2+n_theta);
	printf("Using row %d as random starting value from %s\n",row,filename);
	printf("initial log posterior = %le  -  %le\n",logposterior=LogPosterior_StatesIntegratedOut(model),ElementV(draw,0));
	printf("initial log likelihood = %le  -  %le\n",loglikelihood=LogLikelihood_StatesIntegratedOut(model),ElementV(draw,1));
	ElementV(draw,0)=logposterior;
	ElementV(draw,1)=loglikelihood;
	if (f_start) dw_PrintVector(f_start,draw," %.14le");
	if (logposterior > model->max_log_posterior)
	  {
	    model->max_log_posterior=logposterior;
	    if (model->max_posterior_theta) ConvertThetaToFreeParameters(model,pElementV(model->max_posterior_theta));
	    if (model->max_posterior_q) ConvertQToFreeParameters(model,pElementV(model->max_posterior_q));
	  }
	FreeVector(draw);
	FreeMatrix(draws);
      }
    else
      {
	printf("Unable to open %s\n",filename);
	dw_exit(0);
      }
  else
    {
      printf("initial log posterior = %le\n",logposterior);
      printf("initial log likelihood = %le\n",loglikelihood);
    }

  if (SetUpMetropolisSimulation(n_args,args,tag,model,default_period))
    {
      // simulation parameters
      ndraws=dw_ParseInteger_String(n_args,args,"ndraws",1000);
      burn_in=dw_ParseInteger_String(n_args,args,"burnin",ndraws/10);
      thin=dw_ParseInteger_String(n_args,args,"thin",1);

      // Starting Simulation
      if (dw_FindArgument_String(n_args,args,"database") == -1)
	{
	  // output filename
	  fmt="simulation_%s.out";
	  sprintf(default_filename=(char*)dw_malloc(strlen(fmt) + strlen(tag) - 1),fmt,tag);
	  filename=dw_ParseString_String(n_args,args,"fo",default_filename);
	  f_out=fopen(filename,"wt");
	  dw_free(default_filename);
	}
      else
	{
	  f_out=(FILE*)NULL;
	  // initialize sdsm
	  //sdsm_init(1001,100,100,1,0,1,1);
	  printf("-database not yet supported\n");
	  return;
	}

      Simulate(burn_in,ndraws,thin,1000,model,f_out);

      if (f_start)
	{
	  fprintf(f_start,"%.14le %.14le",model->max_log_posterior,loglikelihood);
	  if (model->max_posterior_theta) 
	    for (j=0; j < n_theta; j++) fprintf(f_start," %.14le",ElementV(model->max_posterior_theta,j));
	  if (model->max_posterior_q)
	    dw_PrintVector(f_start,model->max_posterior_q," %.14le");
	  else
	    fprintf(f_start,"\n");
	  fclose(f_start);
	}

      if (f_out) fclose(f_out);
    }
  else
    {
      printf("Error setting up Metropolis adaptive simulation\n");
      if (f_start) fclose(f_start);
    }
}
