/* matrix/gsl_matrix_long_double.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough
 *
 * This program is 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.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_MATRIX_LONG_DOUBLE_H__
#define __GSL_MATRIX_LONG_DOUBLE_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_inline.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_vector_long_double.h>
#include <gsl/gsl_blas_types.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

typedef struct
{
  size_t size1;
  size_t size2;
  size_t tda;
  long double * data;
  gsl_block_long_double * block;
  int owner;
} gsl_matrix_long_double;

typedef struct
{
  gsl_matrix_long_double matrix;
} _gsl_matrix_long_double_view;

typedef _gsl_matrix_long_double_view gsl_matrix_long_double_view;

typedef struct
{
  gsl_matrix_long_double matrix;
} _gsl_matrix_long_double_const_view;

typedef const _gsl_matrix_long_double_const_view gsl_matrix_long_double_const_view;

/* Allocation */

GSL_FUN gsl_matrix_long_double *
gsl_matrix_long_double_alloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_long_double *
gsl_matrix_long_double_calloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_long_double *
gsl_matrix_long_double_alloc_from_block (gsl_block_long_double * b,
                                   const size_t offset,
                                   const size_t n1,
                                   const size_t n2,
                                   const size_t d2);

GSL_FUN gsl_matrix_long_double *
gsl_matrix_long_double_alloc_from_matrix (gsl_matrix_long_double * m,
                                    const size_t k1,
                                    const size_t k2,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN gsl_vector_long_double *
gsl_vector_long_double_alloc_row_from_matrix (gsl_matrix_long_double * m,
                                        const size_t i);

GSL_FUN gsl_vector_long_double *
gsl_vector_long_double_alloc_col_from_matrix (gsl_matrix_long_double * m,
                                        const size_t j);

GSL_FUN void gsl_matrix_long_double_free (gsl_matrix_long_double * m);

/* Views */

GSL_FUN _gsl_matrix_long_double_view
gsl_matrix_long_double_submatrix (gsl_matrix_long_double * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_long_double_view
gsl_matrix_long_double_row (gsl_matrix_long_double * m, const size_t i);

GSL_FUN _gsl_vector_long_double_view
gsl_matrix_long_double_column (gsl_matrix_long_double * m, const size_t j);

GSL_FUN _gsl_vector_long_double_view
gsl_matrix_long_double_diagonal (gsl_matrix_long_double * m);

GSL_FUN _gsl_vector_long_double_view
gsl_matrix_long_double_subdiagonal (gsl_matrix_long_double * m, const size_t k);

GSL_FUN _gsl_vector_long_double_view
gsl_matrix_long_double_superdiagonal (gsl_matrix_long_double * m, const size_t k);

GSL_FUN _gsl_vector_long_double_view
gsl_matrix_long_double_subrow (gsl_matrix_long_double * m, const size_t i,
                         const size_t offset, const size_t n);

GSL_FUN _gsl_vector_long_double_view
gsl_matrix_long_double_subcolumn (gsl_matrix_long_double * m, const size_t j,
                            const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_long_double_view
gsl_matrix_long_double_view_array (long double * base,
                             const size_t n1,
                             const size_t n2);

GSL_FUN _gsl_matrix_long_double_view
gsl_matrix_long_double_view_array_with_tda (long double * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

GSL_FUN _gsl_matrix_long_double_view
gsl_matrix_long_double_view_vector (gsl_vector_long_double * v,
                              const size_t n1,
                              const size_t n2);

GSL_FUN _gsl_matrix_long_double_view
gsl_matrix_long_double_view_vector_with_tda (gsl_vector_long_double * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

GSL_FUN _gsl_matrix_long_double_const_view
gsl_matrix_long_double_const_submatrix (const gsl_matrix_long_double * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_long_double_const_view
gsl_matrix_long_double_const_row (const gsl_matrix_long_double * m,
                            const size_t i);

GSL_FUN _gsl_vector_long_double_const_view
gsl_matrix_long_double_const_column (const gsl_matrix_long_double * m,
                               const size_t j);

GSL_FUN _gsl_vector_long_double_const_view
gsl_matrix_long_double_const_diagonal (const gsl_matrix_long_double * m);

GSL_FUN _gsl_vector_long_double_const_view
gsl_matrix_long_double_const_subdiagonal (const gsl_matrix_long_double * m,
                                    const size_t k);

GSL_FUN _gsl_vector_long_double_const_view
gsl_matrix_long_double_const_superdiagonal (const gsl_matrix_long_double * m,
                                      const size_t k);

GSL_FUN _gsl_vector_long_double_const_view
gsl_matrix_long_double_const_subrow (const gsl_matrix_long_double * m, const size_t i,
                               const size_t offset, const size_t n);

GSL_FUN _gsl_vector_long_double_const_view
gsl_matrix_long_double_const_subcolumn (const gsl_matrix_long_double * m, const size_t j,
                                  const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_long_double_const_view
gsl_matrix_long_double_const_view_array (const long double * base,
                                   const size_t n1,
                                   const size_t n2);

GSL_FUN _gsl_matrix_long_double_const_view
gsl_matrix_long_double_const_view_array_with_tda (const long double * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

GSL_FUN _gsl_matrix_long_double_const_view
gsl_matrix_long_double_const_view_vector (const gsl_vector_long_double * v,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN _gsl_matrix_long_double_const_view
gsl_matrix_long_double_const_view_vector_with_tda (const gsl_vector_long_double * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

GSL_FUN void gsl_matrix_long_double_set_zero (gsl_matrix_long_double * m);
GSL_FUN void gsl_matrix_long_double_set_identity (gsl_matrix_long_double * m);
GSL_FUN void gsl_matrix_long_double_set_all (gsl_matrix_long_double * m, long double x);

GSL_FUN int gsl_matrix_long_double_fread (FILE * stream, gsl_matrix_long_double * m) ;
GSL_FUN int gsl_matrix_long_double_fwrite (FILE * stream, const gsl_matrix_long_double * m) ;
GSL_FUN int gsl_matrix_long_double_fscanf (FILE * stream, gsl_matrix_long_double * m);
GSL_FUN int gsl_matrix_long_double_fprintf (FILE * stream, const gsl_matrix_long_double * m, const char * format);

GSL_FUN int gsl_matrix_long_double_memcpy(gsl_matrix_long_double * dest, const gsl_matrix_long_double * src);
GSL_FUN int gsl_matrix_long_double_swap(gsl_matrix_long_double * m1, gsl_matrix_long_double * m2);
GSL_FUN int gsl_matrix_long_double_tricpy(CBLAS_UPLO_t Uplo, CBLAS_DIAG_t Diag, gsl_matrix_long_double * dest, const gsl_matrix_long_double * src);

GSL_FUN int gsl_matrix_long_double_swap_rows(gsl_matrix_long_double * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_long_double_swap_columns(gsl_matrix_long_double * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_long_double_swap_rowcol(gsl_matrix_long_double * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_long_double_transpose (gsl_matrix_long_double * m);
GSL_FUN int gsl_matrix_long_double_transpose_memcpy (gsl_matrix_long_double * dest, const gsl_matrix_long_double * src);
GSL_FUN int gsl_matrix_long_double_transpose_tricpy (CBLAS_UPLO_t Uplo_src, CBLAS_DIAG_t Diag, gsl_matrix_long_double * dest, const gsl_matrix_long_double * src);

GSL_FUN long double gsl_matrix_long_double_max (const gsl_matrix_long_double * m);
GSL_FUN long double gsl_matrix_long_double_min (const gsl_matrix_long_double * m);
GSL_FUN void gsl_matrix_long_double_minmax (const gsl_matrix_long_double * m, long double * min_out, long double * max_out);

GSL_FUN void gsl_matrix_long_double_max_index (const gsl_matrix_long_double * m, size_t * imax, size_t *jmax);
GSL_FUN void gsl_matrix_long_double_min_index (const gsl_matrix_long_double * m, size_t * imin, size_t *jmin);
GSL_FUN void gsl_matrix_long_double_minmax_index (const gsl_matrix_long_double * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);

GSL_FUN int gsl_matrix_long_double_equal (const gsl_matrix_long_double * a, const gsl_matrix_long_double * b);

GSL_FUN int gsl_matrix_long_double_isnull (const gsl_matrix_long_double * m);
GSL_FUN int gsl_matrix_long_double_ispos (const gsl_matrix_long_double * m);
GSL_FUN int gsl_matrix_long_double_isneg (const gsl_matrix_long_double * m);
GSL_FUN int gsl_matrix_long_double_isnonneg (const gsl_matrix_long_double * m);

GSL_FUN int gsl_matrix_long_double_add (gsl_matrix_long_double * a, const gsl_matrix_long_double * b);
GSL_FUN int gsl_matrix_long_double_sub (gsl_matrix_long_double * a, const gsl_matrix_long_double * b);
GSL_FUN int gsl_matrix_long_double_mul_elements (gsl_matrix_long_double * a, const gsl_matrix_long_double * b);
GSL_FUN int gsl_matrix_long_double_div_elements (gsl_matrix_long_double * a, const gsl_matrix_long_double * b);
GSL_FUN int gsl_matrix_long_double_scale (gsl_matrix_long_double * a, const double x);
GSL_FUN int gsl_matrix_long_double_scale_rows (gsl_matrix_long_double * a, const gsl_vector_long_double * x);
GSL_FUN int gsl_matrix_long_double_scale_columns (gsl_matrix_long_double * a, const gsl_vector_long_double * x);
GSL_FUN int gsl_matrix_long_double_add_constant (gsl_matrix_long_double * a, const double x);
GSL_FUN int gsl_matrix_long_double_add_diagonal (gsl_matrix_long_double * a, const double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
GSL_FUN int gsl_matrix_long_double_get_row(gsl_vector_long_double * v, const gsl_matrix_long_double * m, const size_t i);
GSL_FUN int gsl_matrix_long_double_get_col(gsl_vector_long_double * v, const gsl_matrix_long_double * m, const size_t j);
GSL_FUN int gsl_matrix_long_double_set_row(gsl_matrix_long_double * m, const size_t i, const gsl_vector_long_double * v);
GSL_FUN int gsl_matrix_long_double_set_col(gsl_matrix_long_double * m, const size_t j, const gsl_vector_long_double * v);
/***********************************************************************/

/* inline functions if you are using GCC */

GSL_FUN INLINE_DECL long double   gsl_matrix_long_double_get(const gsl_matrix_long_double * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL void    gsl_matrix_long_double_set(gsl_matrix_long_double * m, const size_t i, const size_t j, const long double x);
GSL_FUN INLINE_DECL long double * gsl_matrix_long_double_ptr(gsl_matrix_long_double * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL const long double * gsl_matrix_long_double_const_ptr(const gsl_matrix_long_double * m, const size_t i, const size_t j);

#ifdef HAVE_INLINE
INLINE_FUN
long double
gsl_matrix_long_double_get(const gsl_matrix_long_double * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_VAL("first index out of range", GSL_EINVAL, 0) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_VAL("second index out of range", GSL_EINVAL, 0) ;
        }
    }
#endif
  return m->data[i * m->tda + j] ;
}

INLINE_FUN
void
gsl_matrix_long_double_set(gsl_matrix_long_double * m, const size_t i, const size_t j, const long double x)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_VOID("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_VOID("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  m->data[i * m->tda + j] = x ;
}

INLINE_FUN
long double *
gsl_matrix_long_double_ptr(gsl_matrix_long_double * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  return (long double *) (m->data + (i * m->tda + j)) ;
}

INLINE_FUN
const long double *
gsl_matrix_long_double_const_ptr(const gsl_matrix_long_double * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  return (const long double *) (m->data + (i * m->tda + j)) ;
}

#endif

__END_DECLS

#endif /* __GSL_MATRIX_LONG_DOUBLE_H__ */


#ifndef _SPC_SPC_H

#define _SPC_SPC_H

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <string.h>

#include <gsl/gsl_nan.h>
#include <gsl/gsl_sys.h>

#include "aXe_grism.h"
#include "aXe_utils.h"
#include "fitsio.h"

#define SPCTOL 1.0e-5

// interpolation type used for the
// response function
#define RESP_FUNC_INTERP_TYPE gsl_interp_linear

extern spectrum *
allocate_spectrum (const int numbin);

extern void
free_spectrum (spectrum * const spec);

extern void
fprintf_spectrum (FILE * output, const spectrum * const sp);

extern spectrum *
subtract_spectra (spectrum * a, spectrum * b);

extern int
get_ID_index_to_SPC (char filename[], char ID[]);

extern void
add_ID_index_to_SPC (char filename[], char ID[], int hdunum);

extern int
add_ID_to_SPC (char filename[], int N, char ID[]);

extern int
find_ID_in_SPC (char filename[], char ID[]);

extern void
create_SPC (char filename[], int overwrite);

extern int
get_SPC_colnum (fitsfile * input, char colname[]);

extern void
add_spectra_to_SPC (char filename[], spectrum * obj_spec,
		    spectrum * bck_spec, spectrum * sobj_spec,
		    int aperID, int beamID);

extern void
add_data_to_SPC (spectrum * spec, char countcolname[],
		 char errorcolname[], char weightcolname[], char ID[],
		 char filename[], int hdunum, long N);

extern spectrum *
trim_spectrum (spectrum * spc);

extern spectrum *
empty_counts_spectrum_copy (spectrum * a);

extern void
add_ID_to_SPC_opened (fitsfile *output, int N, char ID[]);

extern void
add_spectra_to_SPC_opened (fitsfile *input, spectrum * obj_spec,
			   spectrum * bck_spec, spectrum * sobj_spec,
			   int aperID, int beamID);

extern void
add_data_to_SPC_opened (spectrum * spec, char countcolname[],
			char errorcolname[], char weightcolname[],
			char ID[], fitsfile *input, long N);

extern fitsfile *
create_SPC_opened (char filename[], int overwrite);

#endif


/*
Copyright 2010-2011, D. E. Shaw Research.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions, and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions, and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

* Neither the name of D. E. Shaw Research nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __r123_gslmicrorng_dot_h__
#define __r123_gslmicrorng_dot_h__

#include <gsl/gsl_rng.h>
#include <string.h>

/**   The macro: GSL_MICRORNG(NAME, CBRNGNAME) is the GSL
   analog analog of the C++ r123::MicroURNG template.  It declares a gsl_rng
   type named gsl_rng_NAME which uses the underlying CBRNGNAME
   and can be invoked a limited number of times between calls to NAME_reset.

   When the underlying CBRNG's \c ctr_t is an \ref arrayNxW "r123arrayNxW",
   and the gsl_rng_NAME may called up to \c N*2^32 times
   between calls to \c NAME_reset.

   \c NAME_reset takes a gsl_rng_NAME type, a counter and a key as arguments.
   It restarts the micro-rng with a new base counter and key.

   Note that you must call NAME_reset before the first use
   of a gsl_rng.  NAME_reset is not called automatically by
   gsl_rng_alloc().

   @code
   #include <Random123/threefry.h>
   #include <Random123/gsl_microrng.h> // this file
   GSL_MICRORNG(microcbrng, threefry4x64, 20)	// creates gsl_rng_microcbrng

   int main(int argc, char** argv) {
	gsl_rng *r = gsl_rng_alloc(gsl_rng_microcbrng);
	threefry4x64_ctr_t c = {{}};
	threefry4x64_key_t k = {{}};

	for (...) {
	    c.v[0] = ??; //  some application variable
	    microcbrng_reset(r, c, k);
	    for (...) {
		// gaussian calls r several times.  It is safe for
		// r to be used upto 2^20 times in this loop
		something[i] = gsl_ran_gaussian(r, 1.5);
	    }
	}
   }
   @endcode

*/

#define GSL_MICRORNG(NAME, CBRNGNAME)                                   \
const gsl_rng_type *gsl_rng_##NAME;                                     \
                                                                        \
typedef struct{                                                         \
    CBRNGNAME##_ctr_t ctr;                                              \
    CBRNGNAME##_ctr_t r;                                                \
    CBRNGNAME##_key_t key;                                              \
    R123_ULONG_LONG n;                                                  \
    int elem;                                                           \
} NAME##_state;                                                         \
                                                                        \
static unsigned long int NAME##_get(void *vstate){                      \
    NAME##_state *st = (NAME##_state *)vstate;                          \
    const int N=sizeof(st->ctr.v)/sizeof(st->ctr.v[0]);                 \
    if( st->elem == 0 ){                                                \
        CBRNGNAME##_ctr_t c = st->ctr;                                  \
        c.v[N-1] |= st->n<<(R123_W(CBRNGNAME##_ctr_t)-32);              \
        st->n++;                                                        \
        st->r = CBRNGNAME(c, st->key);                                  \
        st->elem = N;                                                   \
    }                                                                   \
    return 0xffffffff & st->r.v[--st->elem];                            \
}                                                                       \
                                                                        \
static double                                                           \
NAME##_get_double (void * vstate)                                       \
{                                                                       \
    return NAME##_get (vstate)/4294967296.;                             \
}                                                                       \
                                                                        \
static void NAME##_set(void *vstate, unsigned long int s){              \
    NAME##_state *st = (NAME##_state *)vstate;                          \
    st->elem = 0;                                                       \
    st->n = ~0; /* will abort if _reset is not called */                \
}                                                                       \
                                                                        \
static const gsl_rng_type NAME##_type = {                               \
    #NAME,                                                              \
    0xffffffffUL,                                                       \
    0,                                                                  \
    sizeof(NAME##_state),                                               \
    &NAME##_set,                                                        \
    &NAME##_get,                                                        \
    &NAME##_get_double                                                  \
};                                                                      \
                                                                        \
R123_STATIC_INLINE void NAME##_reset(const gsl_rng* gr, CBRNGNAME##_ctr_t c, CBRNGNAME##_key_t k) { \
    NAME##_state* state = (NAME##_state *)gr->state;                    \
    state->ctr = c;                                                     \
    state->key = k;                                                     \
    state->n = 0;                                                       \
    state->elem = 0;                                                    \
}                                                                       \
                                                                        \
const gsl_rng_type *gsl_rng_##NAME = &NAME##_type

#endif


#include <stdlib.h>
#include <gsl/vector/gsl_vector.h>
#include <gsl/gsl_errno.h>

#define BASE_DOUBLE
#include <gsl/templates_on.h>
#include <gsl/vector/prop_source.c>
#include <gsl/templates_off.h>
#undef BASE_DOUBLE


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nlopt.h>

// System definition and dimension

int mysys = 0;
int dim = 3;

// Semi-empirical method and parameter variation range

char * method = "pm7";
double pdev = 0.7;

// Algorithm parameters

nlopt_algorithm global_alg = NLOPT_GD_MLSL_LDS;
nlopt_algorithm local_alg = NLOPT_LN_BOBYQA;
int maxeval = 3;
double minrms = 0.01;
double tol = 0.001;

//Define here  your system's input for MOPAC

void gen_srpgeo(int ndat, double ** data) {
	long length;
	char * buffer = 0;
	char procedure[0x100];

	switch (mysys) {
	case 0: {
		// Ar/C10H8
		FILE * fp = fopen("./naf_geo.xyz", "r");
		if (!fp)
			exit(EXIT_FAILURE);
		fseek(fp, 0L, SEEK_END);
		length = ftell(fp);
		rewind(fp);
		buffer = (char *) malloc((length+1) * sizeof(char));
		if (buffer) {
			fread(buffer, sizeof(char), length, fp);
		}
		fclose(fp);

		for (int i = 0; i < ndat; ++i) {
			char buf[0x100];
			snprintf(buf, sizeof(buf), "./inp_semp/geo_%d.mop", i);
			FILE * fq = fopen(buf, "w");
			strcpy(procedure, method);
			strcpy(procedure, " charge=0 1scf EXTERNAL=mopac_parameter\n");
			fprintf(fq, "%s", procedure);
			fprintf(fq, "Dumb title rule\n");
			fprintf(fq, " \n");
			fprintf(fq, "Ar %f %f %f\n", data[i][0], data[i][1], data[i][2]);
			fputs(buffer, fq);
			fprintf(fq, " ");
			fclose(fq);
		}
		free(buffer);
	}

	default:
		break;
	}
}


#ifndef mooney_rivlin_h
#define mooney_rivlin_h

#include <petsc.h>
#include "../include/structs.h"

#ifndef PHYSICS_STRUCT_MR
#define PHYSICS_STRUCT_MR
typedef struct Physics_MR_ *Physics_MR;
struct Physics_MR_ {
  // Material properties for MR
  CeedScalar mu_1;
  CeedScalar mu_2;
  CeedScalar lambda;
};
#endif // PHYSICS_STRUCT_MR

// Create context object
PetscErrorCode PhysicsContext_MR(MPI_Comm comm, Ceed ceed, Units *units,
                                 CeedQFunctionContext *ctx);
PetscErrorCode PhysicsSmootherContext_MR(MPI_Comm comm, Ceed ceed,
    CeedQFunctionContext ctx, CeedQFunctionContext *ctx_smoother);

// Process physics options - Mooney-Rivlin
PetscErrorCode ProcessPhysics_MR(MPI_Comm comm, Physics_MR phys, Units units);

#endif // mooney_rivlin_h


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "parmt_postProcess.h"
#ifdef PARMT_USE_INTEL
#include <mkl_cblas.h>
#else
#include <cblas.h>
#endif
#include "compearth.h"
#include "iscl/array/array.h"
#include "iscl/memory/memory.h"
#include "iscl/os/os.h"

static void getBaseAndExp(const double val, double *base, int *exp);
static void setFillColor(const int i, const int iopt, char color[32]);

/*!
 * @brief Writes the global station distribution of stations, the
 *        station names, the epicenter or moment tensor, and, if
 *        desired, some indication of station polarity.
 */
int postmt_gmtHelper_writeGlobalMap(
    struct globalMapOpts_struct globalMap,
    const int nobs, const struct sacData_struct *data)
{
    const char *fcnm = "postmt_gmtHelper_writeGlobalMap\0";
    FILE *ofl;
    char *dirName, line[256], cpick[8];
    int *pol, i, ierr, l, nw, nwd, nwu;
    size_t lenos;
    const char *forwardSlash = "/";
    const int nTimeVars = 11;
    const enum sacHeader_enum timeVarNames[11]
       = {SAC_CHAR_KA,
          SAC_CHAR_KT0, SAC_CHAR_KT1, SAC_CHAR_KT2, SAC_CHAR_KT3,
          SAC_CHAR_KT4, SAC_CHAR_KT5, SAC_CHAR_KT6, SAC_CHAR_KT7,
          SAC_CHAR_KT8, SAC_CHAR_KT9};

    dirName = os_dirname(globalMap.outputScript, &ierr);
    if (!os_path_isdir(dirName))
    {
        ierr = os_makedirs(dirName);
        if (ierr != 0)
        {
            printf("%s: Failed to make output directory: %s\n", fcnm, dirName);
            return -1;
        }
    }
    memory_free8c(&dirName);

    ofl = fopen(globalMap.outputScript, "w");
    fprintf(ofl, "#!/bin/bash\n");
    fprintf(ofl, "outps=%s\n", globalMap.psFile);
    fprintf(ofl, "olat=%f\n", globalMap.evla);
    fprintf(ofl, "olon=%f\n", globalMap.evlo);
    fprintf(ofl, "J=-JH${olon}%s6i\n", forwardSlash);
    fprintf(ofl, "R=-Rg\n");
    fprintf(ofl, "gmt pscoast $J $R -B0g30 -Di -Ggray -P -K > ${outps}\n");
    fprintf(ofl, "ts=0.15i\n");

    fprintf(ofl, "# Draw great circle arcs between source and receivers\n");
    fprintf(ofl, "gmt psxy $J $R -W1p -O -K << EOF >> ${outps}\n");
    for (i=0; i<nobs; i++)
    {
        fprintf(ofl, "%8.3f %8.3f\n", data[i].header.stlo, data[i].header.stla);
        fprintf(ofl, "%8.3f %8.3f\n", globalMap.evlo, globalMap.evla);
        if (i < nobs - 1){fprintf(ofl, "\n");}
    }
    fprintf(ofl, "EOF\n");

    fprintf(ofl, "# Plot the moment tensor\n");
    postmt_gmtHelper_makePsmecaLine(globalMap.basis, globalMap.mts,
                                    globalMap.evla, globalMap.evlo,
                                    globalMap.evdp, "Optimum\0", line);
    if (globalMap.lwantMT)
    {
        fprintf(ofl, "gmt psmeca $J $R -Sm0.15i -M -N -Gblue -W0.5p,black -O -K << EOF >> ${outps}\n");
        fprintf(ofl, "%s", line);
        fprintf(ofl, "EOF\n");
    }
    else
    {
        fprintf(ofl, "# Plot the epicenter\n");
        fprintf(ofl, "gmt psxy $J $R -Sa${ts} -Gblue -Wblack -O -K << EOF >> ${outps}\n");
        fprintf(ofl, "%8.3f %8.3f\n", globalMap.evlo, globalMap.evla);
        fprintf(ofl, "EOF\n");
    }

    if (!globalMap.lwantPolarity)
    {
        fprintf(ofl, "# Plot the stations\n");
        fprintf(ofl, "gmt psxy $J $R -St${ts} -Gred -Wblack -O -K << EOF >> ${outps}\n");
        for (i=0; i<nobs; i++)
        {
            fprintf(ofl, "%8.3f %8.3f %s\n", data[i].header.stlo,
                    data[i].header.stla, data[i].header.kstnm);
        }
        fprintf(ofl, "EOF\n");
    }
    else
    {
        // Get the polarities
        nw = 0;
        nwd = 0;
        nwu = 0;
        pol = (int *) calloc((size_t) nobs, sizeof(int));
        for (i=0; i<nobs; i++)
        {
            memset(cpick, 0, 8*sizeof(char));
            for (l=0; l<nTimeVars; l++)
            {
                ierr = sacio_getCharacterHeader(timeVarNames[l],
                                                data[i].header, cpick);
                if (ierr == 0){break;}
            }
            lenos = strlen(cpick);
            if (lenos > 0)
            {
                if (cpick[lenos-1] == '+')
                {
                    nwu = nwu + 1;
                    pol[i] = 1;
                }
                else if (cpick[lenos-1] == '-')
                {
                    nwd = nwd + 1;
                    pol[i] =-1;
                }
                else
                {
                    nw = nw + 1;
                }
            }
            else
            {
                nw = nw + 1;
            }
        }
        // Write the unknowns
        if (nw > 0)
        {
            fprintf(ofl, "# Plot the indeterminant stations\n");
            fprintf(ofl, "gmt psxy $J $R -Ss${ts} -Gred -Wblack -O -K << EOF >> ${outps}\n");
            for (i=0; i<nobs; i++)
            {
                if (pol[i] == 0)
                {
                    fprintf(ofl, "%8.3f %8.3f %s\n", data[i].header.stlo,
                            data[i].header.stla, data[i].header.kstnm);
                }
            }
            fprintf(ofl, "EOF\n");
        }
        // Write the ups
        if (nwu > 0)
        {
            fprintf(ofl, "# Plot the upward stations\n");
            fprintf(ofl, "gmt psxy $J $R -St${ts} -Gred -Wblack -O -K << EOF >> ${outps}\n");
            for (i=0; i<nobs; i++)
            {
                if (pol[i] == 1)
                {
                    fprintf(ofl, "%8.3f %8.3f %s\n", data[i].header.stlo,
                            data[i].header.stla, data[i].header.kstnm);
                }
            }
            fprintf(ofl, "EOF\n");
        }
        // Write the downs
        if (nwd > 0)
        {
            fprintf(ofl, "# Plot the down stations\n");
            fprintf(ofl, "gmt psxy $J $R -Si${ts} -Gred -Wblack -O -K << EOF >> ${outps}\n");
            for (i=0; i<nobs; i++)
            {
                if (pol[i] ==-1)
                {
                    fprintf(ofl, "%8.3f %8.3f %s\n", data[i].header.stlo,
                            data[i].header.stla, data[i].header.kstnm);
                }
            }
            fprintf(ofl, "EOF\n");
        }
        free(pol);
    }

    fprintf(ofl, "# Plot the station names\n");
    fprintf(ofl, "gmt pstext $J $R -F+f8p+a0+jCT -D0%s-4p -O << EOF >> ${outps}\n",
            forwardSlash);
    for (i=0; i<nobs; i++)
    {
        fprintf(ofl, "%8.3f %8.3f %s\n", data[i].header.stlo,
                data[i].header.stla, data[i].header.kstnm);
    }
    fprintf(ofl, "EOF\n");
    fprintf(ofl, "gmt psconvert -A -Tj ${outps}\n");
    fprintf(ofl, "rm ${outps}\n");
    fclose(ofl);
    chmod(globalMap.outputScript, 0755);
    return 0;
}
//============================================================================//
int postmt_gmtHelper_writeThetaBoxes(const bool lappend, const bool lclose,
                                     const char *outputScript,
                                     const char *psFile,
                                     const int nt,
                                     const int ithetaOpt,
                                     const double *__restrict__ thetas,
                                     const double *__restrict__ thetaHist)
{
    FILE *ofl;
    char color[32], app[8], more[8], shift[8];
    double *cumTheta, *h, hAvg, thetaAvg, tmax;
    int i, ierr;
    const bool lwritePrior = true;
    tmax = array_max64f(nt, thetaHist, &ierr);
    // Compute h
    h = memory_calloc64f(nt);
    compearth_theta2h(nt, thetas, h);
    thetaAvg = -30.0;
    memset(app, 0, 8*sizeof(char));
    memset(more, 0, 8*sizeof(char));
    memset(shift, 0, 8*sizeof(char));
    if (!lappend)
    {
        ofl = fopen(outputScript, "w");
        fprintf(ofl, "#!/bin/bash\n");
        /*
        fprintf(ofl, "gmt gmtset FONT_LABEL 12p\n");
        fprintf(ofl, "gmt gmtset MAP_LABEL_OFFSET 0.1c\n");
        */
        fprintf(ofl, "parms=\"--FONT_LABEL=10p --MAP_LABEL_OFFSET=0.1c --PROJ_LENGTH_UNIT=cm\"\n");
        fprintf(ofl, "psfl=%s\n", psFile);
    }
    else
    {
        ofl = fopen(outputScript, "a");
        strcpy(app, "-O\0");
        strcpy(more, ">\0");
        strcpy(shift, "-Y4.0\0");
    }
    fprintf(ofl,
/*
            "gmt psbasemap -JX5i/1i %s -R0/90/0/%.2f -Bg10a10:\"Dips (deg)\":/a%.2f:\"Likelihood\":WSn -P %s -K >%s ${psfl}\n",
*/
            "gmt psbasemap -JX5i/1i %s -R0/90/0/%.2f -Bpxg10a10+l:\"Dips (deg)\" -Bpya%.2f+l:\"Likelihood\" -BWSnn -P %s -K ${parms} >%s ${psfl}\n",
            shift, tmax*1.1, tmax*0.2, app, more);
    setFillColor(0, ithetaOpt, color);
    if (nt > 1)
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
    }
    else
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
    }
    fprintf(ofl, "%f %f\n", 0.0, 0.0);
    fprintf(ofl, "%f %f\n", 0.0, thetaHist[0]);
    for (i=0; i<nt-1; i++)
    {
        hAvg = 0.5*(h[i] + h[i+1]);
        compearth_h2theta(1, &hAvg, &thetaAvg);
        fprintf(ofl, "%f %f\n", thetaAvg*180.0/M_PI, thetaHist[i]);
        fprintf(ofl, "%f %f\n", thetaAvg*180.0/M_PI, 0.0);
        fprintf(ofl, "EOF\n");
        setFillColor(i+1, ithetaOpt, color);
        if (i < nt - 2 || lwritePrior)
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
        }
        else
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
        }
        fprintf(ofl, "%f %f\n", thetaAvg*180.0/M_PI, 0.0);
        fprintf(ofl, "%f %f\n", thetaAvg*180.0/M_PI, thetaHist[i+1]);
    }
    fprintf(ofl, "%f %f\n", 90.0, thetaHist[nt-1]);
    fprintf(ofl, "%f %f\n", 90.0, 0.0);
    fprintf(ofl, "EOF\n");
    // Write the prior distribution
    if (lwritePrior)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,black -O -K << EOF >> ${psfl}\n");
        fprintf(ofl, "%f %f\n", 00.0, 1.0/(double) nt);
        fprintf(ofl, "%f %f\n", 90.0, 1.0/(double) nt);
        fprintf(ofl, "EOF\n");
    }
    // Write the CDF
/*
    fprintf(ofl, "gmt psbasemap -R0/90/0/1.05 -J -Bp0.2/a0.2:\"CDF\":E -O -K >> ${psfl}\n");
*/
    fprintf(ofl, "gmt psbasemap -R0/90/0/1.05 -J -Bpx0.2 -Bpya0.2+l\"CDF\" -BE -O -K ${parms} >> ${psfl}\n");
    cumTheta = array_cumsum64f(nt, thetaHist, &ierr);
    if (lclose)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O << EOF >> ${psfl}\n");
    }
    else
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O -K << EOF >> ${psfl}\n");
    }
    for (i=0; i<nt; i++)
    {
        fprintf(ofl, "%f %f\n", thetas[i]*180/M_PI, cumTheta[i]);
    }
    fprintf(ofl, "EOF\n");
    if (lclose)
    {
        //fprintf(ofl, "gmt psconvert -A -Tj ${psfl}\n");
        //fprintf(ofl, "rm ${psfl}\n");
        fprintf(ofl, "gmt psconvert -A -Tf ${psfl}\n");
        fprintf(ofl, "/bin/rm ${psfl}\n");
    }
    memory_free64f(&cumTheta);
    memory_free64f(&h);
    fclose(ofl);
    chmod(outputScript, 0755);
    return 0;
}
//============================================================================//
int postmt_gmtHelper_writeSigmaBoxes(const bool lappend, const bool lclose,
                                     const char *outputScript,
                                     const char *psFile,
                                     const int ns,
                                     const int isigmaOpt,
                                     const double *__restrict__ sigmas,
                                     const double *__restrict__ sigmaHist)
{
    FILE *ofl;
    char color[32], app[8], more[8], shift[8];
    double *cumSigma, ds, smax;
    int i, ierr;
    const bool lwritePrior = true;
    smax = array_max64f(ns, sigmaHist, &ierr);
    // Take averages
    ds = 0.0;
    memset(app, 0, 8*sizeof(char));
    memset(more, 0, 8*sizeof(char));
    memset(shift, 0, 8*sizeof(char));
    if (!lappend)
    {
        ofl = fopen(outputScript, "w");
        fprintf(ofl, "#!/bin/bash\n");
        /*
        fprintf(ofl, "gmt gmtset FONT_LABEL 12p\n");
        fprintf(ofl, "gmt gmtset MAP_LABEL_OFFSET 0.1c\n");
        */
        fprintf(ofl, "parms=\"--FONT_LABEL=10p --MAP_LABEL_OFFSET=0.1c --PROJ_LENGTH_UNIT=cm\"\n");
        fprintf(ofl, "psfl=%s\n", psFile);
    }
    else
    {
        ofl = fopen(outputScript, "a");
        strcpy(app, "-O\0");
        strcpy(more, ">\0");
        strcpy(shift, "-Y4.0\0");
    }
    fprintf(ofl,
/*
           "gmt psbasemap -JX5i/1i %s -R-90/90/0/%.2f -Bg15a15:\"Slips (deg)\":/a%.2f:\"Likelihood\":WSn -P %s -K >%s ${psfl}\n",
*/
            "gmt psbasemap -JX5i/1i %s -R-90/90/0/%.2f -Bpxg15a15+l\"Slips (deg)\" -Bpya%.2f+l\"Likelihood\" -BWSn -P %s -K ${parms} >%s ${psfl}\n",
            shift, smax*1.1, smax*0.2, app, more);
    setFillColor(0, isigmaOpt, color);
    if (ns > 1)
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
       ds = (sigmas[1] - sigmas[0])*180.0/M_PI;
    }
    else
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
    }
    fprintf(ofl, "%.2f %f\n", -90.0, 0.0);
    fprintf(ofl, "%.2f %f\n", -90.0, sigmaHist[0]);
    for (i=0; i<ns-1; i++)
    {
        fprintf(ofl, "%.2f %f\n", -90.0 + (double) (i+1)*ds, sigmaHist[i]);
        fprintf(ofl, "%.2f %f\n", -90.0 + (double) (i+1)*ds, 0.0);
        fprintf(ofl, "EOF\n");
        setFillColor(i+1, isigmaOpt, color);
        if (i < ns - 2 || lwritePrior)
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
        }
        else
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
        }
        fprintf(ofl, "%.2f %f\n", -90.0 + (double) (i+1)*ds, 0.0);
        fprintf(ofl, "%.2f %f\n", -90.0 + (double) (i+1)*ds, sigmaHist[i+1]);
    }
    fprintf(ofl, "%.2f %f\n", 90.0, sigmaHist[ns-1]);
    fprintf(ofl, "%.2f %f\n", 90.0, 0.0);
    fprintf(ofl, "EOF\n");
    // Write the prior distribution
    if (lwritePrior)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,black -O -K << EOF >> ${psfl}\n");
        fprintf(ofl, "%f %f\n",-90.0, 1.0/(double) ns);
        fprintf(ofl, "%f %f\n", 90.0, 1.0/(double) ns);
        fprintf(ofl, "EOF\n");
    }
    // Write the CDF
/*
    fprintf(ofl, "gmt psbasemap -R-90/90/0/1.05 -J -Bp0.2/a0.2:\"CDF\":E -O -K >> ${psfl}\n");
*/
    fprintf(ofl, "gmt psbasemap -R-90/90/0/1.05 -J -Bpx0.2 -Bpya0.2+l\"CDF\" -BE -O -K ${parms} >> ${psfl}\n");
    cumSigma = array_cumsum64f(ns, sigmaHist, &ierr);
    if (lclose)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O << EOF >> ${psfl}\n");
    }
    else
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O -K << EOF >> ${psfl}\n");
    }
    for (i=0; i<ns; i++)
    {
        fprintf(ofl, "%f %f\n", sigmas[i]*180/M_PI, cumSigma[i]);
    }
    fprintf(ofl, "EOF\n");
    if (lclose)
    {
        //fprintf(ofl, "gmt psconvert -A -Tj ${psfl}\n");
        //fprintf(ofl, "rm ${psfl}\n");
        fprintf(ofl, "gmt psconvert -A -Tf ${psfl}\n");
        fprintf(ofl, "/bin/rm ${psfl}\n");
    }
    memory_free64f(&cumSigma);
    fclose(ofl);
    chmod(outputScript, 0755);
    return 0;
}

