double *smoothed_rate_Helmstetter(double *xgrid, double *ygrid, double dx, double dy, int Ngrid, double *xs, double *ys, double *err, double *weights, int N, int ord){
/* Calculates background rate from a catalog, using the algorithm from:
 * Helmstetter et al (2007) "High-resolution Time-independent Grid-based Forecast for M ≥ 5 Earthquakes in California"
 *
 * Input:
 *  xgrid, ygrid: x,y grid for which rate should be calculated. size [1...Ngrid]
 *  dx, dy: spacing between grid points.
 *  xs, ys: x,y coordinates of events. size [1...N]
 *  err= location error associated with each event. size [1...N]
 *  weights: weight assigned to each event. Can be used as flag for declustering (0/1 for excluded/selected events), or to weight some events more than others.
 *  		 if weights==NULL, all events are selected with weight=1. size [1...N]
 *  ord= 1,2: indicates if first o second nearest neighbour should be used.
 *
 * Output:
 *  vector of size [1...Ngrid] containing number of events in each grid point for the total time period.
 */

	double d, w;
	double *dist=NULL;
	int *ind, no_ind;
	double *rate, *rate_tot;

	ind=iarray(1,Ngrid);
	rate=darray(0,Ngrid);
	rate_tot=darray(1,Ngrid);
	for (int i=1; i<=Ngrid; i++) rate_tot[i]=0.0;

	switch (ord){
	//calculate first or second nearest neighbor distance for each earthquake:
		case 1:
			all_nearestneighbours(xs, ys, N, NULL, &dist);
			break;
		case 2:
			all_2ndnearestneighbours(xs, ys, N, NULL, &dist);
			break;
		default:
			print_screen("** Error:  illegal value for variable 'ord' in smoothed_rate_Helmstetter.c. \n**");
			print_logfile("** Error:  illegal value for variable 'ord' in smoothed_rate_Helmstetter.c. \n**");
			return NULL;
	}

	//todo could parallelize (omp)
	for (int eq=1; eq<=N; eq++){
		if (!weights || (weights[eq]>0.0)){	//skip if weight=0.0
			d=fmax(dist[eq],err[eq]);
			find_gridpoints_exact(ygrid, xgrid, NULL, dx, dy, 0.0, Ngrid, Ngrid, ys[eq], xs[eq], d, 0.0, 0.0, 10000, &no_ind, &ind, &rate, 1, 0);
			w= (weights)? weights[eq] : 1.0;
			for (int i=1; i<=no_ind; i++) rate_tot[ind[i]]+=w*rate[i];
		}
	}

	free_iarray(ind,1,Ngrid);
	free_darray(rate,0,Ngrid);

	return rate_tot;
}
double *smoothed_rate_Helmstetter_nonuni(double *xgrid, double *ygrid, int Ngrid, double *xs, double *ys, double *err, double *weights, int N, int ord){
	/* Very similar to Helmstetter function, but for non uniform grid.
	 * Since cannot use exact integral of Gaussian function in each grid point, will only use value at the grid cell center.
	 *
	 * Input:
	 *  xgrid, ygrid: x,y grid for which rate should be calculated. size [1...Ngrid]
	 *  dx, dy: spacing between grid points.
	 *  xs, ys: x,y coordinates of events. size [1...N]
	 *  err= location error associated with each event. size [1...N]
	 *  weights: weight assigned to each event. Can be used as flag for declustering (0/1 for excluded/selected events), or to weight some events more than others.
	 *  		 if weights==NULL, all events are selected with weight=1. size [1...N]
	 *  ord= 1,2: indicates if first o second nearest neighbour should be used.
	 *
	 * Output:
	 *  vector of size [1...Ngrid] containing number of events in each grid point for the total time period.
	 */

	double d, w;
	double *dist=NULL;
	int *ind, no_ind;
	double *rate, *rate_tot;

	ind=iarray(1,Ngrid);
	rate=darray(1,Ngrid);
	rate_tot=darray(1,Ngrid);
	for (int i=1; i<=Ngrid; i++) rate_tot[i]=0.0;

	switch (ord){
		case 1:
			all_nearestneighbours(xs, ys, N, NULL, &dist);
			break;
		case 2:
			all_2ndnearestneighbours(xs, ys, N, NULL, &dist);
			break;
		default:
			print_screen("** Error:  illegal value for variable 'ord' in smoothed_rate_Helmstetter_nonuni. \n**");
			print_logfile("** Error:  illegal value for variable 'ord' in smoothed_rate_Helmstetter_nonuni. \n**");
			return NULL;
	}

	//todo could parallelize (omp)
	for (int eq=1; eq<=N; eq++){
		if (!weights || (weights[eq]>0.0)){
			d=fmax(dist[eq],err[eq]);
			// smooth event based on coordinates of the center of each grid point (not exact calculation as in Helmstetter function).
			find_gridpoints(ygrid, xgrid, NULL, NULL, Ngrid, ys[eq], xs[eq], d, 0.0, 0.0001, 1, &no_ind, &ind, &rate, 1, 0);
			w= (weights)? weights[eq] : 1.0;
			for (int i=1; i<=no_ind; i++) rate_tot[ind[i]]+=w*rate[i];
		}
	}

	return rate_tot;
}
Beispiel #3
0
char* proxy_cache(char* input_url, char* h_path, int semid)
{
        umask(000);             //set permission umask(000)
        char homedir[30];
	char hash_url[41];      //hashed URL
        int check = 0;          //check variable

        struct dirent *pFile;   //declare dirent
        DIR *pDir;              //declare DIR 
	
	strcpy(h_path, getHomeDir(homedir));
        strcat(h_path, "/proxy_cache");                 //attach "/proxy_cache" after home directory
        mkdir(h_path, S_IRWXU | S_IRWXG | S_IRWXO);     //make proxy_cache directory

        sha1_hash(input_url, hash_url);                 //convert input_url to hashed URL
        strncat(h_path, "/",1);                         //attach "/" to h_path
        strncat(h_path, hash_url,1);                    //attach hash_url[0] to h_path
        //current h_path = "home directory/proxy_cache/hash_url[0]"

        mkdir(h_path, S_IRWXU | S_IRWXG | S_IRWXO);     //make h_path directory
	
        strncat(h_path, "/",1);                         //attach "/' to h_path
        strncat(h_path,&hash_url[1], 1);                //attach hash_url[1] to h_path
        //current h_path = "home directory/proxy_cache/hash_url[0]/hash_url[1]"
        check=mkdir(h_path, S_IRWXU | S_IRWXG | S_IRWXO);       //make h_path directory
        if(check==-1){                                          //only in case h_path aleady exist, to read file is executed.   
                pDir=opendir(h_path);                           //pDir = h_path directory

                for(pFile=readdir(pDir); pFile; pFile=readdir(pDir)){           //check same name file to already exist(
                        if(strcmp(pFile->d_name, &hash_url[2])==0){             //compare files in h_pat with hash_url[2]~end
                                //!HIT!
                                //print hash_url, local time in "logfile"
				print_logfile(1, semid, hash_url);			
                                check=1;        //if same check ==1? HIT
                                break;
                        }
                }
                closedir(pDir);                 //close directory
        }


        strncat(h_path, "/",1);                 //attach "/" to h_path
        strcat(h_path, &hash_url[2]);                        //current h_path="home directory/proxy_cache/hash_url[0]/hash_url[1]/hash_url[2]~end"
	
        return h_path;
}
Beispiel #4
0
void connect_webserver(char *IPAddr, int portnum, char *buf, char *URL, int semid){
	int hash_fd;			//hash file descriptor
	int socket_fd;			//socket descriptor
	struct sockaddr_in server_addr; 
	int len;
	char res_buf[BUFFSIZE];
	
	creat(hash_path, 0777);		
	hash_fd=open(hash_path, O_WRONLY);
	if((socket_fd = socket(PF_INET, SOCK_STREAM, 0))<0){	//create socket of client
		printf("Proxy Server : can't create socket.\n");//if it fails, print error message
		exit(0);
	}	
	bzero((char*)&server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;                       //set information of c_server_addr 
	server_addr.sin_addr.s_addr=inet_addr(IPAddr);          //set address. s_req_IPAddr is ip address in request message
	server_addr.sin_port=htons(portnum);                          //set port number. HTTP port number is 80

	//request connection to web server
	if(connect(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))<0){
		printf("Proxy Server : can't connect to web server.\n");//if it fails, print error message
	}
	write(socket_fd, buf, strlen(buf)+1);               //write request meesage to web server

	bzero(res_buf, BUFFSIZE);
	
	//print logfile
	print_logfile(0, semid, URL);
	
	//set alarm by 10 second
	alarm(10);	

	while((len=read(socket_fd, res_buf, BUFFSIZE))>0){//read response message from web server, until message finish.
		
		write(hash_fd, res_buf, len);
		bzero(res_buf, BUFFSIZE);
	}
	alarm(0);
	close(hash_fd);
	close(socket_fd);                     //close socket descriptors
}
Beispiel #5
0
int rate_state_evolution(struct catalog cat, double *times, double **cmpdata, struct pscmp *DCFS, double tt0, double tt1, double dt_step, double Asig, double ta,
			int points[], double *out_NeX, double *NeT, double *ReT, double **all_NeT, int N, int NTS, int Neqks, double *gamma_init, double *back_rate, double *R, int last){

	/* Calculates seismicity in space and time based on rate-and-state (Dieterich 1994) constitutive law.
	 * Aseismic stresses in cmpdata are assumed to grow linearly between time steps.
	 *
	 * Input:
	 *  cat: catalog containing earthquakes to be included in LogLikelihood calculation.
	 *  times: timesteps corresponding to aseismic loading. [0...NTS]
	 *  cmpdata: stresses due to aseismic loading. [0...NTS-1; 1...N], where cmpdata[x][m] is the stress change at grid point [m] between times[x+1] and times[x].
	 *  		if NULL, it will be ignored.
	 *  DCFS: structure containing seismic sources. [0...Neqks-1]
	 *  tt0, tt1: start, end time of calculation
	 *  Asig, ta: rate-state parameters
	 *  points: list of indices of points to be included (referred to grid vectors in crst structure in main). if NULL, use sequence [1,2,3,...,N]
	 *  N, NTS, Neqks: no. of grid points, time steps for aseismic sources, seismic sources.
	 *  gamma_init: values of gammas at time tt0. NB: indices refer to *entire grid* (not just those elements of "points"): [1...NgridT]
	 *  back_rate: spatially nonuniform background rate. array containing NgridT times the ratio between avg rate and rate at that point. (so that the sum of back_rate is NgridT).
	 *   		if NULL, will assume it's 1 for all points (uniform rate). NB: indices refer to *entire grid* (not just those elements of "points"): [1...NgridT]
	 *  last: flag indicating if the values of gamma_init should be overwritten at the end, with value at tt1.
	 *
	 * Output:
	 *  out_NeX: number of events in each grid cell. [1...N] (i.e. it refers to the subset of points in "points").
	 *  NeT: total no of events in each time step (i.e., sum of out_NeX). [0...nts-1]
	 *  ReT: total seismicity rate at the end of each time step.  [0...nts-1]
	 *  all_NeT: no of events binned in space and time  [0...nts-1][1...N];
	 *  R: seismicity rate at the time of the earthquakes given in cat (used for first term of LogLikelihood).
	 *
	 *  NB: assumes that times, cat, DCFS, NTS, times are always the same (each time function is called), since many static internal structures are initialized in the first function call.
	 */


	// Variables used for MPI.
	int procId = 0;

	#ifdef _CRS_MPI
		MPI_Comm_rank(MPI_COMM_WORLD, &procId);
	#endif

  double  tau, dtau_dt, dtau_dt00=Asig/ta, ta1;
  int     TS0, TS1, n;
  double  gamma, back_rate_n;
  double  tt0step, tt1step;

  //events will contain times, magnitudes of all earthquakes (both from catalog and from DCFS):
  static double **events;
  static int **indices;	//contains indices of events referred to DCFS and cat.
  int Neq;	//size of events[0...Neq];
  int is_incat, is_inDCFS;	//flag for events in events
  int cat_i, DCFS_i; //indices of elements in events referred to cat, DCFS.
  static int *TS_eqk;	//time step before each earthquake in events.

  // variables used to find earthquakes within each grid point (see below):
  static int **which_eqk;
  static int *num_eqk;
  static float ** cat_weights;
  static int ** DCFS_whichpt;

  //internal variables for seismicity calculation:
  double *NeX;
  double **Rprivate;	//private variable for each OMP thread, corresponds to global R.
  double **NeTprivate, **ReTprivate;
  static double *dt, *NeXdum, *ReX;


  //dummy variables:
  int err=0, errtot=0;
  int j0, next_eqk, counter_eqk, next_TS;
  int counter1, counter2, k;
  double t_pre, t_now, t_endstep;
  double a,b;
  int reach_end;
  int step, nts;
  int nthreads, nthreadstot=omp_get_max_threads();

  static int firsttimein=1;
  int warning_printed=0;


  if (firsttimein==1){
		firsttimein=0;

		//allocate memory:
		NeXdum=darray(1,N);
		ReX=darray(1,N);

		//----------------------------------------------------------------------------------------------//
		//					Set up list of earthquakes for each grid point								//
		//----------------------------------------------------------------------------------------------//

		//create a merged set of events from cat and DCFS; this is needed since the both define calculation time steps.
		events=union_cats2(cat, DCFS, Neqks, &indices, &Neq);

		which_eqk=i2array(1,N,0,Neq-1);	//list of earthquakes in each grid point
		num_eqk=iarray(1,N);	//number of earthquakes in each grid point
		cat_weights=f2array(1,N,0,Neq-1);	//catalog weights
		DCFS_whichpt=i2array(1,N,0,Neq-1);	//grid point index in DCFS elements (since they contain stress field for a selection of pts only)

		for (int n=1; n<=N; n++) num_eqk[n]=0;

		for(int eq=0;eq<Neq;eq++){
			counter1=counter2=1;
			cat_i=indices[1][eq];	//	NB:cat_i[i]==-1 means no events selected.
			DCFS_i=indices[2][eq];  //	NB:DCFS_i[i]==-1 means no events selected.
			for (int n=1; n<=N; n++){
				if (counter2 > DCFS[DCFS_i].nsel && counter1 > cat.ngrid[cat_i]) break;	//all points have already been included
				else{
					//find index in cat and DCFS which may refer to this grid point:
					if (cat_i!=-1) while (counter1 <=cat.ngrid[cat_i] && cat.ngridpoints[cat_i][counter1]<n) counter1+=1;
					if (DCFS_i!=-1) while (counter2 <=DCFS[DCFS_i].nsel && DCFS[DCFS_i].which_pts[counter2]<n) counter2+=1;
					//check if index refers to this grid point:
					is_incat= (cat_i!=-1 && counter1 <= cat.ngrid[cat_i] && cat.ngridpoints[cat_i][counter1]==n) ? 1 : 0;
					is_inDCFS= (DCFS_i!=-1 && counter2 <= DCFS[DCFS_i].nsel && DCFS[DCFS_i].which_pts[counter2]==n) ? 1 : 0;
					//add earthquake to list for this grid point, and fill in cat_weights, DCFS_whichpt accordingly
					if (is_incat | is_inDCFS){
						which_eqk[n][num_eqk[n]]=eq;
						cat_weights[n][num_eqk[n]]= (is_incat)? cat.weights[cat_i][counter1] : 0.0;	//only in DCFS
						DCFS_whichpt[n][num_eqk[n]]= (is_inDCFS)? counter2 : 0;	//only in cat: will not change gamma later.
						num_eqk[n]+=1;
					}
				}
			}
		}

		//----------------------------------------------------------------------------------------------//
		//									Time steps initialization									//
		//----------------------------------------------------------------------------------------------//

		//calculate time step duration:
		if (NTS!=0){
			dt=darray(0,NTS-1);
			for (int g=0; g<NTS; g++) dt[g]=times[g+1]-times[g];
		}

		//find last time step before each earthquake:
		TS_eqk=iarray(0,Neq-1);
		for (int i=0; i<Neq; i++){
			if (NTS==0) TS_eqk[i]=1;	//this will make t_pre be correct later (j0<NTS condition).
			else{
				k=0;
				while(k<NTS && times[k]<events[1][i]) k++;
				if(times[k]>=events[1][i]) k--;
				TS_eqk[i]=k;
				if (k<0 && events[1][i]>=tt0) {
					print_screen("**Warning: no time steps available before earthquake no. %d ** (forecast_stepG2_new.c)\n",i);
					print_logfile("**Warning: no time steps available before earthquake no. %d ** (forecast_stepG2_new.c)\n",i);
					return 1;
				}
			}
		}
  }

  if (Asig==0 && ta==0.0) return(0);	//in this case, function has only been called to setup variables above.

  NeX= (out_NeX)? out_NeX : NeXdum;

  // Initialize vector to 0;
  if (ReT) for(int m=1;m<=N;m++) ReX[m]=0.0;
  if (NeX) for(int m=1;m<=N;m++) NeX[m]=0.0;

  if (tt1<tt0) {
	  print_screen("\n*** Warning: tt1<tt0 in forecast_stepG2_new.c  ***\n");
	  print_logfile("\n*** Warning: tt1<tt0 in forecast_stepG2_new.c  ***\n");
	  return 1;
  }
  if (NTS>0 && times[0]>tt0 && times[NTS]<tt1) {
	  print_screen("\n** Warning: time steps in forecast_stepG don't cover entire forecast range!**\n");
	  print_logfile("\n** Warning: time steps in forecast_stepG don't cover entire forecast range!**\n");
	  return 1;
  }

  //TS0= First time step after tt0.
  TS0=0;
  if (NTS==0) TS0=1;	//this will make t_pre be correct later (j0<NTS condition).
  else{
	  while(TS0<NTS && times[TS0]<=tt0) TS0++;
	  if(procId == 0) {
		  if(times[TS0]<=tt0 & !warning_printed) {
			  warning_printed=1;
			  print_screen("\n*** Warning: times[TS0]<=tt0 in forecast_stepG2_new.c  ***\n");
			  print_logfile("\n*** Warning: times[TS0]<=tt0 in forecast_stepG2_new.c  ***\n");
			  return 1;
		  }
	  }
  }

  //TS1= Last time step before tt1.
  TS1=1;	//this will make t_pre be correct later (j0<NTS condition).
  if (NTS>0){
	  while(TS1<NTS-1 && times[TS1]<tt1) TS1++;
	  if(times[TS1]>=tt1) TS1--;
  }

  //Rprivate is used for parallelization (a barrier creates a bottleneck and poor performance):
  Rprivate=d2array(0,nthreadstot-1, 0, cat.Z);
  if (!Rprivate) memory_error_quit;
  for (int t=0; t<omp_get_max_threads(); t++){
	  for (int eq=0; eq<=cat.Z; eq++) Rprivate[t][eq]=0.0;
  }

  //Similar to above, but for individual time steps:
  nts=(dt_step<tol0) ? 0 : ceil((tt1-tt0)/dt_step);	//number of output time steps;
  for (int i=0; i<nts; i++){
    if (ReT) ReT[i]=0.0;
    if (NeT) NeT[i]=0.0;
  }

  NeTprivate=d2array(0,nthreadstot-1, 0, nts-1);
  ReTprivate=d2array(0,nthreadstot-1, 0, nts-1);
  if (!NeTprivate | !ReTprivate) memory_error_quit;
  for (int t=0; t<omp_get_max_threads(); t++){
	  if (NeT) for (int i=0; i<nts; i++) NeTprivate[t][i]=0.0;
	  if (ReT) for (int i=0; i<nts; i++) ReTprivate[t][i]=0.0;
  }

  err=0;

  //loop over grid points:
  #pragma omp parallel for firstprivate(err) private(n, gamma,tau,j0, next_eqk, next_TS, t_now, t_pre, reach_end, t_endstep, cat_i, DCFS_i, a, b, dtau_dt, counter_eqk, back_rate_n, ta1, tt0step, tt1step, step, TS0, TS1) reduction(+:errtot)
  for(int m=1;m<=N;m++){

	nthreads=omp_get_num_threads();

    tt0step=tt0;
    tt1step= (nts==1)? tt1 : tt0step+dt_step;	//to make sure it enters at least once (floating point error may give problem otherwise).
   
	t_now=tt0;

	if (err!=0) continue;
	n=(points==0)? m : points[m];

	//set background rate and starting gamma given as arguments:
	back_rate_n= (back_rate) ? back_rate[n] : 1.0;
	gamma=gamma_init[n];
	if (NeX) NeX[m]=0.0;

	step=0;

	while (tt1step<=tt1){	//overall time span

		if (dt_step<tol0) break;	//to avoid infinite loop if tt0=tt1 and dt_step=0;

		//TS0= First time step after tt0.
		TS0=0;
		if (NTS==0) TS0=1;	//this will make t_pre be correct later (j0<NTS condition).
		else{
		  while(TS0<NTS && times[TS0]<=tt0step) TS0++;
		  if(procId == 0) {
			  if(times[TS0]<=tt0 & !warning_printed) {
				  warning_printed=1;
				  print_screen("\n*** Warning: times[TS0]<=tt0 in forecast_stepG2_new.c  ***\n");
				  print_logfile("\n*** Warning: times[TS0]<=tt0 in forecast_stepG2_new.c  ***\n");
			  }
		  }
		}

		//TS1= Last time step before tt1.
		TS1=1;	//this will make t_pre be correct later (j0<NTS condition).
		if (NTS>0){
		  while(TS1<NTS-1 && times[TS1]<tt1step) TS1++;
		  if(times[TS1]>=tt1step) TS1--;
		}

		j0=TS0;     //next time step (first time step after tt0)
	    counter_eqk=0;
		reach_end=0;

		//find first earthquake after or at tt0:
		while (counter_eqk<num_eqk[n] && events[1][which_eqk[n][counter_eqk]]<tt0step) counter_eqk+=1;

		//loop over time steps until reaching tt1step:
		while (tol0<(tt1step-t_now)){

			if (err!=0) break;	//error in a previous loop;
			if (counter_eqk>=num_eqk[n]) reach_end=1;	//all earthquakes for this grid point have been included (counter_eqk is out of range).
			else {
				next_eqk=which_eqk[n][counter_eqk];
				if (events[1][next_eqk]>=tt1step) reach_end=1;
			}

			t_endstep= reach_end ? tt1step : events[1][next_eqk];	//end time of this while loop iteration;
			next_TS= reach_end ? TS1 : TS_eqk[next_eqk];		//last time step before t_endstep
			cat_i= reach_end ? 0 : indices[1][next_eqk];		//index of next event (occurring at time events[1][next_eqk])
			DCFS_i= reach_end ? 0 : indices[2][next_eqk];		//index of next event (occurring at time events[1][next_eqk])

			// evolve seismicity up to next barrier (which is the smallest between next earthquake (events[1][next_eqk]), next time step (times[j0]) or tt1step)
			t_pre= (j0<=NTS) ? fmin(t_endstep, times[j0]) - t_now : t_endstep - t_now;	//find time left to next barrier

			dtau_dt=(cmpdata && j0-1>=0 && j0<=NTS)? (Asig/ta)+cmpdata[j0-1][n]/dt[j0-1] : (Asig/ta);//stressing rate during current time step (including stress step from cmpdata and background stressing rate):
			if (t_pre>tol0){
				tau=dtau_dt*t_pre;	//stress change during current time step
				ta1=Asig/dtau_dt;	//dummy variable
				if (NeX) {
					//find no. of earthquakes
					a=gamma*dtau_dt-1;	//dummy variable
					b=a*exp(-t_pre/ta1)+1;	//dummy variable
					if (!isinf(fabs(b))) NeX[m]+= fmax(0.0, back_rate_n*(dtau_dt/dtau_dt00)*(t_pre+ta1*log(b/(gamma*dtau_dt))));	//due to numerical error it can give -ve values.
				}
				//update gamma:
				gamma=(fabs(tau/Asig)>1e-10)? (gamma-t_pre/(tau))*exp(-tau/Asig)+t_pre/(tau) : gamma*(1-tau/Asig)+t_pre/Asig;
			}

			//evolve seismicity between time steps:
			t_now+=t_pre;

			for(int j=j0;j<next_TS;j++){
				dtau_dt=(cmpdata)? (Asig/ta)+cmpdata[j][n]/dt[j] : (Asig/ta);
				tau=dtau_dt*dt[j];
				ta1=Asig/dtau_dt;
				if (NeX) {
					a=gamma*dtau_dt-1;
					b=a*exp(-dt[j]/ta1)+1;

					if (!isinf(fabs(b))) NeX[m]+=fmax(0.0, back_rate_n*(dtau_dt/dtau_dt00)*(dt[j]+ta1*log(b/(gamma*dtau_dt))));	//due to numerical error it can give -ve values for gamma->inf
				}
				gamma=(fabs(tau/Asig)>1e-10)? (gamma-dt[j]/(tau))*exp(-tau/Asig)+dt[j]/(tau) : gamma*(1-tau/Asig)+dt[j]/Asig;
				t_now+=dt[j];
			}

			// evolve seismicity till the end:
			t_pre=t_endstep-t_now;

			if (t_pre>tol0) {
				dtau_dt=(cmpdata)? (Asig/ta)+(1.0/dt[next_TS])*cmpdata[next_TS][n] : (Asig/ta);
				tau=dtau_dt*t_pre;
				ta1=Asig/dtau_dt;
				if (NeX) {
					a=gamma*dtau_dt-1;
					b=a*exp(-t_pre/ta1)+1;
					if (!isinf(fabs(b))) NeX[m]+= fmax(0.0, back_rate_n*(dtau_dt/dtau_dt00)*(t_pre+ta1*log(b/(gamma*dtau_dt)))); //due to numerical error it can give -ve values for gamma->inf
				}
				gamma=(fabs(tau/Asig)>1e-10)? (gamma-t_pre/(tau))*exp(-tau/Asig)+t_pre/(tau) : gamma*(1-tau/Asig)+t_pre/Asig;
			}

			t_now+=t_pre;

			if (reach_end==0){
				if (cat_i!=-1) {
					Rprivate[omp_get_thread_num()][cat_i]+= back_rate_n*cat_weights[n][counter_eqk]*(ta/Asig)/gamma;
				}
				gamma= (DCFS_i==-1 | DCFS_whichpt[n][counter_eqk]==0)? gamma : gamma*exp(-DCFS[DCFS_i].cmb[DCFS_whichpt[n][counter_eqk]]/Asig);
				//if (n==1) printf("[%.5e:%.5e][%.5e:%.5e]: gamma=%f\n",tt0,tt1, tt0step, tt1step,gamma);
				if (isinf(gamma)){
					print_screen("*Warning: gamma==Inf, must choose larger Asig!*\n");
					print_logfile("*Warning: gamma==Inf, must choose larger Asig!*\n");
					err=1;
					errtot+=1;
				}
			}
			j0=next_TS+1;
			counter_eqk+=1;
		  }
		if (NeT) NeTprivate[omp_get_thread_num()][step]+=NeX[m];
		if (ReT) ReTprivate[omp_get_thread_num()][step]+=back_rate_n*(ta/Asig)/gamma;

		if (all_NeT) all_NeT[step][m]=NeX[m];

		step+=1;
		tt0step=tt1step;
		tt1step+=dt_step;
		if (fabs(tt1step-tt1)<tol0) tt1step=tt1;	//to avoid floating point error.

	}

	if (last) gamma_init[n]=gamma;	//update gamma_init with final value;
	if (ReT) ReX[m]=back_rate_n*(ta/Asig)/gamma;	//instantaneous seismicity rate at the end of the time step;

  }

  //collect values of R, NeT, ReT from threads:
  //final rate and tot no. of events given by the sum over all grid points:
  for (int i=0; i<nts; i++){
    if (ReT) ReT[i]=0.0;
    if (NeT) NeT[i]=0.0;
  }
  for (int t=0; t<nthreads; t++){
	  if (R) for (int eq=1; eq<=cat.Z; eq++) R[eq]+=Rprivate[t][eq];
	  if (NeT) for (int i=0; i<nts; i++) {
		if (NeT) NeT[i]+= (i==0) ? NeTprivate[t][i] : NeTprivate[t][i]-NeTprivate[t][i-1];
		if (ReT) ReT[i]+= ReTprivate[t][i];
	  }
  }

  free_d2array(Rprivate,0,nthreadstot-1, 0, cat.Z);
  free_d2array(NeTprivate,0,nthreadstot-1, 0, nts-1);
  free_d2array(ReTprivate,0,nthreadstot-1, 0, nts-1);
  return(errtot);

}