//============================================================================//
int postmt_gmtHelper_writeKappaBoxes(const bool lappend, const bool lclose,
                                     const char *outputScript,
                                     const char *psFile,
                                     const int nk,
                                     const int kappaOpt,
                                     const double *__restrict__ kappas,
                                     const double *__restrict__ kappaHist)
{
    FILE *ofl;
    char color[32], app[8], more[8], shift[8];
    double *cumKappa, dk, kmax;
    int i, ierr;
    const bool lwritePrior = true;
    kmax = array_max64f(nk, kappaHist, &ierr);
    // Take averages
    dk = 0.0;
    memset(app, 0, 8*sizeof(char));
    memset(more, 0, 8*sizeof(char));
    memset(shift, 0, 8*sizeof(char));
    if (!lappend)
    {
        ofl = fopen(outputScript, "w");
        fprintf(ofl, "#!/bin/bash\n");
        /*
        fprintf(ofl, "gmt gmtset FONT_LABEL 12p\n");
        fprintf(ofl, "gmt gmtset MAP_LABEL_OFFSET 0.1c\n");
        */
        fprintf(ofl, "parms=\"--FONT_LABEL=10p --MAP_LABEL_OFFSET=0.1c --PROJ_LENGTH_UNIT=cm\"\n");
        fprintf(ofl, "psfl=%s\n", psFile);
    }
    else
    {
        ofl = fopen(outputScript, "a");
        strcpy(app, "-O\0");
        strcpy(more, ">\0");
        strcpy(shift, "-Y4.0\0");
    }
    fprintf(ofl,
/*
            "gmt psbasemap -JX5i/1i %s -R0/360/0/%.2f -Bg30a30:\"Strike (deg)\":/a%.2f:\"Likelihood\":WSn -P %s -K >%s ${psfl}\n",
*/
            "gmt psbasemap -JX5i/1i %s -R0/360/0/%.2f -Bpxg30a30+l\"Strike (deg)\" -Bpya%.2f+l\"Likelihood\" -BWSn -P %s -K ${parms} >%s ${psfl}\n",
            shift, kmax*1.1, kmax*0.2, app, more);
    setFillColor(0, kappaOpt, color);
    if (nk > 1)
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
       dk = (kappas[1] - kappas[0])*180.0/M_PI;
    }
    else
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
    }
    fprintf(ofl, "%.2f %f\n", 0.0, 0.0);
    fprintf(ofl, "%.2f %f\n", 0.0, kappaHist[0]);
    for (i=0; i<nk-1; i++)
    {
        fprintf(ofl, "%.2f %f\n", 0.0 + (double) (i+1)*dk, kappaHist[i]);
        fprintf(ofl, "%.2f %f\n", 0.0 + (double) (i+1)*dk, 0.0);
        fprintf(ofl, "EOF\n");
        setFillColor(i+1, kappaOpt, color);
        if (i < nk - 2 || lwritePrior)
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
        }
        else
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
        }
        fprintf(ofl, "%.2f %f\n", 0.0 + (double) (i+1)*dk, 0.0);
        fprintf(ofl, "%.2f %f\n", 0.0 + (double) (i+1)*dk, kappaHist[i+1]);
    }
    fprintf(ofl, "%.2f %f\n", 360.0, kappaHist[nk-1]);
    fprintf(ofl, "%.2f %f\n", 360.0, 0.0);
    fprintf(ofl, "EOF\n");
    // Write the prior distribution
    if (lwritePrior)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,black -O -K << EOF >> ${psfl}\n");
        fprintf(ofl, "%f %f\n", 0.0,   1.0/(double) nk);
        fprintf(ofl, "%f %f\n", 360.0, 1.0/(double) nk);
        fprintf(ofl, "EOF\n");
    }
    // Write the CDF
/*
    fprintf(ofl, "gmt psbasemap -R0/360/0/1.05 -J -Bp0.2/a0.2:\"CDF\":E -O -K >> ${psfl}\n");
*/
    fprintf(ofl, "gmt psbasemap -R0/360/0/1.05 -J -Bpx0.2 -Bpya0.2+l\"CDF\" -BE -O -K ${parms} >> ${psfl}\n");
    cumKappa = array_cumsum64f(nk, kappaHist, &ierr);
    if (lclose)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O << EOF >> ${psfl}\n");
    }
    else
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O -K << EOF >> ${psfl}\n");
    }
    for (i=0; i<nk; i++)
    {
        fprintf(ofl, "%f %f\n", kappas[i]*180.0/M_PI, cumKappa[i]);
    }
    fprintf(ofl, "EOF\n");
    if (lclose)
    {
        //fprintf(ofl, "gmt psconvert -A -Tj ${psfl}\n");
        //fprintf(ofl, "rm ${psfl}\n");
        fprintf(ofl, "gmt psconvert -A -Tf ${psfl}\n");
        fprintf(ofl, "/bin/rm ${psfl}\n");
    }
    memory_free64f(&cumKappa);
    fclose(ofl);
    chmod(outputScript, 0755);
    return 0;
}
//============================================================================//
int postmt_gmtHelper_writeDepthBoxes(const bool lappend, const bool lclose,
                                     const char *outputScript,
                                     const char *psFile,
                                     const int nd,
                                     const int idepOpt,
                                     const double *__restrict__ deps,
                                     const double *__restrict__ depHist)
{
    FILE *ofl;
    char color[32], app[8], more[8], shift[8];
    double *cumDep, dd, dmax, depMin, depMax;
    int i, ierr;
    const bool lwritePrior = true;
    // Compute moment magnitudes
    dmax = array_max64f(nd, depHist, &ierr);
    dd = 0.1;
    if (nd > 1){dd = deps[1] - deps[0];};
    depMin = fmax(0.0, deps[0]    - dd/2.0);
    depMax = fmax(0.0, deps[nd-1] + dd/2.0);
    memset(app, 0, 8*sizeof(char));
    memset(more, 0, 8*sizeof(char));
    memset(shift, 0, 8*sizeof(char));
    if (!lappend)
    {
        ofl = fopen(outputScript, "w");
        fprintf(ofl, "#!/bin/bash\n");
        /*
        fprintf(ofl, "gmt gmtset FONT_LABEL 12p\n");
        fprintf(ofl, "gmt gmtset MAP_LABEL_OFFSET 0.1c\n");
        */
        fprintf(ofl, "psfl=%s\n", psFile);
    }
    else
    {
        ofl = fopen(outputScript, "a");
        strcpy(app, "-O\0");
        strcpy(more, ">\0");
        strcpy(shift, "-Y4.0\0");
    }
    fprintf(ofl,
/*
            "gmt psbasemap -JX5i/1i %s -R%.1f/%.1f/0/%.2f -Bg%fa%f:\"Depths (km)\":/a%.2f:\"Likelihood\":WSn -P %s -K >%s ${psfl}\n",
*/
            "gmt psbasemap -JX5i/1i %s -R%.1f/%.1f/0/%.2f -Bpxg%fa%f+l\"Depths (km)\" -Bpya%.2f+l\"Likelihood\" -BWSn -P %s -K ${parms} >%s ${psfl}\n",
            shift, depMin, depMax, dmax*1.1, dd, (nd-1)*dd/5.0, dmax*0.2, app, more);
    setFillColor(0, idepOpt, color);
    if (nd > 1)
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
    }
    else
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
    }
    fprintf(ofl, "%.2f %f\n", depMin, 0.0);
    fprintf(ofl, "%.2f %f\n", depMin, depHist[0]);
    for (i=0; i<nd-1; i++)
    {
        fprintf(ofl, "%.2f %f\n", depMin + (double) (i+1)*dd, depHist[i]);
        fprintf(ofl, "%.2f %f\n", depMin + (double) (i+1)*dd, 0.0);
        fprintf(ofl, "EOF\n");
        setFillColor(i+1, idepOpt, color);
        if (i < nd - 2 || lwritePrior)
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
        }
        else
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
        }
        fprintf(ofl, "%.2f %f\n", depMin + (double) (i+1)*dd, 0.0);
        fprintf(ofl, "%.2f %f\n", depMin + (double) (i+1)*dd, depHist[i+1]);
    }
    fprintf(ofl, "%.2f %f\n", depMax, depHist[nd-1]);
    fprintf(ofl, "%.2f %f\n", depMax, 0.0);
    fprintf(ofl, "EOF\n");
    // Write the prior distribution
    if (lwritePrior)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,black -O -K << EOF >> ${psfl}\n");
        fprintf(ofl, "%f %f\n", depMin, 1.0/(double) nd);
        fprintf(ofl, "%f %f\n", depMax, 1.0/(double) nd);
        fprintf(ofl, "EOF\n");
    }
    // Write the CDF
/*
    fprintf(ofl, "gmt psbasemap -R%f/%f/0/1.05 -J -Bp0.2/a0.2:\"CDF\":E -O -K >> ${psfl}\n", depMin, depMax);
*/
    fprintf(ofl, "gmt psbasemap -R%f/%f/0/1.05 -J -Bpx0.2 -Bpya0.2+l\"CDF\" -BE -O -K ${parms} >> ${psfl}\n", depMin, depMax);
    cumDep = array_cumsum64f(nd, depHist, &ierr);
    if (lclose)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O << EOF >> ${psfl}\n");
    }
    else
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O -K << EOF >> ${psfl}\n");
    }
    for (i=0; i<nd; i++)
    {
        fprintf(ofl, "%f %f\n", deps[i], cumDep[i]);
    }
    fprintf(ofl, "EOF\n");
    if (lclose)
    {
        //fprintf(ofl, "gmt psconvert -A -Tj ${psfl}\n");
        //fprintf(ofl, "rm ${psfl}\n");
        fprintf(ofl, "gmt psconvert -A -Tf ${psfl}\n");
        fprintf(ofl, "/bin/rm ${psfl}\n");
    }
    memory_free64f(&cumDep);
    fclose(ofl);
    chmod(outputScript, 0755);
    return 0;
}
//============================================================================//
int postmt_gmtHelper_writeMagnitudeBoxes(const bool lappend, const bool lclose,
                                         const char *outputScript,
                                         const char *psFile,
                                         const int nm,
                                         const int magOpt,
                                         const double *__restrict__ M0s,
                                         const double *__restrict__ magHist)
{
    FILE *ofl;
    char color[32], app[8], more[8], shift[8];
    double *cumMag, *Mw, dm, mmax, mwMin, mwMax;
    int i, ierr;
    const bool lwritePrior = true;
    // Compute moment magnitudes
    Mw = memory_calloc64f(nm);
    mmax = array_max64f(nm, magHist, &ierr);
    compearth_m02mw(nm, CE_KANAMORI_1978, M0s, Mw);
    dm = 0.1;
    if (nm > 1){dm = Mw[1] - Mw[0];};
    mwMin = Mw[0] - dm/2.0;
    mwMax = Mw[nm-1] + dm/2.0;
    memset(app, 0, 8*sizeof(char));
    memset(more, 0, 8*sizeof(char));
    memset(shift, 0, 8*sizeof(char));
    if (!lappend)
    {
        ofl = fopen(outputScript, "w");
        fprintf(ofl, "#!/bin/bash\n");
        /*
        fprintf(ofl, "gmt gmtset FONT_LABEL 12p\n");
        fprintf(ofl, "gmt gmtset MAP_LABEL_OFFSET 0.1c\n");
        */
        fprintf(ofl, "parms=\"--FONT_LABEL=10p --MAP_LABEL_OFFSET=0.1c --PROJ_LENGTH_UNIT=cm\"\n");
        fprintf(ofl, "psfl=%s\n", psFile);
    }
    else
    {
        ofl = fopen(outputScript, "a");
        strcpy(app, "-O\0");
        strcpy(more, ">\0");
        strcpy(shift, "-Y4.0\0");
    }
    fprintf(ofl,
/*
            "gmt psbasemap -JX5i/1i %s -R%.2f/%.2f/0/%.2f -Bg%fa%f:\"Magnitude (Mw)\":/a%.2f:\"Likelihood\":WSn -P %s -K >%s ${psfl}\n",
*/
            "gmt psbasemap -JX5i/1i %s -R%.2f/%.2f/0/%.2f -Bpxg%fa%f+l\"Magnitude (Mw)\" -Bpya%.2f+l\"Likelihood\" -BWSn -P %s -K ${parms} >%s ${psfl}\n",
            shift, mwMin, mwMax, mmax*1.1, dm, (nm-1)*dm/5.0, mmax*0.2, app, more);
    setFillColor(0, magOpt, color);
    if (nm > 1)
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
    }
    else
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
    }
    fprintf(ofl, "%.2f %f\n", mwMin, 0.0);
    fprintf(ofl, "%.2f %f\n", mwMin, magHist[0]);
    for (i=0; i<nm-1; i++)
    {
        fprintf(ofl, "%.2f %f\n", mwMin + (double) (i+1)*dm, magHist[i]);
        fprintf(ofl, "%.2f %f\n", mwMin + (double) (i+1)*dm, 0.0);
        fprintf(ofl, "EOF\n");
        setFillColor(i+1, magOpt, color);
        if (i < nm - 2 || lwritePrior)
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
        }
        else
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
        }
        fprintf(ofl, "%.2f %f\n", mwMin + (double) (i+1)*dm, 0.0);
        fprintf(ofl, "%.2f %f\n", mwMin + (double) (i+1)*dm, magHist[i+1]);
    }
    fprintf(ofl, "%.2f %f\n", mwMax, magHist[nm-1]);
    fprintf(ofl, "%.2f %f\n", mwMax, 0.0);
    fprintf(ofl, "EOF\n");
    // Write the prior distribution
    if (lwritePrior)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,black -O -K << EOF >> ${psfl}\n");
        fprintf(ofl, "%f %f\n", mwMin, 1.0/(double) nm);
        fprintf(ofl, "%f %f\n", mwMax, 1.0/(double) nm);
        fprintf(ofl, "EOF\n");
    }
    // Write the CDF
/*
    fprintf(ofl, "gmt psbasemap -R%f/%f/0/1.05 -J -Bp0.2/a0.2:\"CDF\":E -O -K >> ${psfl}\n", mwMin, mwMax);
*/
    fprintf(ofl, "gmt psbasemap -R%f/%f/0/1.05 -J -Bpx0.2 -Bpya0.2+l\"CDF\" -BE -O -K ${parms} >> ${psfl}\n", mwMin, mwMax);
    cumMag = array_cumsum64f(nm, magHist, &ierr);
    if (lclose)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O << EOF >> ${psfl}\n");
    }
    else
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O -K << EOF >> ${psfl}\n");
    }
    for (i=0; i<nm; i++)
    {
        fprintf(ofl, "%f %f\n", Mw[i], cumMag[i]);
    }
    fprintf(ofl, "EOF\n");
    if (lclose)
    {
        //fprintf(ofl, "gmt psconvert -A -Tj ${psfl}\n");
        //fprintf(ofl, "rm ${psfl}\n");
    }
    fclose(ofl);
    memory_free64f(&cumMag);
    memory_free64f(&Mw);
    chmod(outputScript, 0755);
    return 0;
}
//============================================================================//
int postmt_gmtHelper_writeGammaBoxes(const bool lappend, const bool lclose,
                                     const char *outputScript,
                                     const char *psFile,
                                     const int ng,
                                     const int igammaOpt,
                                     const double *__restrict__ gammas,
                                     const double *__restrict__ gammaHist)
{
    FILE *ofl;
    char color[32], app[8], more[8], shift[8];
    double *cumGamma, *v, gmax, gammaAvg, vAvg;
    int i, ierr;
    const bool lwritePrior = true;
    gmax = array_max64f(ng, gammaHist, &ierr);
    // Compute v
    v = memory_calloc64f(ng);
    compearth_gamma2v(ng, gammas, v);
    // Take averages
    gammaAvg = -30.0;
    memset(app, 0, 8*sizeof(char));
    memset(shift, 0, 8*sizeof(char));
    memset(more, 0, 8*sizeof(char));
    if (!lappend)
    {
        ofl = fopen(outputScript, "w");
        fprintf(ofl, "#!/bin/bash\n");
        /*
        fprintf(ofl, "gmt gmtset FONT_LABEL 12p\n");
        fprintf(ofl, "gmt gmtset MAP_LABEL_OFFSET 0.1c\n");
        */
        fprintf(ofl, "parms=\"--FONT_LABEL=10p --MAP_LABEL_OFFSET=0.1c --PROJ_LENGTH_UNIT=cm\"\n");
        fprintf(ofl, "psfl=%s\n", psFile);
    }
    else
    {
        ofl = fopen(outputScript, "a");
        strcpy(app, "-O\0");
        strcpy(more, ">\0");
        strcpy(shift, "-Y4.0\0");
    }
    fprintf(ofl,
/*
            "gmt psbasemap -JX5i/1i %s -R-30/30/0/%.2f -Bg5a5:\"Longitude (deg)\":/a%.2f:\"Likelihood\":WSn -P %s -K >%s ${psfl}\n",
*/
            "gmt psbasemap -JX5i/1i %s -R-30/30/0/%.2f -Bpxg5a5+l\"Longitude (deg)\" -Bpya%.2f+l\"Likelihood\" -BWSn -P %s -K ${parms} >%s ${psfl}\n",
            shift, gmax*1.1, gmax*0.2, app, more);
    setFillColor(0, igammaOpt, color);
    if (ng > 1)
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
    }
    else
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
    }
    fprintf(ofl, "%f %f\n", -30.0, 0.0);
    fprintf(ofl, "%f %f\n", -30.0, gammaHist[0]);
    for (i=0; i<ng-1; i++)
    {
        vAvg = 0.5*(v[i] + v[i+1]);
        compearth_v2gamma(1, &vAvg, &gammaAvg);
        fprintf(ofl, "%f %f\n", gammaAvg*180.0/M_PI, gammaHist[i]);
        fprintf(ofl, "%f %f\n", gammaAvg*180.0/M_PI, 0.0);
        fprintf(ofl, "EOF\n");
        setFillColor(i+1, igammaOpt, color);
        if (i < ng - 2 || lwritePrior)
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
        }
        else
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
        }
        fprintf(ofl, "%f %f\n", gammaAvg*180.0/M_PI, 0.0);
        fprintf(ofl, "%f %f\n", gammaAvg*180.0/M_PI, gammaHist[i+1]);
    }
    fprintf(ofl, "%f %f\n", 30.0, gammaHist[ng-1]);
    fprintf(ofl, "%f %f\n", 30.0, 0.0);
    fprintf(ofl, "EOF\n");
    // Write the prior distribution
    if (lwritePrior)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,black -O -K << EOF >> ${psfl}\n");
        fprintf(ofl, "%f %f\n",-30.0, 1.0/(double) ng);
        fprintf(ofl, "%f %f\n", 30.0, 1.0/(double) ng);
        fprintf(ofl, "EOF\n");
    }
    // Write the CDF
/*
    fprintf(ofl, "gmt psbasemap -R-30/30/0/1.05 -J -Bp0.2/a0.2:\"CDF\":E -O -K >> ${psfl}\n");
*/
    fprintf(ofl, "gmt psbasemap -R-30/30/0/1.05 -J -Bpx0.2 -Bpya0.2+l\"CDF\" -BE -O -K ${parms} >> ${psfl}\n");
    cumGamma = array_cumsum64f(ng, gammaHist, &ierr);
    if (lclose)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O << EOF >> ${psfl}\n");
    }
    else
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O -K << EOF >> ${psfl}\n");
    }
    for (i=0; i<ng; i++)
    {
        fprintf(ofl, "%f %f\n", gammas[i]*180.0/M_PI, cumGamma[i]);
    }
    fprintf(ofl, "EOF\n");
    if (lclose)
    {
        //fprintf(ofl, "gmt psconvert -A -Tj ${psfl}\n");
        //fprintf(ofl, "rm ${psfl}\n");
        fprintf(ofl, "gmt psconvert -A -Tf ${psfl}\n");
        fprintf(ofl, "/bin/rm ${psfl}\n");
    }
    memory_free64f(&cumGamma);
    memory_free64f(&v);
    fclose(ofl);
    chmod(outputScript, 0755);
    return 0;
}
//============================================================================//
int postmt_gmtHelper_writeBetaBoxes(const bool lappend, const bool lclose,
                                    const char *outputScript,
                                    const char *psFile,
                                    const int nb,
                                    const int ibetaOpt,
                                    const double *__restrict__ betas,
                                    const double *__restrict__ betaHist)
{
    FILE *ofl;
    char color[32], app[8], more[8], shift[8];
    double *betaCum, *u, bmax, betaAvg, uAvg;
    int i, ierr;
    const bool lwritePrior = true;
    bmax = array_max64f(nb, betaHist, &ierr);
    // Compute u
    u = memory_calloc64f(nb);
    compearth_beta2u(nb, betas, u);
    // Take averages
    betaAvg = 0.0;
    memset(app, 0, 8*sizeof(char));
    memset(more, 0, 8*sizeof(char));
    memset(shift, 0, 8*sizeof(char));
    if (!lappend)
    {
        ofl = fopen(outputScript, "w");
        fprintf(ofl, "#!/bin/bash\n");
        /*
        fprintf(ofl, "gmt gmtset FONT_LABEL 12p\n");
        fprintf(ofl, "gmt gmtset MAP_LABEL_OFFSET 0.1c\n");
        */
        fprintf(ofl, "parms=\"--FONT_LABEL=10p --MAP_LABEL_OFFSET=0.1c --PROJ_LENGTH_UNIT=cm\"\n");
        fprintf(ofl, "psfl=%s\n", psFile);
    }
    else
    {
        ofl = fopen(outputScript, "a");
        strcpy(app, "-O\0");
        strcpy(more, ">\0");
        strcpy(shift, "-Y4.0\0");
    }
    fprintf(ofl,
/*
            "gmt psbasemap -JX5i/1i %s -R-90/90/0/%.3f -Bg15a15:\"Latitude (deg)\":/a%.2f:\"Likelihood\":WSn -P %s -K >%s ${psfl}\n",
*/
            "gmt psbasemap -JX5i/1i %s -R-90/90/0/%.3f -Bpxg15a15+l\"Latitude (deg)\" -Bpya%.2f+l\"Likelihood\" -BWSn -P %s -K ${parms} >%s ${psfl}\n",
            shift, bmax*1.1, bmax*0.2, app, more);
    setFillColor(0, ibetaOpt, color);
    if (nb > 1)
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
    }
    else
    {
       fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
    }
    fprintf(ofl, "%f %f\n", 90.0 - 0.0, 0.0);
    fprintf(ofl, "%f %f\n", 90.0 - 0.0, betaHist[0]);
    for (i=0; i<nb-1; i++)
    {
        uAvg = 0.5*(u[i] + u[i+1]);
        compearth_u2beta(1, &uAvg, &betaAvg);
        //compearth_u2beta(1, 20, 2, &uAvg, 1.e-7, &betaAvg);
        fprintf(ofl, "%f %f\n", 90.0 - betaAvg*180.0/M_PI, betaHist[i]);
        fprintf(ofl, "%f %f\n", 90.0 - betaAvg*180.0/M_PI, 0.0);
        fprintf(ofl, "EOF\n");
        setFillColor(i+1, ibetaOpt, color);
        if (i < nb - 2 || lwritePrior)
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O -K << EOF >> ${psfl}\n", color);
        }
        else
        {
            fprintf(ofl, "gmt psxy -R -J -Wblack %s -O << EOF >> ${psfl}\n", color);
        }
        fprintf(ofl, "%f %f\n", 90.0 - betaAvg*180.0/M_PI, 0.0);
        fprintf(ofl, "%f %f\n", 90.0 - betaAvg*180.0/M_PI, betaHist[i+1]);
    }
    fprintf(ofl, "%f %f\n", 90.0 - M_PI*180.0/M_PI, betaHist[nb-1]);
    fprintf(ofl, "%f %f\n", 90.0 - M_PI*180.0/M_PI, 0.0);
    fprintf(ofl, "EOF\n");
    // Write the prior distribution
    if (lwritePrior)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,black -O -K << EOF >> ${psfl}\n");
        fprintf(ofl, "%f %f\n",-90.0, 1.0/(double) nb);
        fprintf(ofl, "%f %f\n", 90.0, 1.0/(double) nb);
        fprintf(ofl, "EOF\n");
    }
    // Write the CDF
/*
    fprintf(ofl, "gmt psbasemap -R-90/90/0/1.05 -J -Bp0.2/a0.2:\"CDF\":E -O -K >> ${psfl}\n");
*/
    fprintf(ofl, "gmt psbasemap -R-90/90/0/1.05 -J -Bpx0.2 -Bpya0.2+l\"CDF\" -BE -O -K ${parms} >> ${psfl}\n");
    betaCum = array_cumsum64f(nb, betaHist, &ierr);
    if (lclose)
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O << EOF >> ${psfl}\n");
    }
    else
    {
        fprintf(ofl, "gmt psxy -R -J -W1,blue -O -K << EOF >> ${psfl}\n");
    }
    for (i=0; i<nb; i++)
    {
        // the cdf is written backwards because i flip the axis to make it
        // increase left to right; this is opposite of what colatitude wants
        // to do
        fprintf(ofl, "%f %f\n", 90.0 - betas[i]*180.0/M_PI, betaCum[nb-1-i]);
    }
    fprintf(ofl, "EOF\n");
    if (lclose)
    {
        //fprintf(ofl, "gmt psconvert -A -Tj ${psfl}\n");
        //fprintf(ofl, "rm ${psfl}\n");
        fprintf(ofl, "gmt psconvert -A -Tf ${psfl}\n");
        fprintf(ofl, "/bin/rm ${psfl}\n");
    }
    memory_free64f(&u);
    memory_free64f(&betaCum);
    fclose(ofl);
    chmod(outputScript, 0755);
    return 0;
}
//============================================================================//
int postmt_gmtHelper_makeRegularHistograms(
    const int nlocs, const int nm,
    const int nb, const int ng, const int nk,
    const int ns, const int nt,
    const int nmt, const double *__restrict__ phi,
    double **__restrict__ locHist,
    double **__restrict__ magHist,
    double **__restrict__ betaHist,
    double **__restrict__ gammaHist,
    double **__restrict__ kappaHist,
    double **__restrict__ sigmaHist,
    double **__restrict__ thetaHist)
{
    double *betaH, *gammaH, *kappaH, *locH, *magH, *sigmaH, *thetaH, xsum;
    int ib, ierr, ig, ik, il, im, imt, is, it;
    locH = memory_calloc64f(nlocs);
    magH = memory_calloc64f(nm);
    betaH = memory_calloc64f(nb);
    gammaH = memory_calloc64f(ng);
    kappaH = memory_calloc64f(nk);
    sigmaH = memory_calloc64f(ns);
    thetaH = memory_calloc64f(nt);
    for (il=0; il<nlocs; il++)
    {
        for (im=0; im<nm; im++)
        {
            for (ib=0; ib<nb; ib++)
            {
                for (ig=0; ig<ng; ig++)
                {
                    for (ik=0; ik<nk; ik++)
                    {
                        for (is=0; is<ns; is++)
                        {
                            for (it=0; it<nt; it++)
                            {
                                imt = il*nm*nb*ng*nk*ns*nt
                                    + im*nb*ng*nk*ns*nt
                                    + ib*ng*nk*ns*nt
                                    + ig*nk*ns*nt
                                    + ik*ns*nt
                                    + is*nt
                                    + it;
                                locH[il]   = locH[il]   + phi[imt];
                                magH[im]   = magH[im]   + phi[imt];
                                betaH[ib]  = betaH[ib]  + phi[imt];
                                gammaH[ig] = gammaH[ig] + phi[imt];
                                kappaH[ik] = kappaH[ik] + phi[imt];
                                sigmaH[is] = sigmaH[is] + phi[imt];
                                thetaH[it] = thetaH[it] + phi[imt];
                            }
                        }
                    }
                }
            }
        }
    }
    xsum = array_sum64f(nmt, phi, &ierr);
    cblas_dscal(nlocs, 1.0/xsum, locH, 1);
    cblas_dscal(nm, 1.0/xsum, magH, 1);
    cblas_dscal(nb, 1.0/xsum, betaH, 1);
    cblas_dscal(ng, 1.0/xsum, gammaH, 1);
    cblas_dscal(nk, 1.0/xsum, kappaH, 1);
    cblas_dscal(ns, 1.0/xsum, sigmaH, 1);
    cblas_dscal(nt, 1.0/xsum, thetaH, 1);
    *locHist = locH;
    *magHist = magH;
    *betaHist = betaH;
    *gammaHist = gammaH;
    *kappaHist = kappaH;
    *sigmaHist = sigmaH;
    *thetaHist = thetaH;
    return 0;
}
//============================================================================//
static void getBaseAndExp(const double val, double *base, int *exp)
{
    char cval[64], cexp[64], temp[64];
    int i, k, l;
    bool lp1;
    memset(cval, 0, 64*sizeof(char));
    memset(cexp, 0, 64*sizeof(char));
    memset(temp, 0, 64*sizeof(char));
    sprintf(temp, "%04.2e", val);
    lp1 = true;
    k = 0;
    l = 0;
    for (i=0; i<strlen(temp); i++)
    {
        if (temp[i] == 'e')
        {
            lp1 = false;
            continue;
        }
        else
        {
            if (lp1)
            {
                cval[k] = temp[i];
                k = k + 1;
            }
            else
            {
                cexp[l] = temp[i];
                l = l + 1;
            }
        }
    }
    *exp = atoi(cexp);
    *base = atof(cval);
    return;
}

static void getBaseAndExpMT(const double *mtIn, double *mtOut, int *expOut)
{
    double xfact;
    int expWork, i;
    getBaseAndExp(mtIn[0], &mtOut[0], expOut);
    for (i=1; i<6; i++)
    {
        getBaseAndExp(mtIn[i], &mtOut[i], &expWork);
        if (expWork > *expOut){*expOut = expWork;}
    }
    // Rescale
    for (i=0; i<6; i++)
    {
        getBaseAndExp(mtIn[i], &mtOut[i], &expWork);
        xfact = pow(10.0, expWork - *expOut);
        mtOut[i] = mtOut[i]*xfact;
    }
    return;
}

int postmt_gmtHelper_makePsmecaLine(const enum compearthCoordSystem_enum basis,
                                    const double *mt,
                                    const double evla, const double evlo,
                                    const double evdp, const char *evid,
                                    char line[128])
{
    const char *fcnm = "postmt_gmtHelper_makePsmecaLine\0";
    double mtUSE[6], mtGMT[6];
    int exp, ierr;
    memset(line, 0, 128*sizeof(char));
    ierr = compearth_convertMT(1, basis, CE_USE, mt, mtUSE);
    if (ierr != 0)
    {
        printf("%s: Error switching basis\n", fcnm);
        return -1;
    }
    getBaseAndExpMT(mtUSE, mtGMT, &exp);
    sprintf(line, "%f %f %f %f %f %f %f %f %f %d %s\n",
            evlo, evla, evdp,
            mtGMT[0], mtGMT[1], mtGMT[2], mtGMT[3], mtGMT[4], mtGMT[5],
            exp, evid);
    return 0;
}

static void setFillColor(const int i, const int iopt, char color[32])
{
    memset(color, 0, 32*sizeof(char));
    if (i == iopt)
    {
        strcpy(color, "-Gyellow\0");
    }
    else
    {
        strcpy(color, "-Gred\0");
    }
    return;
}
//============================================================================//
/*
    sprintf("%7.2f %5.2f %f \n"<
            evlo, evla, evdp,
            mrr, mtt, mpp,

Columns: lon lat depth mrr mtt mpp mrt mrp mtp iexp name
-176.96 -29.25 48 7.68 0.09 -7.77 1.39 4.52 -3.26 26 X Y 010176A
*/


#ifndef __GSL_SORT_H__
#define __GSL_SORT_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <gsl/gsl_sort_long_double.h>
#include <gsl/gsl_sort_double.h>
#include <gsl/gsl_sort_float.h>

#include <gsl/gsl_sort_ulong.h>
#include <gsl/gsl_sort_long.h>

#include <gsl/gsl_sort_uint.h>
#include <gsl/gsl_sort_int.h>

#include <gsl/gsl_sort_ushort.h>
#include <gsl/gsl_sort_short.h>

#include <gsl/gsl_sort_uchar.h>
#include <gsl/gsl_sort_char.h>

#endif /* __GSL_SORT_H__ */


/**
* Copyright 2016 BitTorrent Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once

#include <scraps/config.h>

#include <scraps/Byte.h>
#include <scraps/Temp.h>
#include <scraps/ByteArray.h>

#include <gsl.h>

#include <iterator>

namespace scraps {

constexpr signed char DecToHex(int c) {
    if (c >= 0 && c < 16) {
        return "0123456789abcdef"[c];
    }
    return -1;
}

constexpr signed char DecToHex(const Byte& c) {
    return DecToHex(c.value());
}

template <typename CharT>
constexpr int8_t HexToDec(CharT c) {
    if (c >= '0' && c <= '9') { return c - '0'; }
    if (c >= 'a' && c <= 'f') { return c - 'a' + 10; }
    if (c >= 'A' && c <= 'F') { return c - 'A' + 10; }
    return -1;
}

/**
 * Returns a hex string representation of the input span. The output does not
 * include an "0x" prefix.
 *
 * example: ToHex(std::array<uint8_t, 1>{0xAB}) == "AB";
 */
template <typename T, std::ptrdiff_t... BytesDimension>
std::string ToHex(const gsl::span<T, BytesDimension...> range) {
    std::string ret;

    static_assert(sizeof(T) == 1, "Input span type too large");

    ret.reserve(range.size() * 2 + 2);

    for (auto& b : range) {
        ret += DecToHex(b >> 4);
        ret += DecToHex(b & 0x0F);
    }

    return ret;
}

template <typename T, size_t N>
std::string ToHex(const std::array<T, N>& in) {
    return ToHex(gsl::span<const T, N>{in});
}

template <size_t N>
std::string ToHex(const ByteArray<N>& in) {
    return ToHex(gsl::span<const unsigned char, N>{in.bytes});
}

/**
 * Fills a byte range from a range of hex characters. Returns true if the input
 * range is successfully converted to the output range. A prefix of "0x" or "0X"
 * is optional.
 */
template <typename HexCharT, std::ptrdiff_t HexExtent, typename ByteType, std::ptrdiff_t... BytesDimension>
constexpr bool ToBytes(const gsl::basic_string_span<const HexCharT, HexExtent> hex, const gsl::span<ByteType, BytesDimension...> bytes) {
    auto prefixSize = 0;
    if (hex.size() > 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) {
        prefixSize += 2;
    }
    if (hex.size() - prefixSize != bytes.size() * 2) {
        return false;
    }
    for (decltype(bytes.size()) i = 0; i < bytes.size(); ++i) {
        auto hi = HexToDec(hex[i * 2 + prefixSize]);
        auto lo = HexToDec(hex[i * 2 + 1 + prefixSize]);
        if (hi < 0 || lo < 0) {
            return false;
        }
        bytes[i] = ByteType{static_cast<uint8_t>((hi << 4) | lo)};
    }
    return true;
}

template <typename CharT, typename T, size_t N>
constexpr bool ToBytes(const std::basic_string<CharT>& in, std::array<T, N>& out) {
    return ToBytes(gsl::basic_string_span<const CharT>{in}, gsl::span<T, N>{out});
}

} // namespace scraps


/*
 * Copyright (c) 2016-2021 lymastee, All rights reserved.
 * Contact: lymastee@hotmail.com
 *
 * This file is part of the gslib project.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#pragma once

#ifndef loopblinn_875a5488_30b0_4449_b97a_e55c8d8a0db1_h
#define loopblinn_875a5488_30b0_4449_b97a_e55c8d8a0db1_h

#include <gslib/std.h>
#include <gslib/rtree.h>
#include <ariel/painterpath.h>
#include <ariel/delaunay.h>

__ariel_begin__

class lb_joint;
class lb_end_joint;
class lb_control_joint;
class lb_line;
class lb_polygon;
class lb_shrink_line;
class lb_shrink;

typedef vector<lb_joint*> lb_joint_list;
typedef vector<lb_line*> lb_line_list;
typedef vector<lb_polygon*> lb_polygon_list;
typedef vector<lb_shrink_line*> lb_shrink_lines;
typedef stack<lb_polygon*> lb_polygon_stack;

enum lb_joint_type
{
    lbt_end_joint,
    lbt_control_joint,
};

/*
 * The reason why the original point and the NDC(normalized device coordinate) point should
 * be separated was that we need the original point for the convenience of the error handling
 * works, and we need the NDC point to do the loopblinn calculations so that the float
 * point won't overflow.
 */
class __gs_novtable lb_joint abstract
{
protected:
    lb_line*            _prev;
    lb_line*            _next;
    vec2                _point;
    vec2                _ndcpoint;
    void*               _binding;

public:
    lb_joint()
    {
        _prev = _next = nullptr;
        _binding = nullptr;
    }
    virtual ~lb_joint() {}
    virtual lb_joint_type get_type() const = 0;
    virtual const vec2& get_point() const { return _point; }
    virtual const vec2& get_ndc_point() const { return _ndcpoint; }

public:
    void set_point(const vec2& p) { _point = p; }
    void set_ndc_point(const vec2& p) { _ndcpoint = p; }
    void set_prev_line(lb_line* p) { _prev = p; }
    void set_next_line(lb_line* p) { _next = p; }
    lb_line* get_prev_line() const { return _prev; }
    lb_line* get_next_line() const { return _next; }
    lb_joint* get_prev_joint() const;
    lb_joint* get_next_joint() const;
    bool is_adjacent_joint(const lb_joint* p) const { return p == get_prev_joint() || p == get_next_joint(); }
    void set_binding(void* p) { _binding = p; }
    void* get_binding() const { return _binding; }
};

class lb_end_joint:
    public lb_joint
{
protected:
    vec3                _klm[2];

public:
    lb_end_joint() {}
    lb_joint_type get_type() const override { return lbt_end_joint; }
    bool prev_is_curve() const;
    bool next_is_curve() const;
    void set_klm(int i, const vec3& p) { _klm[i] = p; }
    const vec3& get_klm(int i) const { return _klm[i]; }
};

class lb_control_joint:
    public lb_joint
{
protected:
    vec3                _klm;

public:
    lb_control_joint() {}
    lb_joint_type get_type() const override { return lbt_control_joint; }
    void set_klm(const vec3& p) { _klm = p; }
    const vec3& get_klm() const { return _klm; }
};

class lb_line
{
protected:
    lb_joint*           _joint[2];
    bool                _opened;

public:
    lb_line()
    {
        _joint[0] = _joint[1] = nullptr;
        _opened = false;
    }
    void set_opened(bool b) { _opened = b; }
    bool is_opened() const { return _opened; }
    void set_prev_joint(lb_joint* p) { _joint[0] = p; }
    void set_next_joint(lb_joint* p) { _joint[1] = p; }
    lb_joint* get_prev_joint() const { return _joint[0]; }
    lb_joint* get_next_joint() const { return _joint[1]; }
    lb_line* get_prev_line() const;
    lb_line* get_next_line() const;
    const vec2& get_prev_point() const { return _joint[0]->get_point(); }
    const vec2& get_next_point() const { return _joint[1]->get_point(); }
    static lb_line* get_line_between(lb_joint* j1, lb_joint* j2);
};

enum lb_span_type
{
    lst_linear,
    lst_quad,
    lst_cubic,
};

class __gs_novtable lb_span abstract
{
protected:
    rectf               _rc;

public:
    virtual ~lb_span() {}
    virtual lb_span_type get_type() const = 0;
    virtual bool can_split() const = 0;
    virtual bool is_overlapped(const lb_span* span) const = 0;

public:
    const rectf& get_rect() const { return _rc; }
    float get_area() const { return _rc.width() * _rc.height(); }
};

typedef vector<lb_span*> lb_span_list;
typedef rtree_entity<lb_span*> lb_rtree_entity;
typedef rtree_node<lb_rtree_entity> lb_rtree_node;
typedef _tree_allocator<lb_rtree_node> lb_rtree_alloc;
typedef tree<lb_rtree_entity, lb_rtree_node, lb_rtree_alloc> lb_tree;
typedef rtree<lb_rtree_entity, quadratic_split_alg<8, 3, lb_tree>, lb_rtree_node, lb_rtree_alloc> lb_rtree;
typedef delaunay_triangulation lb_triangulator;

/*
 * The polygon should be decomposed to the form like boundary - holes,
 * this procedure could also be called flattening.
 * After we retrieve the boundary we need to create a shrink for the boundary
 * for including test, if necessary, so that we could decide if a sub path
 * (case : cw - ccw - {cw}?) was a new path that ends the previous boundary.
 */
class lb_polygon
{
protected:
    lb_line*            _boundary;
    lb_line_list        _holes;
    lb_rtree            _mytree;
    lb_triangulator     _cdt;
    dt_input_joints     _dtjoints;

public:
    lb_polygon() { _boundary = nullptr; }
    void set_boundary(lb_line* p) { _boundary = p; }
    void add_hole(lb_line* p) { _holes.push_back(p); }
    lb_line* get_boundary() const { return _boundary; }
    const lb_line_list& get_holes() const { return _holes; }
    bool is_inside(const vec2& p) const;
    lb_rtree& get_rtree() { return _mytree; }
    void convert_to_ndc(const mat3& m);
    void create_dt_joints();
    void pack_constraints();
    void build_cdt();
    lb_triangulator& get_cdt_result() { return _cdt; }
    void tracing() const;
    void trace_boundary() const;
    void trace_last_hole() const;
    void trace_holes() const;
    void trace_rtree() const { _mytree.tracing(); }
};

/*
 * Notice that the path put into the loopblinn categorizer MUST be a simple polygon,
 * which means you should run a xor clip process before if you can't tell whether a
 * path was simple or complex.
 * Another point was that the path MUST be Winding rule.
 * You can also convert a path of OddEven rule to Winding by clipping.
 */
class loop_blinn_processor
{
public:
    loop_blinn_processor(float w, float h) { _width = w, _height = h; }
    ~loop_blinn_processor();
    void proceed(const painter_path& path);
    lb_polygon_list& get_polygons() { return _polygons; }
    lb_joint_list& get_joints() { return _joint_holdings; }
    lb_line_list& get_lines() { return _line_holdings; }
    void trace_polygons() const;
    void trace_rtree() const;

protected:
    float               _width;
    float               _height;
    lb_line_list        _line_holdings;
    lb_joint_list       _joint_holdings;
    lb_polygon_list     _polygons;
    lb_span_list        _span_holdings;

protected:
    template<class _joint>
    lb_joint* create_joint(const vec2& p);
    lb_line* create_line();
    lb_polygon* create_polygon();
    void flattening(const painter_path& path);
    int flattening(const painter_path& path, int start, lb_polygon* parent, lb_polygon_stack& st);
    int create_patch(lb_line*& line, const painter_path& path, int start);
    lb_joint* create_segment(lb_joint* prev, const painter_path& path, int i);
    void check_boundary(lb_polygon* poly);
    void check_holes(lb_polygon* poly);
    void check_span(lb_polygon* poly, lb_control_joint* joint);
    void check_rtree(lb_polygon* poly);
    void check_rtree_span(lb_polygon* poly, lb_span* span);
    void split_quadratic(lb_line* line1, lb_line* line2, lb_joint* sp[5]);
    void split_cubic(lb_line* line1, lb_line* line2, lb_line* line3, lb_joint* sp[7], float t);
    int try_split_cubic(lb_line* line1, lb_line* line2, lb_line* line3, lb_joint* sp[7], float t);
    lb_span* split_rtree_span(lb_span* span);
    void split_span_recursively(lb_polygon* poly, lb_span* span);
    void calc_klm_coords();
    void calc_klm_coords(lb_polygon* poly);
    void calc_klm_coords(lb_polygon* poly, lb_line* start);
    lb_line* calc_klm_span(lb_polygon* poly, lb_line* line);
};

extern lb_line* lb_get_span(lb_line_list& span, lb_line* start);
extern void lb_get_current_span(lb_line_list& span, lb_control_joint* joint);

__ariel_end__

#endif


#ifndef TREE_H
#define TREE_H
#include "node.h"
#include <string>
#include <vector>
#include <gsl/gsl_rng.h>
#include "data.h"

using namespace std;

namespace weakarg
{

extern gsl_rng * rng;

/**
    @brief Genealogy of the isolates under study
*/
class Tree
{
protected:
    Node * root;///<Root node of the genealogy
    std::vector<Node*> nodes;///<Vector of all the nodes in the genealogy
    int n;///<Number of isolates
    double ttotal;///<Sum of branch lengths
public:
    Tree(std::string newick,bool isFilename=true,bool forceages=true);///<Creates a tree from a Newick file
    Tree(int n);///< Creates a Coalescent tree by simulation
    Tree(Tree *intree);///< Creates a copy of a tree via newick (== slow)
    Tree(Data * data);///< Creates a UPGMA tree
    Tree(const Tree& t);///< Copy constructor
    void assign(const Tree& t);///< Copy a tree while allocating as little new storage as possible
    ~Tree();
    std::string newick(int p=6) const; ///<Returns a Newick description of the tree (precision options)
    std::string newickNoInternalLabels(int p=6) const; ///<Returns a Newick description of the tree (precision options)
    void makeFromNewick(std::string newick,bool forceages=false);///< Creates a tree from a newick string
    inline int getN() const
    {
        return n;
    }///<Returns the number of isolates
    inline Node* getNode(int i) const
    {
        return nodes[i];
    }///<Returns a node given its index
    inline Node* getRoot() const
    {
        return root;
    }///<Returns the root node
    inline double getDist(int i) const
    {
        return nodes[i]->getDist();
    }///<Returns the time of a node given its index
    double prior() const; ///<Returns log-prior of the tree
    inline double getTTotal() const
    {
        return ttotal;
    }///<Returns the sum of branch lengths
    void computeTTotal(); ///<Computes the sum of branch lengths
    int getPoint(double * dist, std::vector<int> * samplespace=NULL) const; ///<Returns a point chosen uniformly at random on the tree, or uniformally on a subspace of specified clonal edges
    std::vector<int> getAllChildren(int e);///<Returns a vector of the indices of the children of a given node
    std::vector<int> getAllSampledSeqs(int e);///<Returns a vector of all the observed sequences of the children of a given node

    void orderNodes(double dist=1);///<orders the list by age
    int orderNodes(int which, double dist);///<places a node in a new place in the list
    void swapFather(int a,int b);///<Swaps the father of two nodes
    void swapNode(int a, int b);///<Swaps two nodes in the list
    int getOldestReversedNode();///<Returns the oldest node that has been age reversed

    void testNodeAges() const; ///<Tests node ages
    double tavare() const;

    inline int otherChild(int par,int onechild){
	if(getNode(par)->getLeft()->getId()==onechild) return(getNode(par)->getRight()->getId());
	else if(getNode(par)->getRight()->getId()==onechild) return(getNode(par)->getLeft()->getId());
	else{cerr<<"Error in RecTree::otherChild: parent doesn't have a suitable child!"<<endl;throw("unknown child error");}
    };
    std::vector<int> getMinEdgeList(std::vector<int> seqs);
    int getNextGroup(std::vector<int> *seqs);
    bool isParentToOnly(int e, std::vector<int> seqs,std::vector<int> *which);

};

} // end namespace weakarg
#endif


#ifndef SN3D_H
#define SN3D_H

#include <cassert>

#ifndef __CUDA_ARCH__
  // host code

  #define __artis_assert(e) if (!(e)) { if (output_file != NULL) {(void)fprintf(output_file, "[rank %d] %s:%d: failed assertion `%s' in function %s\n", globals::rank_global, __FILE__, __LINE__, #e, __PRETTY_FUNCTION__);} (void)fprintf(stderr, "[rank %d] %s:%d: failed assertion `%s' in function %s\n", globals::rank_global, __FILE__, __LINE__, #e, __PRETTY_FUNCTION__); abort();}
  //

  #define assert_always(e) __artis_assert(e)

  #if defined TESTMODE && TESTMODE
    #define assert_testmodeonly(e) __artis_assert(e)
  #else
    #define	assert_testmodeonly(e) ((void)0)
  #endif

  #define printout(...) fprintf(output_file, __VA_ARGS__)

  #ifdef _OPENMP
  #ifndef __CUDACC__
    #define safeadd(var, val) _Pragma("omp atomic update") \
    var += val
  #else
    #define safeadd(var, val) var += val
  #endif
  #else
    #define safeadd(var, val) var += val
  #endif

#else
  // device code

  #define printout(...) printf (__VA_ARGS__)

  #define assert_always(e) assert(e)

  #if defined TESTMODE && TESTMODE
    #define assert_testmodeonly(e) assert(e)
  #else
    #define	assert_testmodeonly(e) ((void)0)
  #endif

  #define safeadd(var, val) atomicAdd(&var, val)

#endif

#define safeincrement(var) safeadd(var, 1)

#include "cuda.h"

#include <stdarg.h>  /// MK: needed for printout()
#include <gsl/gsl_integration.h>

#define DEBUG_ON
// #define DO_TITER
// #define FORCE_LTE

#include "globals.h"
#include "types.h"
#include "vectors.h"

#if (DETAILED_BF_ESTIMATORS_ON && !NO_LUT_PHOTOION)
  #error Must use NO_LUT_PHOTOION with DETAILED_BF_ESTIMATORS_ON
#endif

#if !defined MPI_ON
  // #define MPI_ON //only needed for debugging MPI, the makefile will switch this on
#endif

#ifdef MPI_ON
  #include "mpi.h"
#endif

//#define _OPENMP
#ifdef _OPENMP
  #include "omp.h"
#endif

#define COOLING_UNDEFINED       -99

#define RPKT_EVENTTYPE_BB 550
#define RPKT_EVENTTYPE_CONT 551

extern int tid;
extern __managed__ bool use_cellhist;
extern __managed__ bool neutral_flag;
#ifndef __CUDA_ARCH__
extern gsl_rng *rng;  // pointer for random number generator
#else
extern __device__ void *rng;
#endif
extern gsl_integration_workspace *gslworkspace;
extern FILE *output_file;
extern __managed__ int myGpuId;

#ifdef _OPENMP
  #pragma omp threadprivate(tid, myGpuId, use_cellhist, neutral_flag, rng, gslworkspace, output_file)
#endif

inline void gsl_error_handler_printout(const char *reason, const char *file, int line, int gsl_errno)
{
  if (gsl_errno != 18) // roundoff error
  {
    printout("WARNING: gsl (%s:%d): %s (Error code %d)\n", file, line, reason, gsl_errno);
    // abort();
  }
}

inline FILE *fopen_required(const char *filename, const char *mode)
{
  FILE *file = fopen(filename, mode);
  if (file == NULL)
  {
    printout("ERROR: Could not open file '%s' for mode '%s'.\n", filename, mode);
    abort();
  }

  return file;
}

inline int get_timestep(const double time)
{
  assert_always(time >= globals::tmin);
  assert_always(time < globals::tmax);
  for (int nts = 0; nts < globals::ntstep; nts++)
  {
    const double tsend = (nts < (globals::ntstep - 1)) ? globals::time_step[nts + 1].start : globals::tmax;
    if (time >= globals::time_step[nts].start && time < tsend)
    {
      return nts;
    }
  }
  assert_always(false); // could not find matching timestep

  return -1;
}

inline double get_arrive_time(const PKT *pkt_ptr)
/// We know that a packet escaped at "escape_time". However, we have
/// to allow for travel time. Use the formula in Leon's paper. The extra
/// distance to be travelled beyond the reference surface is ds = r_ref (1 - mu).
{
  return pkt_ptr->escape_time - (dot(pkt_ptr->pos, pkt_ptr->dir) / globals::CLIGHT_PROP);
}

inline double get_arrive_time_cmf(const PKT *pkt_ptr)
{
  return pkt_ptr->escape_time * sqrt(1. - (globals::vmax * globals::vmax / CLIGHTSQUARED));
}

__host__ __device__
inline int get_max_threads(void)
{
#ifdef __CUDA_ARCH__
  return MCUDATHREADS;
#elif defined _OPENMP
  return omp_get_max_threads();
#else
  return 1;
#endif
}

__host__ __device__
inline int get_num_threads(void)
{
#ifdef __CUDA_ARCH__
  return blockDim.x * blockDim.y * blockDim.z;
#elif defined _OPENMP
  return omp_get_num_threads();
#else
  return 1;
#endif
}

__host__ __device__
inline int get_thread_num(void)
{
#ifdef __CUDA_ARCH__
  return threadIdx.x + blockDim.x * blockIdx.x;
#elif defined _OPENMP
  return omp_get_thread_num();
#else
  return 0;
#endif
}

#endif // SN3D_H