/***************************************************************************
 * mgl_c.h is part of Math Graphic Library
 * Copyright (C) 2007 Alexey Balakin <balakin@appl.sci-nnov.ru>            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library 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 Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef _MGL_C_H_
#define _MGL_C_H_

#include <mgl/config.h>

#if(MGL_USE_DOUBLE==1)
typedef double mreal;
#else
typedef float mreal;
#endif
//#include <mgl/mgl_define.h>

#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************/
//#ifdef _MGL_DATA_H_
#ifdef __cplusplus
struct mglDraw;
typedef mglDraw* HMDR;
class mglGraph;
typedef mglGraph* HMGL;
class mglData;
typedef mglData* HMDT;
class mglParse;
typedef mglParse* HMPR;
#else
typedef void* HMDR;
typedef void* HMGL;
typedef void* HMDT;
typedef void* HMPR;
#endif
#ifndef NO_GSL
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#else
struct gsl_vector;
struct gsl_matrix;
#endif
/*****************************************************************************/
HMGL mgl_create_graph_gl();
HMGL mgl_create_graph_zb(int width, int height);
HMGL mgl_create_graph_ps(int width, int height);
HMGL mgl_create_graph_idtf();
#ifndef MGL_NO_WIDGET
int mgl_fortran_func(HMGL gr, void *);
HMGL mgl_create_graph_glut(int (*draw)(HMGL gr, void *p), const char *title, void *par);
HMGL mgl_create_graph_fltk(int (*draw)(HMGL gr, void *p), const char *title, void *par);
HMGL mgl_create_graph_qt(int (*draw)(HMGL gr, void *p), const char *title, void *par);
HMGL mgl_create_graph_glut_dr(HMDR dr, const char *title);
HMGL mgl_create_graph_fltk_dr(HMDR dr, const char *title);
HMGL mgl_create_graph_qt_dr(HMDR dr, const char *title);
void mgl_fltk_run();
void mgl_qt_run();

void mgl_wnd_set_delay(HMGL gr, mreal dt);
void mgl_wnd_set_auto_clf(HMGL gr, int val);
void mgl_wnd_set_show_mouse_pos(HMGL gr, int val);
void mgl_wnd_set_clf_update(HMGL gr, int val);
void mgl_wnd_toggle_alpha(HMGL gr);
void mgl_wnd_toggle_light(HMGL gr);
void mgl_wnd_toggle_zoom(HMGL gr);
void mgl_wnd_toggle_rotate(HMGL gr);
void mgl_wnd_toggle_no(HMGL gr);
void mgl_wnd_update(HMGL gr);
void mgl_wnd_reload(HMGL gr, int o);
void mgl_wnd_adjust(HMGL gr);
void mgl_wnd_next_frame(HMGL gr);
void mgl_wnd_prev_frame(HMGL gr);
void mgl_wnd_animation(HMGL gr);
#endif
void mgl_set_show_mouse_pos(HMGL gr, int enable);
void mgl_get_last_mouse_pos(HMGL gr, mreal *x, mreal *y, mreal *z);
void mgl_calc_xyz(HMGL gr, int xs, int ys, mreal *x, mreal *y, mreal *z);
void mgl_calc_scr(HMGL gr, mreal x, mreal y, mreal z, int *xs, int *ys);
//void mgl_fltk_thread();
//void mgl_qt_thread();
void mgl_update(HMGL graph);
void mgl_delete_graph(HMGL graph);
/*****************************************************************************/
HMDT mgl_create_data();
HMDT mgl_create_data_size(int nx, int ny, int nz);
HMDT mgl_create_data_file(const char *fname);
void mgl_delete_data(HMDT dat);
/*****************************************************************************/
HMPR mgl_create_parser();
void mgl_delete_parser(HMPR p);
void mgl_scan_func(HMPR p, const wchar_t *line);
void mgl_add_param(HMPR p, int id, const char *str);
void mgl_add_paramw(HMPR p, int id, const wchar_t *str);
/*===!!! NOTE !!! You must not delete obtained data arrays !!!===============*/
HMDT mgl_add_var(HMPR, const char *name);
/*===!!! NOTE !!! You must not delete obtained data arrays !!!===============*/
HMDT mgl_find_var(HMPR, const char *name);
int mgl_parse(HMGL gr, HMPR p, const char *str, int pos);
int mgl_parsew(HMGL gr, HMPR p, const wchar_t *str, int pos);
void mgl_parse_text(HMGL gr, HMPR p, const char *str);
void mgl_parsew_text(HMGL gr, HMPR p, const wchar_t *str);
void mgl_restore_once(HMPR p);
void mgl_parser_allow_setsize(HMPR p, int a);
/*****************************************************************************/
/*		Setup mglGraph														 */
/*****************************************************************************/
void mgl_set_def_param(HMGL gr);
void mgl_set_palette(HMGL gr, const char *colors);
void mgl_set_pal_color(HMGL graph, int n, mreal r, mreal g, mreal b);
void mgl_set_pal_num(HMGL graph, int num);
void mgl_set_rotated_text(HMGL graph, int rotated);
void mgl_set_cut(HMGL graph, int cut);
void mgl_set_cut_box(HMGL gr, mreal x1,mreal y1,mreal z1,mreal x2,mreal y2,mreal z2);
void mgl_set_tick_len(HMGL graph, mreal len, mreal stt);
void mgl_set_tick_stl(HMGL gr, const char *stl, const char *sub);
void mgl_set_bar_width(HMGL graph, mreal width);
void mgl_set_base_line_width(HMGL gr, mreal size);
void mgl_set_mark_size(HMGL graph, mreal size);
void mgl_set_arrow_size(HMGL graph, mreal size);
void mgl_set_font_size(HMGL graph, mreal size);
void mgl_set_font_def(HMGL graph, const char *fnt);
void mgl_set_alpha_default(HMGL graph, mreal alpha);
void mgl_set_size(HMGL graph, int width, int height);
void mgl_set_axial_dir(HMGL graph, char dir);
void mgl_set_meshnum(HMGL graph, int num);
void mgl_set_zoom(HMGL gr, mreal x1, mreal y1, mreal x2, mreal y2);
void mgl_set_plotfactor(HMGL gr, mreal val);
void mgl_set_draw_face(HMGL gr, int enable);
void mgl_set_scheme(HMGL gr, const char *sch);
void mgl_load_font(HMGL gr, const char *name, const char *path);
void mgl_copy_font(HMGL gr, HMGL gr_from);
void mgl_restore_font(HMGL gr);
int mgl_get_warn(HMGL gr);
/*****************************************************************************/
/*		Export to file or to memory											 */
/*****************************************************************************/
void mgl_show_image(HMGL graph, const char *viewer, int keep);
void mgl_write_frame(HMGL graph, const char *fname,const char *descr);
void mgl_write_bmp(HMGL graph, const char *fname,const char *descr);
void mgl_write_jpg(HMGL graph, const char *fname,const char *descr);
void mgl_write_png(HMGL graph, const char *fname,const char *descr);
void mgl_write_png_solid(HMGL graph, const char *fname,const char *descr);
void mgl_write_eps(HMGL graph, const char *fname,const char *descr);
void mgl_write_svg(HMGL graph, const char *fname,const char *descr);
void mgl_write_idtf(HMGL graph, const char *fname,const char *descr);
void mgl_write_gif(HMGL graph, const char *fname,const char *descr);
void mgl_start_gif(HMGL graph, const char *fname,int ms);
void mgl_close_gif(HMGL graph);
const unsigned char *mgl_get_rgb(HMGL graph);
const unsigned char *mgl_get_rgba(HMGL graph);
int mgl_get_width(HMGL graph);
int mgl_get_height(HMGL graph);
/*****************************************************************************/
/*		Setup frames transparency (alpha) and lightning						 */
/*****************************************************************************/
int mgl_new_frame(HMGL graph);
void mgl_end_frame(HMGL graph);
int mgl_get_num_frame(HMGL graph);
void mgl_reset_frames(HMGL graph);
void mgl_set_transp_type(HMGL graph, int type);
void mgl_set_transp(HMGL graph, int enable);
void mgl_set_alpha(HMGL graph, int enable);
void mgl_set_fog(HMGL graph, mreal d, mreal dz);
void mgl_set_light(HMGL graph, int enable);
void mgl_set_light_n(HMGL gr, int n, int enable);
void mgl_add_light(HMGL graph, int n, mreal x, mreal y, mreal z, char c);
void mgl_add_light_rgb(HMGL graph, int n, mreal x, mreal y, mreal z, int infty, mreal r, mreal g, mreal b, mreal i);
void mgl_set_ambbr(HMGL gr, mreal i);
/*****************************************************************************/
/*		Scale and rotate													 */
/*****************************************************************************/
void mgl_mat_pop(HMGL gr);
void mgl_mat_push(HMGL gr);
void mgl_identity(HMGL graph, int rel);
void mgl_clf(HMGL graph);
void mgl_flush(HMGL gr);
void mgl_clf_rgb(HMGL graph, mreal r, mreal g, mreal b);
void mgl_subplot(HMGL graph, int nx,int ny,int m);
void mgl_subplot_d(HMGL graph, int nx,int ny,int m, mreal dx, mreal dy);
void mgl_subplot_s(HMGL graph, int nx,int ny,int m,const char *style);
void mgl_inplot(HMGL graph, mreal x1,mreal x2,mreal y1,mreal y2);
void mgl_relplot(HMGL graph, mreal x1,mreal x2,mreal y1,mreal y2);
void mgl_columnplot(HMGL graph, int num, int ind);
void mgl_columnplot_d(HMGL graph, int num, int ind, mreal d);
void mgl_stickplot(HMGL graph, int num, int ind, mreal tet, mreal phi);
void mgl_aspect(HMGL graph, mreal Ax,mreal Ay,mreal Az);
void mgl_rotate(HMGL graph, mreal TetX,mreal TetZ,mreal TetY);
void mgl_rotate_vector(HMGL graph, mreal Tet,mreal x,mreal y,mreal z);
void mgl_perspective(HMGL graph, mreal val);
/*****************************************************************************/
/*		Axis functions														 */
/*****************************************************************************/
void mgl_adjust_ticks(HMGL graph, const char *dir);
void mgl_set_ticks(HMGL graph, mreal DX, mreal DY, mreal DZ);
void mgl_set_subticks(HMGL graph, int NX, int NY, int NZ);
void mgl_set_ticks_dir(HMGL graph, char dir, mreal d, int ns, mreal org);
void mgl_set_ticks_val(HMGL graph, char dir, int n, double val, const char *lbl, ...);
void mgl_set_ticks_vals(HMGL graph, char dir, int n, mreal *val, const char **lbl);
void mgl_set_caxis(HMGL graph, mreal C1,mreal C2);
void mgl_set_axis(HMGL graph, mreal x1, mreal y1, mreal z1, mreal x2, mreal y2, mreal z2, mreal x0, mreal y0, mreal z0);
void mgl_set_axis_3d(HMGL graph, mreal x1, mreal y1, mreal z1, mreal x2, mreal y2, mreal z2);
void mgl_set_axis_2d(HMGL graph, mreal x1, mreal y1, mreal x2, mreal y2);
inline void mgl_set_ranges(HMGL graph, mreal x1, mreal x2, mreal y1, mreal y2, mreal z1, mreal z2)
{	mgl_set_axis_3d(graph, x1,y1,z1,x2,y2,z2);	};
void mgl_set_origin(HMGL graph, mreal x0, mreal y0, mreal z0);
void mgl_set_tick_origin(HMGL graph, mreal x0, mreal y0, mreal z0);
void mgl_set_crange(HMGL graph, const HMDT a, int add);
void mgl_set_xrange(HMGL graph, const HMDT a, int add);
void mgl_set_yrange(HMGL graph, const HMDT a, int add);
void mgl_set_zrange(HMGL graph, const HMDT a, int add);
void mgl_set_auto(HMGL graph, mreal x1, mreal x2, mreal y1, mreal y2, mreal z1, mreal z2);
void mgl_set_func(HMGL graph, const char *EqX,const char *EqY,const char *EqZ);
void mgl_set_func_ext(HMGL graph, const char *EqX,const char *EqY,const char *EqZ,const char *EqA);
void mgl_set_coor(HMGL gr, int how);
void mgl_set_ternary(HMGL gr, int enable);
void mgl_set_cutoff(HMGL graph, const char *EqC);
void mgl_box(HMGL graph, int ticks);
void mgl_box_str(HMGL graph, const char *col, int ticks);
void mgl_box_rgb(HMGL graph, mreal r, mreal g, mreal b, int ticks);
void mgl_axis(HMGL graph, const char *dir);
void mgl_axis_grid(HMGL graph, const char *dir,const char *pen);
void mgl_label(HMGL graph, char dir, const char *text);
void mgl_label_ext(HMGL graph, char dir, const char *text, mreal pos, mreal size, mreal shift);
void mgl_labelw_ext(HMGL graph, char dir, const wchar_t *text, mreal pos, mreal size, mreal shift);
void mgl_label_xy(HMGL graph, mreal x, mreal y, const char *text, const char *fnt, mreal size);
void mgl_labelw_xy(HMGL graph, mreal x, mreal y, const wchar_t *text, const char *fnt, mreal size);
void mgl_tune_ticks(HMGL graph, int tune, mreal fact_pos);
void mgl_set_xttw(HMGL graph, const wchar_t *templ);
void mgl_set_yttw(HMGL graph, const wchar_t *templ);
void mgl_set_zttw(HMGL graph, const wchar_t *templ);
void mgl_set_cttw(HMGL graph, const wchar_t *templ);
void mgl_set_xtt(HMGL graph, const char *templ);
void mgl_set_ytt(HMGL graph, const char *templ);
void mgl_set_ztt(HMGL graph, const char *templ);
void mgl_set_ctt(HMGL graph, const char *templ);
/*****************************************************************************/
/*		Simple drawing														 */
/*****************************************************************************/
void mgl_ball(HMGL graph, mreal x,mreal y,mreal z);
void mgl_ball_rgb(HMGL graph, mreal x, mreal y, mreal z, mreal r, mreal g, mreal b, mreal alpha);
void mgl_ball_str(HMGL graph, mreal x, mreal y, mreal z, char col);
void mgl_line(HMGL graph, mreal x1, mreal y1, mreal z1, mreal x2, mreal y2, mreal z2, const char *pen,int n);
void mgl_facex(HMGL graph, mreal x0, mreal y0, mreal z0, mreal wy, mreal wz, const char *stl, mreal dx, mreal dy);
void mgl_facey(HMGL graph, mreal x0, mreal y0, mreal z0, mreal wx, mreal wz, const char *stl, mreal dx, mreal dy);
void mgl_facez(HMGL graph, mreal x0, mreal y0, mreal z0, mreal wx, mreal wy, const char *stl, mreal dx, mreal dy);
void mgl_curve(HMGL graph, mreal x1, mreal y1, mreal z1, mreal dx1, mreal dy1, mreal dz1, mreal x2, mreal y2, mreal z2, mreal dx2, mreal dy2, mreal dz2, const char *pen,int n);

void mgl_puts(HMGL graph, mreal x, mreal y, mreal z,const char *text);
void mgl_putsw(HMGL graph, mreal x, mreal y, mreal z,const wchar_t *text);
void mgl_puts_dir(HMGL graph, mreal x, mreal y, mreal z, mreal dx, mreal dy, mreal dz, const char *text, mreal size);
void mgl_putsw_dir(HMGL graph, mreal x, mreal y, mreal z, mreal dx, mreal dy, mreal dz, const wchar_t *text, mreal size);
void mgl_text(HMGL graph, mreal x, mreal y, mreal z,const char *text);
void mgl_title(HMGL graph, const char *text, const char *fnt, mreal size);
void mgl_titlew(HMGL graph, const wchar_t *text, const char *fnt, mreal size);
void mgl_putsw_ext(HMGL graph, mreal x, mreal y, mreal z,const wchar_t *text,const char *font,mreal size,char dir);
void mgl_puts_ext(HMGL graph, mreal x, mreal y, mreal z,const char *text,const char *font,mreal size,char dir);
void mgl_text_ext(HMGL graph, mreal x, mreal y, mreal z,const char *text,const char *font,mreal size,char dir);
void mgl_colorbar(HMGL graph, const char *sch,int where);
void mgl_colorbar_ext(HMGL graph, const char *sch, int where, mreal x, mreal y, mreal w, mreal h);
void mgl_colorbar_val(HMGL graph, const HMDT dat, const char *sch,int where);
void mgl_simple_plot(HMGL graph, const HMDT a, int type, const char *stl);
void mgl_add_legend(HMGL graph, const char *text,const char *style);
void mgl_add_legendw(HMGL graph, const wchar_t *text,const char *style);
void mgl_clear_legend(HMGL graph);
void mgl_legend_xy(HMGL graph, mreal x, mreal y, const char *font, mreal size, mreal llen);
void mgl_legend(HMGL graph, int where, const char *font, mreal size, mreal llen);
void mgl_set_legend_box(HMGL gr, int enable);
void mgl_set_legend_marks(HMGL gr, int num);
/*****************************************************************************/
/*		1D plotting functions												 */
/*****************************************************************************/
void mgl_fplot(HMGL graph, const char *fy, const char *stl, int n);
void mgl_fplot_xyz(HMGL graph, const char *fx, const char *fy, const char *fz, const char *stl, int n);
void mgl_plot_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *pen);
void mgl_plot_xy(HMGL graph, const HMDT x, const HMDT y, const char *pen);
void mgl_plot(HMGL graph, const HMDT y, const char *pen);
void mgl_radar(HMGL graph, const HMDT a, const char *pen, mreal r);
void mgl_boxplot_xy(HMGL graph, const HMDT x, const HMDT a, const char *pen);
void mgl_boxplot(HMGL graph, const HMDT a, const char *pen);
void mgl_tens_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT c, const char *pen);
void mgl_tens_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT c, const char *pen);
void mgl_tens(HMGL graph, const HMDT y, const HMDT c,	const char *pen);
void mgl_area_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *pen);
void mgl_area_xy(HMGL graph, const HMDT x, const HMDT y, const char *pen);
void mgl_area_xys(HMGL graph, const HMDT x, const HMDT y, const char *pen);
void mgl_area_s(HMGL graph, const HMDT y, const char *pen);
void mgl_area(HMGL graph, const HMDT y, const char *pen);
void mgl_region_xy(HMGL graph, const HMDT x, const HMDT y1, const HMDT y2, const char *pen, int inside);
void mgl_region(HMGL graph, const HMDT y1, const HMDT y2, const char *pen, int inside);
void mgl_mark(HMGL graph, mreal x,mreal y,mreal z,char mark);
void mgl_stem_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *pen);
void mgl_stem_xy(HMGL graph, const HMDT x, const HMDT y, const char *pen);
void mgl_stem(HMGL graph, const HMDT y,	const char *pen);
void mgl_step_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *pen);
void mgl_step_xy(HMGL graph, const HMDT x, const HMDT y, const char *pen);
void mgl_step(HMGL graph, const HMDT y,	const char *pen);
void mgl_bars_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *pen);
void mgl_bars_xy(HMGL graph, const HMDT x, const HMDT y, const char *pen);
void mgl_bars(HMGL graph, const HMDT y,	const char *pen);
void mgl_barh_yx(HMGL graph, const HMDT y, const HMDT v, const char *pen);
void mgl_barh(HMGL graph, const HMDT v,	const char *pen);
/*****************************************************************************/
/*		Advanced 1D plotting functions												 */
/*****************************************************************************/
void mgl_torus(HMGL graph, const HMDT r, const HMDT z, const char *pen);
void mgl_text_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z,const char *text, const char *font, mreal size);
void mgl_text_xy(HMGL graph, const HMDT x, const HMDT y, const char *text, const char *font, mreal size);
void mgl_text_y(HMGL graph, const HMDT y, const char *text, const char *font, mreal size);
void mgl_chart(HMGL graph, const HMDT a, const char *col);
void mgl_error(HMGL graph, const HMDT y, const HMDT ey, const char *pen);
void mgl_error_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT ey, const char *pen);
void mgl_error_exy(HMGL graph, const HMDT x, const HMDT y, const HMDT ex, const HMDT ey, const char *pen);
void mgl_mark_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT r, const char *pen);
void mgl_mark_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT r, const char *pen);
void mgl_mark_y(HMGL graph, const HMDT y, const HMDT r, const char *pen);
void mgl_tube_xyzr(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT r, const char *pen);
void mgl_tube_xyr(HMGL graph, const HMDT x, const HMDT y, const HMDT r, const char *pen);
void mgl_tube_r(HMGL graph, const HMDT y, const HMDT r, const char *pen);
void mgl_tube_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, mreal r, const char *pen);
void mgl_tube_xy(HMGL graph, const HMDT x, const HMDT y, mreal r, const char *penl);
void mgl_tube(HMGL graph, const HMDT y, mreal r, const char *pen);

void mgl_textmark_xyzr(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT r, const char *text, const char *fnt);
void mgl_textmark_xyr(HMGL graph, const HMDT x, const HMDT y, const HMDT r, const char *text, const char *fnt);
void mgl_textmark_yr(HMGL graph, const HMDT y, const HMDT r, const char *text, const char *fnt);
void mgl_textmark(HMGL graph, const HMDT y, const char *text, const char *fnt);
void mgl_textmarkw_xyzr(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT r, const wchar_t *text, const char *fnt);
void mgl_textmarkw_xyr(HMGL graph, const HMDT x, const HMDT y, const HMDT r, const wchar_t *text, const char *fnt);
void mgl_textmarkw_yr(HMGL graph, const HMDT y, const HMDT r, const wchar_t *text, const char *fnt);
void mgl_textmarkw(HMGL graph, const HMDT y, const wchar_t *text, const char *fnt);
/*****************************************************************************/
/*		2D plotting functions												 */
/*****************************************************************************/
void mgl_fsurf(HMGL graph, const char *fz, const char *stl, int n);
void mgl_fsurf_xyz(HMGL graph, const char *fx, const char *fy, const char *fz, const char *stl, int n);
void mgl_grid_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *stl,mreal zVal);
void mgl_grid(HMGL graph, const HMDT a,const char *stl,mreal zVal);
void mgl_mesh_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch);
void mgl_mesh(HMGL graph, const HMDT z, const char *sch);
void mgl_fall_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch);
void mgl_fall(HMGL graph, const HMDT z, const char *sch);
void mgl_belt_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch);
void mgl_belt(HMGL graph, const HMDT z, const char *sch);
void mgl_surf_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch);
void mgl_surf(HMGL graph, const HMDT z, const char *sch);
void mgl_dens_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch,mreal zVal);
void mgl_dens(HMGL graph, const HMDT z, const char *sch,mreal zVal);
void mgl_boxs_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch,mreal zVal);
void mgl_boxs(HMGL graph, const HMDT z, const char *sch,mreal zVal);
void mgl_tile_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch);
void mgl_tile(HMGL graph, const HMDT z, const char *sch);
void mgl_tiles_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT r, const char *sch);
void mgl_tiles(HMGL graph, const HMDT z, const HMDT r, const char *sch);
void mgl_cont_xy_val(HMGL graph, const HMDT v, const HMDT x, const HMDT y, const HMDT z, const char *sch, mreal zVal);
void mgl_cont_val(HMGL graph, const HMDT v, const HMDT z, const char *sch,mreal zVal);
void mgl_cont_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch, int Num, mreal zVal);
void mgl_cont(HMGL graph, const HMDT z, const char *sch, int Num, mreal zVal);

void mgl_contf_xy_val(HMGL graph, const HMDT v, const HMDT x, const HMDT y, const HMDT z, const char *sch, mreal zVal);
void mgl_contf_val(HMGL graph, const HMDT v, const HMDT z, const char *sch,mreal zVal);
void mgl_contf_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch, int Num, mreal zVal);
void mgl_contf(HMGL graph, const HMDT z, const char *sch, int Num, mreal zVal);

void mgl_contd_xy_val(HMGL graph, const HMDT v, const HMDT x, const HMDT y, const HMDT z, const char *sch, mreal zVal);
void mgl_contd_val(HMGL graph, const HMDT v, const HMDT z, const char *sch,mreal zVal);
void mgl_contd_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const char *sch, int Num, mreal zVal);
void mgl_contd(HMGL graph, const HMDT z, const char *sch, int Num, mreal zVal);

void mgl_axial_xy_val(HMGL graph, const HMDT v, const HMDT x, const HMDT y, const HMDT a, const char *sch);
void mgl_axial_val(HMGL graph, const HMDT v, const HMDT a, const char *sch);
void mgl_axial_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT a, const char *sch, int Num);
void mgl_axial(HMGL graph, const HMDT a, const char *sch, int Num);
/*****************************************************************************/
/*		Dual plotting functions												 */
/*****************************************************************************/
void mgl_surfc_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT c, const char *sch);
void mgl_surfc(HMGL graph, const HMDT z, const HMDT c, const char *sch);
void mgl_surfa_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT c, const char *sch);
void mgl_surfa(HMGL graph, const HMDT z, const HMDT c, const char *sch);
void mgl_stfa_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT re, const HMDT im, int dn, const char *sch, mreal zVal);
void mgl_stfa(HMGL graph, const HMDT re, const HMDT im, int dn, const char *sch, mreal zVal);
void mgl_traj_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT ax, const HMDT ay, const char *sch,mreal zVal,mreal len);
void mgl_traj_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT ax, const HMDT ay, const HMDT az, const char *sch,mreal len);
void mgl_vect_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT ax, const HMDT ay, const char *sch,mreal zVal,int flag);
void mgl_vect_2d(HMGL graph, const HMDT ax, const HMDT ay, const char *sch,mreal zVal,int flag);
void mgl_vectl_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT ax, const HMDT ay, const char *sch,mreal zVal);
void mgl_vectl_2d(HMGL graph, const HMDT ax, const HMDT ay, const char *sch,mreal zVal);
void mgl_vectc_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT ax, const HMDT ay, const char *sch,mreal zVal);
void mgl_vectc_2d(HMGL graph, const HMDT ax, const HMDT ay, const char *sch,mreal zVal);
void mgl_vect_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT ax, const HMDT ay, const HMDT az, const char *sch,int flag);
void mgl_vect_3d(HMGL graph, const HMDT ax, const HMDT ay, const HMDT az, const char *sch,int flag);
void mgl_vectl_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT ax, const HMDT ay, const HMDT az, const char *sch);
void mgl_vectl_3d(HMGL graph, const HMDT ax, const HMDT ay, const HMDT az, const char *sch);
void mgl_vectc_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT ax, const HMDT ay, const HMDT az, const char *sch);
void mgl_vectc_3d(HMGL graph, const HMDT ax, const HMDT ay, const HMDT az, const char *sch);
void mgl_map_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT a, const HMDT b, const char *sch, int ks, int pnts);
void mgl_map(HMGL graph, const HMDT a, const HMDT b, const char *sch, int ks, int pnts);
void mgl_surf3a_xyz_val(HMGL graph, mreal Val, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const HMDT b, const char *stl);
void mgl_surf3a_val(HMGL graph, mreal Val, const HMDT a, const HMDT b, const char *stl);
void mgl_surf3a_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const HMDT b, const char *stl, int num);
void mgl_surf3a(HMGL graph, const HMDT a, const HMDT b, const char *stl, int num);
void mgl_surf3c_xyz_val(HMGL graph, mreal Val, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const HMDT b, const char *stl);
void mgl_surf3c_val(HMGL graph, mreal Val, const HMDT a, const HMDT b, const char *stl);
void mgl_surf3c_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const HMDT b,
			const char *stl, int num);
void mgl_surf3c(HMGL graph, const HMDT a, const HMDT b, const char *stl, int num);
void mgl_flow_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT ax, const HMDT ay, const char *sch, int num, int central, mreal zVal);
void mgl_flow_2d(HMGL graph, const HMDT ax, const HMDT ay, const char *sch, int num, int central, mreal zVal);
void mgl_flow_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT ax, const HMDT ay, const HMDT az, const char *sch, int num, int central);
void mgl_flow_3d(HMGL graph, const HMDT ax, const HMDT ay, const HMDT az, const char *sch, int num, int central);

void mgl_flowp_xy(HMGL graph, mreal x0, mreal y0, mreal z0, const HMDT x, const HMDT y, const HMDT ax, const HMDT ay, const char *sch);
void mgl_flowp_2d(HMGL graph, mreal x0, mreal y0, mreal z0, const HMDT ax, const HMDT ay, const char *sch);
void mgl_flowp_xyz(HMGL graph, mreal x0, mreal y0, mreal z0, const HMDT x, const HMDT y, const HMDT z, const HMDT ax, const HMDT ay, const HMDT az, const char *sch);
void mgl_flowp_3d(HMGL graph, mreal x0, mreal y0, mreal z0, const HMDT ax, const HMDT ay, const HMDT az, const char *sch);

void mgl_pipe_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT ax, const HMDT ay, const char *sch, mreal r0, int num, int central, mreal zVal);
void mgl_pipe_2d(HMGL graph, const HMDT ax, const HMDT ay, const char *sch, mreal r0, int num, int central, mreal zVal);
void mgl_pipe_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT ax, const HMDT ay, const HMDT az, const char *sch, mreal r0, int num, int central);
void mgl_pipe_3d(HMGL graph, const HMDT ax, const HMDT ay, const HMDT az, const char *sch, mreal r0, int num, int central);
void mgl_dew_xy(HMGL gr, const HMDT x, const HMDT y, const HMDT ax, const HMDT ay, const char *sch,mreal zVal);
void mgl_dew_2d(HMGL gr, const HMDT ax, const HMDT ay, const char *sch,mreal zVal);

void mgl_grad_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT ph, const char *sch, int num);
void mgl_grad_xy(HMGL graph, const HMDT x, const HMDT y, const HMDT ph, const char *sch, int num, mreal zVal);
void mgl_grad(HMGL graph, const HMDT ph, const char *sch, int num, mreal zVal);
/*****************************************************************************/
/*		3D plotting functions												 */
/*****************************************************************************/
void mgl_grid3_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, char dir, int sVal, const char *stl);
void mgl_grid3(HMGL graph, const HMDT a, char dir, int sVal, const char *stl);
void mgl_grid3_all_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *stl);
void mgl_grid3_all(HMGL graph, const HMDT a, const char *stl);
void mgl_dens3_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, char dir, int sVal, const char *stl);
void mgl_dens3(HMGL graph, const HMDT a, char dir, int sVal, const char *stl);
void mgl_dens3_all_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *stl);
void mgl_dens3_all(HMGL graph, const HMDT a, const char *stl);
void mgl_surf3_xyz_val(HMGL graph, mreal Val, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *stl);
void mgl_surf3_val(HMGL graph, mreal Val, const HMDT a, const char *stl);
void mgl_surf3_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *stl, int num);
void mgl_surf3(HMGL graph, const HMDT a, const char *stl, int num);
void mgl_cont3_xyz_val(HMGL graph, const HMDT v, const HMDT x, const HMDT y, const HMDT z, const HMDT a, char dir, int sVal, const char *sch);
void mgl_cont3_val(HMGL graph, const HMDT v, const HMDT a, char dir, int sVal, const char *sch);
void mgl_cont3_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, char dir, int sVal, const char *sch, int Num);
void mgl_cont3(HMGL graph, const HMDT a, char dir, int sVal, const char *sch, int Num);
void mgl_cont_all_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *sch, int Num);
void mgl_cont_all(HMGL graph, const HMDT a, const char *sch, int Num);
void mgl_cloudp_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *stl, mreal alpha);
void mgl_cloudp(HMGL graph, const HMDT a, const char *stl, mreal alpha);
void mgl_cloud_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *stl, mreal alpha);
void mgl_cloud(HMGL graph, const HMDT a, const char *stl, mreal alpha);
void mgl_contf3_xyz_val(HMGL graph, const HMDT v, const HMDT x, const HMDT y, const HMDT z, const HMDT a, char dir, int sVal, const char *sch);
void mgl_contf3_val(HMGL graph, const HMDT v, const HMDT a, char dir, int sVal, const char *sch);
void mgl_contf3_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, char dir, int sVal, const char *sch, int Num);
void mgl_contf3(HMGL graph, const HMDT a, char dir, int sVal, const char *sch, int Num);
void mgl_contf_all_xyz(HMGL graph, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *sch, int Num);
void mgl_contf_all(HMGL graph, const HMDT a, const char *sch, int Num);
void mgl_beam_val(HMGL graph, mreal Val, const HMDT tr, const HMDT g1, const HMDT g2, const HMDT a, mreal r, const char *stl, int norm);
void mgl_beam(HMGL graph, const HMDT tr, const HMDT g1, const HMDT g2, const HMDT a, mreal r, const char *stl, int norm, int num);
/*****************************************************************************/
/*		Triangular plotting functions											 */
/*****************************************************************************/
void mgl_triplot_xyzc(HMGL gr, const HMDT nums, const HMDT x, const HMDT y, const HMDT z, const HMDT c, const char *sch);
void mgl_triplot_xyz(HMGL gr, const HMDT nums, const HMDT x, const HMDT y, const HMDT z, const char *sch);
void mgl_triplot_xy(HMGL gr, const HMDT nums, const HMDT x, const HMDT y, const char *sch, mreal zVal);
void mgl_quadplot_xyzc(HMGL gr, const HMDT nums, const HMDT x, const HMDT y, const HMDT z, const HMDT c, const char *sch);
void mgl_quadplot_xyz(HMGL gr, const HMDT nums, const HMDT x, const HMDT y, const HMDT z, const char *sch);
void mgl_quadplot_xy(HMGL gr, const HMDT nums, const HMDT x, const HMDT y, const char *sch, mreal zVal);
void mgl_tricont_xyzcv(HMGL gr, const HMDT v, const HMDT nums, const HMDT x, const HMDT y, const HMDT z, const HMDT c, const char *sch, mreal zVal);
void mgl_tricont_xyzv(HMGL gr, const HMDT v, const HMDT nums, const HMDT x, const HMDT y, const HMDT z, const char *sch, mreal zVal);
void mgl_tricont_xyzc(HMGL gr, const HMDT nums, const HMDT x, const HMDT y, const HMDT z, const HMDT c, const char *sch, int n, mreal zVal);
void mgl_tricont_xyz(HMGL gr, const HMDT nums, const HMDT x, const HMDT y, const HMDT z, const char *sch, int n, mreal zVal);
void mgl_dots(HMGL gr, const HMDT x, const HMDT y, const HMDT z, const char *sch);
void mgl_dots_a(HMGL gr, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *sch);
void mgl_dots_tr(HMGL gr, const HMDT tr, const char *sch);
void mgl_crust(HMGL gr, const HMDT x, const HMDT y, const HMDT z, const char *sch, mreal er);
void mgl_crust_tr(HMGL gr, const HMDT tr, const char *sch, mreal er);
/*****************************************************************************/
/*		Combined plotting functions											 */
/*****************************************************************************/
void mgl_dens_x(HMGL graph, const HMDT a, const char *stl, mreal sVal);
void mgl_dens_y(HMGL graph, const HMDT a, const char *stl, mreal sVal);
void mgl_dens_z(HMGL graph, const HMDT a, const char *stl, mreal sVal);
void mgl_cont_x(HMGL graph, const HMDT a, const char *stl, mreal sVal, int Num);
void mgl_cont_y(HMGL graph, const HMDT a, const char *stl, mreal sVal, int Num);
void mgl_cont_z(HMGL graph, const HMDT a, const char *stl, mreal sVal, int Num);
void mgl_cont_x_val(HMGL graph, const HMDT v, const HMDT a, const char *stl, mreal sVal);
void mgl_cont_y_val(HMGL graph, const HMDT v, const HMDT a, const char *stl, mreal sVal);
void mgl_cont_z_val(HMGL graph, const HMDT v, const HMDT a, const char *stl, mreal sVal);
void mgl_contf_x(HMGL graph, const HMDT a, const char *stl, mreal sVal, int Num);
void mgl_contf_y(HMGL graph, const HMDT a, const char *stl, mreal sVal, int Num);
void mgl_contf_z(HMGL graph, const HMDT a, const char *stl, mreal sVal, int Num);
void mgl_contf_x_val(HMGL graph, const HMDT v, const HMDT a, const char *stl, mreal sVal);
void mgl_contf_y_val(HMGL graph, const HMDT v, const HMDT a, const char *stl, mreal sVal);
void mgl_contf_z_val(HMGL graph, const HMDT v, const HMDT a, const char *stl, mreal sVal);
/*****************************************************************************/
/*		Data creation functions												 */
/*****************************************************************************/
void mgl_data_rearrange(HMDT dat, int mx, int my, int mz);
void mgl_data_set_float(HMDT dat, const float *A,int NX,int NY,int NZ);
void mgl_data_set_double(HMDT dat, const double *A,int NX,int NY,int NZ);
void mgl_data_set_float2(HMDT d, const float **A,int N1,int N2);
void mgl_data_set_double2(HMDT d, const double **A,int N1,int N2);
void mgl_data_set_float3(HMDT d, const float ***A,int N1,int N2,int N3);
void mgl_data_set_double3(HMDT d, const double ***A,int N1,int N2,int N3);
void mgl_data_set(HMDT dat, const HMDT a);
void mgl_data_set_vector(HMDT dat, gsl_vector *v);
void mgl_data_set_matrix(HMDT dat, gsl_matrix *m);

mreal mgl_data_get_value(const HMDT dat, int i, int j, int k);
int mgl_data_get_nx(const HMDT dat);
int mgl_data_get_ny(const HMDT dat);
int mgl_data_get_nz(const HMDT dat);
void mgl_data_set_value(HMDT dat, mreal v, int i, int j, int k);
void mgl_data_set_values(HMDT dat, const char *val, int nx, int ny, int nz);
int mgl_data_read(HMDT dat, const char *fname);
int mgl_data_read_mat(HMDT dat, const char *fname, int dim);
int mgl_data_read_dim(HMDT dat, const char *fname,int mx,int my,int mz);
void mgl_data_save(HMDT dat, const char *fname,int ns);
void mgl_data_export(HMDT dat, const char *fname, const char *scheme,mreal v1,mreal v2,int ns);
void mgl_data_import(HMDT dat, const char *fname, const char *scheme,mreal v1,mreal v2);
void mgl_data_create(HMDT dat, int nx,int ny,int nz);
void mgl_data_transpose(HMDT dat, const char *dim);
void mgl_data_norm(HMDT dat, mreal v1,mreal v2,int sym,int dim);
void mgl_data_norm_slice(HMDT dat, mreal v1,mreal v2,char dir,int keep_en,int sym);
HMDT mgl_data_subdata(const HMDT dat, int xx,int yy,int zz);
HMDT mgl_data_subdata_ext(const HMDT dat, const HMDT xx, const HMDT yy, const HMDT zz);
HMDT mgl_data_column(const HMDT dat, const char *eq);
void mgl_data_set_id(HMDT d, const char *id);
void mgl_data_fill(HMDT dat, mreal x1,mreal x2,char dir);
void mgl_data_fill_eq(HMGL gr, HMDT dat, const char *eq, const HMDT vdat, const HMDT wdat);
void mgl_data_put_val(HMDT dat, mreal val, int i, int j, int k);
void mgl_data_put_dat(HMDT dat, const HMDT val, int i, int j, int k);
void mgl_data_modify(HMDT dat, const char *eq,int dim);
void mgl_data_modify_vw(HMDT dat, const char *eq,const HMDT vdat,const HMDT wdat);
void mgl_data_squeeze(HMDT dat, int rx,int ry,int rz,int smooth);
mreal mgl_data_max(const HMDT dat);
mreal mgl_data_min(const HMDT dat);
mreal *mgl_data_value(HMDT dat, int i,int j,int k);
const mreal *mgl_data_data(const HMDT dat);

mreal mgl_data_first(const HMDT dat, const char *cond, int *i, int *j, int *k);
mreal mgl_data_last(const HMDT dat, const char *cond, int *i, int *j, int *k);
int mgl_data_find(const HMDT dat, const char *cond, char dir, int i, int j, int k);
int mgl_data_find_any(const HMDT dat, const char *cond);
mreal mgl_data_max_int(const HMDT dat, int *i, int *j, int *k);
mreal mgl_data_max_real(const HMDT dat, mreal *x, mreal *y, mreal *z);
mreal mgl_data_min_int(const HMDT dat, int *i, int *j, int *k);
mreal mgl_data_min_real(const HMDT dat, mreal *x, mreal *y, mreal *z);
mreal mgl_data_momentum_mw(const HMDT dat, char dir, mreal *m, mreal *w);

HMDT mgl_data_combine(const HMDT dat1, const HMDT dat2);
void mgl_data_extend(HMDT dat, int n1, int n2);
void mgl_data_insert(HMDT dat, char dir, int at, int num);
void mgl_data_delete(HMDT dat, char dir, int at, int num);
/*****************************************************************************/
/*		Data manipulation functions											 */
/*****************************************************************************/
void mgl_data_smooth(HMDT dat, int Type,mreal delta,const char *dirs);
HMDT mgl_data_sum(const HMDT dat, const char *dir);
HMDT mgl_data_max_dir(const HMDT dat, const char *dir);
HMDT mgl_data_min_dir(const HMDT dat, const char *dir);
void mgl_data_cumsum(HMDT dat, const char *dir);
void mgl_data_integral(HMDT dat, const char *dir);
void mgl_data_diff(HMDT dat, const char *dir);
void mgl_data_diff_par(HMDT dat, const HMDT v1, const HMDT v2, const HMDT v3);
void mgl_data_diff2(HMDT dat, const char *dir);
void mgl_data_swap(HMDT dat, const char *dir);
void mgl_data_roll(HMDT dat, char dir, int num);
void mgl_data_mirror(HMDT dat, const char *dir);

void mgl_data_hankel(HMDT dat, const char *dir);
void mgl_data_sinfft(HMDT dat, const char *dir);
void mgl_data_cosfft(HMDT dat, const char *dir);
void mgl_data_fill_sample(HMDT dat, int num, const char *how);

mreal mgl_data_spline(const HMDT dat, mreal x,mreal y,mreal z);
mreal mgl_data_spline1(const HMDT dat, mreal x,mreal y,mreal z);
mreal mgl_data_linear(const HMDT dat, mreal x,mreal y,mreal z);
mreal mgl_data_linear1(const HMDT dat, mreal x,mreal y,mreal z);
HMDT mgl_data_resize(const HMDT dat, int mx,int my,int mz);
HMDT mgl_data_resize_box(const HMDT dat, int mx,int my,int mz,mreal x1,mreal x2,
	mreal y1,mreal y2,mreal z1,mreal z2);
HMDT mgl_data_hist(const HMDT dat, int n, mreal v1, mreal v2, int nsub);
HMDT mgl_data_hist_w(const HMDT dat, const HMDT weight, int n, mreal v1, mreal v2, int nsub);
HMDT mgl_data_momentum(const HMDT dat, char dir, const char *how);
HMDT mgl_data_evaluate_i(const HMDT dat, const HMDT idat, int norm);
HMDT mgl_data_evaluate_ij(const HMDT dat, const HMDT idat, const HMDT jdat, int norm);
HMDT mgl_data_evaluate_ijk(const HMDT dat, const HMDT idat, const HMDT jdat, const HMDT kdat, int norm);
void mgl_data_envelop(HMDT dat, char dir);
void mgl_data_sew(HMDT dat, const char *dirs, mreal da);
void mgl_data_crop(HMDT dat, int n1, int n2, char dir);
/*****************************************************************************/
/*		Data operations														 */
/*****************************************************************************/
void mgl_data_mul_dat(HMDT dat, const HMDT d);
void mgl_data_div_dat(HMDT dat, const HMDT d);
void mgl_data_add_dat(HMDT dat, const HMDT d);
void mgl_data_sub_dat(HMDT dat, const HMDT d);
void mgl_data_mul_num(HMDT dat, mreal d);
void mgl_data_div_num(HMDT dat, mreal d);
void mgl_data_add_num(HMDT dat, mreal d);
void mgl_data_sub_num(HMDT dat, mreal d);
/*****************************************************************************/
/*		Nonlinear fitting													 */
/*****************************************************************************/
void mgl_hist_x(HMGL gr, HMDT res, const HMDT x, const HMDT a);
void mgl_hist_xy(HMGL gr, HMDT res, const HMDT x, const HMDT y, const HMDT a);
void mgl_hist_xyz(HMGL gr, HMDT res, const HMDT x, const HMDT y, const HMDT z, const HMDT a);
/*****************************************************************************/
/*		Nonlinear fitting													 */
/*****************************************************************************/
mreal mgl_fit_1(HMGL gr, HMDT fit, const HMDT y, const char *eq, const char *var, mreal *ini);
mreal mgl_fit_2(HMGL gr, HMDT fit, const HMDT z, const char *eq, const char *var, mreal *ini);
mreal mgl_fit_3(HMGL gr, HMDT fit, const HMDT a, const char *eq, const char *var, mreal *ini);
mreal mgl_fit_xy(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const char *eq, const char *var, mreal *ini);
mreal mgl_fit_xyz(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT z, const char *eq, const char *var, mreal *ini);
mreal mgl_fit_xyza(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *eq, const char *var, mreal *ini);
mreal mgl_fit_ys(HMGL gr, HMDT fit, const HMDT y, const HMDT s, const char *eq, const char *var, mreal *ini);
mreal mgl_fit_xys(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT s, const char *eq, const char *var, mreal *ini);
mreal mgl_fit_xyzs(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT z, const HMDT s, const char *eq, const char *var, mreal *ini);
mreal mgl_fit_xyzas(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const HMDT s, const char *eq, const char *var, mreal *ini);

mreal mgl_fit_1_d(HMGL gr, HMDT fit, const HMDT y, const char *eq, const char *var, HMDT ini);
mreal mgl_fit_2_d(HMGL gr, HMDT fit, const HMDT z, const char *eq, const char *var, HMDT ini);
mreal mgl_fit_3_d(HMGL gr, HMDT fit, const HMDT a, const char *eq, const char *var, HMDT ini);
mreal mgl_fit_xy_d(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const char *eq, const char *var, HMDT ini);
mreal mgl_fit_xyz_d(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT z, const char *eq, const char *var, HMDT ini);
mreal mgl_fit_xyza_d(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const char *eq, const char *var, HMDT ini);
mreal mgl_fit_ys_d(HMGL gr, HMDT fit, const HMDT y, const HMDT s, const char *eq, const char *var, HMDT ini);
mreal mgl_fit_xys_d(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT s, const char *eq, const char *var, HMDT ini);
mreal mgl_fit_xyzs_d(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT z, const HMDT s, const char *eq, const char *var, HMDT ini);
mreal mgl_fit_xyzas_d(HMGL gr, HMDT fit, const HMDT x, const HMDT y, const HMDT z, const HMDT a, const HMDT s, const char *eq, const char *var, HMDT ini);

void mgl_puts_fit(HMGL gr, mreal x, mreal y, mreal z, const char *prefix, const char *font, mreal size);
const char *mgl_get_fit(HMGL gr);
/*****************************************************************************/
void mgl_sphere(HMGL graph, mreal x, mreal y, mreal z, mreal r, const char *stl);
void mgl_drop(HMGL graph, mreal x1, mreal y1, mreal z1, mreal x2, mreal y2, mreal z2, mreal r, const char *stl, mreal shift, mreal ap);
void mgl_cone(HMGL graph, mreal x1, mreal y1, mreal z1, mreal x2, mreal y2, mreal z2, mreal r1, mreal r2, const char *stl, int edge);

HMDT mgl_pde_solve(HMGL gr, const char *ham, const HMDT ini_re, const HMDT ini_im, mreal dz, mreal k0);
HMDT mgl_qo2d_solve(const char *ham, const HMDT ini_re, const HMDT ini_im, const HMDT ray, mreal r, mreal k0, HMDT xx, HMDT yy);
HMDT mgl_af2d_solve(const char *ham, const HMDT ini_re, const HMDT ini_im, const HMDT ray, mreal r, mreal k0, HMDT xx, HMDT yy);
HMDT mgl_ray_trace(const char *ham, mreal x0, mreal y0, mreal z0, mreal px, mreal py, mreal pz, mreal dt, mreal tmax);
HMDT mgl_jacobian_2d(const HMDT x, const HMDT y);
HMDT mgl_jacobian_3d(const HMDT x, const HMDT y, const HMDT z);
HMDT mgl_transform_a(const HMDT am, const HMDT ph, const char *tr);
HMDT mgl_transform(const HMDT re, const HMDT im, const char *tr);
HMDT mgl_data_stfa(const HMDT re, const HMDT im, int dn, char dir);

#ifdef __cplusplus
}
#endif

#endif /* _mgl_c_h_ */


#pragma once

// STL and std libs
#include <map>
#include <set>
#include <vector>
#include <list>
#include <memory>
#include <functional>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <chrono>
#include <type_traits>

// Guildline Support Library
#include <gsl.h>

//// boost and std extension
//#include <boost\signals2.hpp>
//#include <boost\any.hpp>
//#include <boost\range\iterator_range_core.hpp>
//#include <boost\range\adaptor\transformed.hpp>
//#include <boost\operators.hpp>
//#include <boost\format.hpp>
//#include <boost\filesystem.hpp>

#include <stride_range.h>
#include <tree.h>
#include <minmax>

#include "Math3D.h"
#include "SmartPointers.h"
#include "String.h"

//#if defined __AVX__
//#undef __AVX__ //#error Eigen have problem with AVX now
//#endif
//#define EIGEN_HAS_CXX11_MATH 1
//#define EIGEN_HAS_STD_RESULT_OF 1
//#define EIGEN_HAS_VARIADIC_TEMPLATES 1
//#include <Eigen\Dense>

namespace Causality
{
	using time_seconds = std::chrono::duration<double>;
	typedef uint64_t id_t;

	using std::string;
	using std::iterator_range;
	//using boost::sub_range;

	//namespace adaptors = boost::adaptors;

	using gsl::owner;
	using gsl::byte;
	using gsl::not_null;

	using stdx::tree_node;
	using stdx::foward_tree_node;
	using stdx::stride_range;
	using stdx::stride_iterator;

	using std::vector;
	using std::map;
	using std::function;
	using std::unique_ptr;
	using std::shared_ptr;
	using std::list;
	using std::weak_ptr;
}


/* gsl_splinalg.h
 *
 * Copyright (C) 2012-2014 Patrick Alken
 *
 * 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_SPLINALG_H__
#define __GSL_SPLINALG_H__

#include <gsl/gsl_math.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_spmatrix.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_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

/* iteration solver type */
typedef struct
{
  const char *name;
  void * (*alloc) (const size_t n, const size_t m);
  int (*iterate) (const gsl_spmatrix *A, const gsl_vector *b,
                  const double tol, gsl_vector *x, void *);
  double (*normr)(const void *);
  void (*free) (void *);
} gsl_splinalg_itersolve_type;

typedef struct
{
  const gsl_splinalg_itersolve_type * type;
  double normr; /* current residual norm || b - A x || */
  void * state;
} gsl_splinalg_itersolve;

/* available types */
GSL_VAR const gsl_splinalg_itersolve_type * gsl_splinalg_itersolve_gmres;

/*
 * Prototypes
 */
gsl_splinalg_itersolve *
gsl_splinalg_itersolve_alloc(const gsl_splinalg_itersolve_type *T,
                             const size_t n, const size_t m);
void gsl_splinalg_itersolve_free(gsl_splinalg_itersolve *w);
const char *gsl_splinalg_itersolve_name(const gsl_splinalg_itersolve *w);
int gsl_splinalg_itersolve_iterate(const gsl_spmatrix *A,
                                   const gsl_vector *b,
                                   const double tol, gsl_vector *x,
                                   gsl_splinalg_itersolve *w);
double gsl_splinalg_itersolve_normr(const gsl_splinalg_itersolve *w);

__END_DECLS

#endif /* __GSL_SPLINALG_H__ */


//
// Copyright (c) 2009, Markus Rickert
// 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.
//
// 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 HOLDER 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.
//

#include <chrono>
#include <memory>
#include <nlopt.h>
#include <random>
#include <utility>

#include "Exception.h"
#include "IterativeInverseKinematics.h"

namespace rl
{
	namespace mdl
	{
		class RL_MDL_EXPORT WeightedInverseKinematics : public IterativeInverseKinematics
		{
		public:
			class Exception : public ::rl::mdl::Exception
			{
			public:
				Exception(const ::nlopt_result& result);

				virtual ~Exception() throw();

				static void check(const ::nlopt_result& result);

				::nlopt_result getResult() const;

				virtual const char* what() const throw();

			protected:

			private:
				::nlopt_result result;
			};

			WeightedInverseKinematics(Kinematic* kinematic);

			virtual ~WeightedInverseKinematics();

			::rl::math::Real getFunctionToleranceAbsolute() const;

			::rl::math::Real getFunctionToleranceRelative() const;

			const ::rl::math::Vector& getLowerBound() const;

			::rl::math::Vector getOptimizationToleranceAbsolute() const;

			::rl::math::Real getOptimizationToleranceRelative() const;

			const ::rl::math::Vector& getUpperBound() const;

			void seed(const ::std::mt19937::result_type& value);

			void setEpsilon(const ::rl::math::Real& epsilon);

			void setFunctionToleranceAbsolute(const ::rl::math::Real& functionToleranceAbsolute);

			void setFunctionToleranceRelative(const ::rl::math::Real& functionToleranceRelative);

			void setLowerBound(const ::rl::math::Vector& lb);

			void setOptimizationToleranceAbsolute(const ::rl::math::Real& optimizationToleranceAbsolute);

			void setOptimizationToleranceAbsolute(const ::rl::math::Vector& optimizationToleranceAbsolute);

			void setOptimizationToleranceRelative(const ::rl::math::Real& optimizationToleranceRelative);

			void setUpperBound(const ::rl::math::Vector& ub);

			bool solve();

		protected:

		private:
			static double f(unsigned int n, const double* x, double* grad, void* data);

			::std::size_t iteration;

			::rl::math::Vector lb;

			::std::unique_ptr<::nlopt_opt_s, decltype(&::nlopt_destroy)> opt;

			::std::uniform_real_distribution<::rl::math::Real> randDistribution;

			::std::mt19937 randEngine;

			::rl::math::Vector ub;
		};
	}
}


#ifndef utils_h
#define utils_h

#include <ceed.h>
#include <petsc.h>

// Translate PetscMemType to CeedMemType
static inline CeedMemType MemTypeP2C(PetscMemType mem_type) {
  return PetscMemTypeDevice(mem_type) ? CEED_MEM_DEVICE : CEED_MEM_HOST;
}

#endif // utils_h


/* histogram/ntuple.c
 *
 * Copyright (C) 2000 Simone Piccardi
 *
 * 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* Jan/2001 Modified by Brian Gough. Minor changes for GSL */

#include <config.h>
#include <errno.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_ntuple.h>

/*
 * gsl_ntuple_open:
 * Initialize an ntuple structure and create the related file
 */

gsl_ntuple *
gsl_ntuple_create (char *filename, void *ntuple_data, size_t size)
{
  gsl_ntuple *ntuple = malloc (sizeof (gsl_ntuple));

  if (ntuple == 0)
    {
      GSL_ERROR_VAL ("failed to allocate space for ntuple struct",
		     GSL_ENOMEM, 0);
    }

  ntuple->ntuple_data = ntuple_data;
  ntuple->size = size;

  ntuple->file = fopen (filename, "wb");

  if (ntuple->file == 0)
    {
      free (ntuple);
      GSL_ERROR_VAL ("unable to create ntuple file", GSL_EFAILED, 0);
    }

  return ntuple;
}

/*
 * gsl_ntuple_open:
 * Initialize an ntuple structure and open the related file
 */

gsl_ntuple *
gsl_ntuple_open (char *filename, void *ntuple_data, size_t size)
{
  gsl_ntuple *ntuple = malloc (sizeof (gsl_ntuple));

  if (ntuple == 0)
    {
      GSL_ERROR_VAL ("failed to allocate space for ntuple struct",
		     GSL_ENOMEM, 0);
    }

  ntuple->ntuple_data = ntuple_data;
  ntuple->size = size;

  ntuple->file = fopen (filename, "rb");

  if (ntuple->file == 0)
    {
      free (ntuple);
      GSL_ERROR_VAL ("unable to open ntuple file for reading",
                     GSL_EFAILED, 0);
    }

  return ntuple;
}

/*
 * gsl_ntuple_write:
 * write to file a data row, must be used in a loop!
 */

int
gsl_ntuple_write (gsl_ntuple * ntuple)
{
  size_t nwrite;

  nwrite = fwrite (ntuple->ntuple_data, ntuple->size,
		   1, ntuple->file);

  if (nwrite != 1)
    {
      GSL_ERROR ("failed to write ntuple entry to file", GSL_EFAILED);
    }

  return GSL_SUCCESS;
}

/* the following function is a synonym for gsl_ntuple_write */

int
gsl_ntuple_bookdata (gsl_ntuple * ntuple)
{
  return gsl_ntuple_write (ntuple);
}

/*
 * gsl_ntuple_read:
 * read form file a data row, must be used in a loop!
 */

int
gsl_ntuple_read (gsl_ntuple * ntuple)
{
  size_t nread;

  nread = fread (ntuple->ntuple_data, ntuple->size, 1, ntuple->file);

  if (nread == 0 && feof(ntuple->file))
    {
      return GSL_EOF;
    }

  if (nread != 1)
    {
      GSL_ERROR ("failed to read ntuple entry from file", GSL_EFAILED);
    }

  return GSL_SUCCESS;
}

/*
 * gsl_ntuple_project:
 * fill an histogram with an ntuple file contents, use
 * SelVal and SelFunc user defined functions to get
 * the value to book and the selection funtion
 */

#define EVAL(f,x) ((*((f)->function))(x,(f)->params))

int
gsl_ntuple_project (gsl_histogram * h, gsl_ntuple * ntuple,
                    gsl_ntuple_value_fn * value_func,
                    gsl_ntuple_select_fn * select_func)
{
  size_t nread;

  do
    {
      nread = fread (ntuple->ntuple_data, ntuple->size,
                     1, ntuple->file);

      if (nread == 0 && feof(ntuple->file))
        {
          break ;
        }

      if (nread != 1)
        {
	  GSL_ERROR ("failed to read ntuple for projection", GSL_EFAILED);
	}

      if (EVAL(select_func, ntuple->ntuple_data))
	{
	  gsl_histogram_increment (h, EVAL(value_func, ntuple->ntuple_data));
	}
    }
  while (1);

  return GSL_SUCCESS;
}

/*
 * gsl_ntuple_close:
 * close the ntuple file and free the memory
 */

int
gsl_ntuple_close (gsl_ntuple * ntuple)
{
  int status = fclose (ntuple->file);

  if (status)
    {
      GSL_ERROR ("failed to close ntuple file", GSL_EFAILED);
    }

  free (ntuple);

  return GSL_SUCCESS;
}


/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
**                                                                                **
** This file forms part of the Underworld geophysics modelling application.         **
**                                                                                **
** For full license and copyright information, please refer to the LICENSE.md file  **
** located at the project root, or contact the authors.                             **
**                                                                                **
**~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <mpi.h>
#include <petsc.h>
#include <petscvec.h>
#include <petscmat.h>
#include <petscksp.h>
#include <petscpc.h>
#include <petscsnes.h>

#include <petscversion.h>
#if ( (PETSC_VERSION_MAJOR >= 3) && (PETSC_VERSION_MINOR >=3) )
  #if (PETSC_VERSION_MINOR >=6)
     #include <petsc/private/kspimpl.h>
  #else
     #include <petsc-private/kspimpl.h>   /*I "petscksp.h" I*/
     //#include "petsc-private/kspimpl.h"
  #endif
#else
  #include "private/kspimpl.h"   /*I "petscksp.h" I*/
#endif

#include <StGermain/libStGermain/src/StGermain.h>
#include <StgDomain/libStgDomain/src/StgDomain.h>
#include <StgFEM/libStgFEM/src/StgFEM.h>
#include <PICellerator/libPICellerator/src/PICellerator.h>
#include <Underworld/libUnderworld/src/Underworld.h>
#include "Solvers/SLE/src/SLE.h" /* to give the AugLagStokes_SLE type */
#include "Solvers/KSPSolvers/src/KSPSolvers.h"

#include "BSSCR.h"
#include "createK2.h"
#include "writeMatVec.h"
#include "ksp_pressure_nullspace.h"

#define KSPBSSCR         "bsscr"

EXTERN_C_BEGIN
EXTERN PetscErrorCode PETSCKSP_DLLEXPORT KSPCreate_BSSCR(KSP);
EXTERN_C_END

PetscErrorCode BSSCR_DRIVER_auglag( KSP ksp, Mat stokes_A, Vec stokes_x, Vec stokes_b, Mat approxS,
                                    MatStokesBlockScaling BA, PetscTruth sym, KSP_BSSCR * bsscrp_self );
PetscErrorCode BSSCR_DRIVER_flex( KSP ksp, Mat stokes_A, Vec stokes_x, Vec stokes_b, Mat approxS, KSP ksp_K,
                                  MatStokesBlockScaling BA, PetscTruth sym, KSP_BSSCR * bsscrp_self );

/*************************************************************************************************/
/****** START Helper Functions *******************************************************************/
#define BSSCR_GetPetscMatrix( matrix ) ( (Mat)(matrix) )
/****** END Helper Functions *********************************************************************/
/*************************************************************************************************/
typedef struct {
    void *ctx;
    KSP_BSSCR * bsscr;
} BSSCR_KSPConverged_Ctx;

/*************************************************************************************************/
/*************************************************************************************************/

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPSetConvergenceMinIts"
PetscErrorCode BSSCR_KSPSetConvergenceMinIts(KSP ksp, PetscInt n, KSP_BSSCR * bsscr)
{
      BSSCR_KSPConverged_Ctx *ctx;
      PetscErrorCode ierr;

      PetscFunctionBegin;

      bsscr->min_it = n; /* set minimum its */

#if ( (PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR >= 5 ) )
      ierr = Stg_PetscNew(BSSCR_KSPConverged_Ctx,&ctx);CHKERRQ(ierr);
      ierr = KSPConvergedDefaultCreate(&ctx->ctx);CHKERRQ(ierr);
      ctx->bsscr=bsscr;
      ierr = KSPSetConvergenceTest(ksp,BSSCR_KSPConverged,ctx,BSSCR_KSPConverged_Destroy);CHKERRQ(ierr);
#endif
#if ( (PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR <=4 ) )
      ierr = Stg_PetscNew(BSSCR_KSPConverged_Ctx,&ctx);CHKERRQ(ierr);
      ierr = KSPDefaultConvergedCreate(&ctx->ctx);CHKERRQ(ierr);
      ctx->bsscr=bsscr;
      ierr = KSPSetConvergenceTest(ksp,BSSCR_KSPConverged,ctx,BSSCR_KSPConverged_Destroy);CHKERRQ(ierr);
#endif
#if ( PETSC_VERSION_MAJOR < 3)
      ierr = KSPSetConvergenceTest(ksp,BSSCR_KSPConverged,(void*)bsscr);CHKERRQ(ierr);
#endif

      PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPConverged"
PetscErrorCode BSSCR_KSPConverged(KSP ksp,PetscInt n,PetscReal rnorm,KSPConvergedReason *reason,void *cctx)
{
  PetscErrorCode           ierr;
#if(PETSC_VERSION_MAJOR == 3)
  BSSCR_KSPConverged_Ctx  *ctx = (BSSCR_KSPConverged_Ctx *)cctx;
  KSP_BSSCR               *bsscr = ctx->bsscr;
#else
  KSP_BSSCR               *bsscr = (KSP_BSSCR*)cctx;
#endif

  PetscFunctionBegin;
#if ( (PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR >=5 ) )
  ierr = KSPConvergedDefault(ksp,n,rnorm,reason,ctx->ctx);CHKERRQ(ierr);
#endif
#if ( (PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR <=4 ) )
  ierr = KSPDefaultConverged(ksp,n,rnorm,reason,ctx->ctx);CHKERRQ(ierr);
#endif
#if ( PETSC_VERSION_MAJOR < 3)
  ierr = KSPDefaultConverged(ksp,n,rnorm,reason,cctx);CHKERRQ(ierr);
#endif
  if (*reason) {
    ierr = PetscInfo2(ksp,"default convergence test KSP iterations=%D, rnorm=%G\n",n,rnorm);CHKERRQ(ierr);
  }
  if(ksp->its < bsscr->min_it){
      ksp->reason          = KSP_CONVERGED_ITERATING;
  }
  PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPConverged_Destroy"
PetscErrorCode BSSCR_KSPConverged_Destroy(void *cctx)
{
  BSSCR_KSPConverged_Ctx *ctx = (BSSCR_KSPConverged_Ctx *)cctx;
  PetscErrorCode           ierr;

  PetscFunctionBegin;
#if ( (PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR >=5 ) )
  ierr = KSPConvergedDefaultDestroy(ctx->ctx);CHKERRQ(ierr);
#else
  ierr = KSPDefaultConvergedDestroy(ctx->ctx);CHKERRQ(ierr);
#endif
  ierr = PetscFree(ctx);CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "KSPRegisterBSSCR"
PetscErrorCode PETSCKSP_DLLEXPORT KSPRegisterBSSCR(const char path[])
{
    PetscErrorCode ierr;

    PetscFunctionBegin;
    ierr = Stg_KSPRegister(KSPBSSCR, path, "KSPCreate_BSSCR", KSPCreate_BSSCR );CHKERRQ(ierr);
    PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "KSPSolve_BSSCR"
PetscErrorCode  KSPSolve_BSSCR(KSP ksp)
{
    Mat            Amat,Pmat; /* Stokes Matrix and it's Preconditioner matrix: Both 2x2 PetscExt block matrices */
    Vec            B, X; /* rhs and solution vectors */
    //MatStructure   pflag;
    PetscErrorCode ierr;
    KSP_BSSCR *    bsscr;
    Stokes_SLE *    SLE;
    //PETScMGSolver * MG;
    Mat K,D,ApproxS;
    MatStokesBlockScaling BA;
    PetscTruth flg, sym, augment;
    double TotalSolveTime;

    PetscFunctionBegin;

    TotalSolveTime = MPI_Wtime();

    PetscPrintf( PETSC_COMM_WORLD, "\nBSSCR -- Block Stokes Schur Compliment Reduction Solver \n");
    /** Get the stokes Block matrix and its preconditioner matrix */
    ierr = Stg_PCGetOperators(ksp->pc,&Amat,&Pmat,PETSC_NULL);CHKERRQ(ierr);

    /** In Petsc proper, KSP's ksp->data is usually set in KSPCreate_XXX function.
        Here it is set in the _StokesBlockKSPInterface_Solve function instead so that we can ensure that the solver
        has everything it needs */

    bsscr         = (KSP_BSSCR*)ksp->data;
    //MG            = (PETScMGSolver*)bsscr->mg;
    SLE           = (Stokes_SLE*)bsscr->st_sle;
    X             = ksp->vec_sol;
    B             = ksp->vec_rhs;

    if( bsscr->do_scaling ){
        (*bsscr->scale)(ksp); /* scales everything including the UW preconditioner */
        BA =  bsscr->BA;
    }

    if( (bsscr->k2type != 0) ){
      if(bsscr->buildK2 != PETSC_NULL) {
            (*bsscr->buildK2)(ksp); /* building K2 from scaled version of stokes operators: K2 lives on bsscr struct = ksp->data */
        }
    }

    /* get sub matrix / vector objects */
    MatNestGetSubMat( Amat, 0,0, &K );
    /* Underworld preconditioner matrix*/
    ApproxS = PETSC_NULL;
    if( ((StokesBlockKSPInterface*)SLE->solver)->preconditioner ) { /* SLE->solver->st_sle == SLE here, by the way */
        StiffnessMatrix *preconditioner;
        preconditioner = ((StokesBlockKSPInterface*)SLE->solver)->preconditioner;
        ApproxS = BSSCR_GetPetscMatrix( preconditioner->matrix );
    }

    sym = bsscr->DIsSym;

    MatNestGetSubMat( Amat, 1,0, &D );if(!D){ PetscPrintf( PETSC_COMM_WORLD, "D does not exist but should!!\n"); exit(1); }

    /**********************************************************/
    /******* SOLVE!! ******************************************/
    /**********************************************************/

    flg = PETSC_FALSE;
    augment = PETSC_TRUE;
    PetscOptionsGetTruth(PETSC_NULL, "-augmented_lagrangian", &augment, &flg);
    BSSCR_DRIVER_auglag( ksp, Amat, X, B, ApproxS, BA, sym, bsscr );

    /**********************************************************/
    /***** END SOLVE!! ****************************************/
    /**********************************************************/
    if( bsscr->do_scaling ){
        (*bsscr->unscale)(ksp);  }
    if( (bsscr->k2type != 0) && bsscr->K2 != PETSC_NULL ){
        if(bsscr->k2type != K2_SLE){/* don't destroy here, as in this case, K2 is just pointing to an existing matrix on the SLE */
            Stg_MatDestroy(&bsscr->K2 );
        }
        bsscr->K2built = PETSC_FALSE;
        bsscr->K2 = PETSC_NULL;  }

    ksp->reason = KSP_CONVERGED_RTOL;

    TotalSolveTime =  MPI_Wtime() - TotalSolveTime;
    PetscPrintf( PETSC_COMM_WORLD, "  Total BSSCR Linear solve time: %lf seconds\n\n", TotalSolveTime);
    bsscr->solver->stats.total_time=TotalSolveTime;
    PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "KSPDestroy_BSSCR"
PetscErrorCode KSPDestroy_BSSCR(KSP ksp)
{
    KSP_BSSCR     *bsscr = (KSP_BSSCR *)ksp->data;
    Mat            K2=bsscr->K2;
    Vec            t,v;
    MatStokesBlockScaling BA=bsscr->BA;
    PetscErrorCode ierr;

    PetscFunctionBegin;

    t=bsscr->t;
    v=bsscr->v;
    if ( v ){ Stg_VecDestroy(&v); }
    if ( t ){ Stg_VecDestroy(&t); }
    if( K2 ){ Stg_MatDestroy(&K2 ); }/* shouldn't need this now */
    if(BA) BSSCR_MatStokesBlockScalingDestroy( BA );
    ierr = PetscFree(ksp->data);CHKERRQ(ierr);

    PetscFunctionReturn(0);
}
static const char *K2Types[] = {"NULL","DGMGD","GMG","GG","SLE","K2Type","K2_",0};
#undef __FUNCT__
#define __FUNCT__ "KSPSetFromOptions_BSSCR"
#if ( (PETSC_VERSION_MAJOR >= 3) && (PETSC_VERSION_MINOR <6) )
PetscErrorCode KSPSetFromOptions_BSSCR(KSP ksp)
{

    PetscTruth  flg;
    KSP_BSSCR  *bsscr = (KSP_BSSCR *)ksp->data;
    PetscErrorCode ierr;
    PetscFunctionBegin;
    ierr = PetscOptionsHead("KSP BSSCR options");CHKERRQ(ierr);
    /* if this ksp has a prefix "XXX_" it will be automatically added to the options. e.g. -ksp_test -> -XXX_ksp_test */
    /* ierr = PetscOptionsTruth("-ksp_test","Test KSP flag","nil",PETSC_FALSE,&test,PETSC_NULL);CHKERRQ(ierr); */
    /* if(test){ PetscPrintf( PETSC_COMM_WORLD,  "\n\n-----  test flag set  ------\n\n"); } */
    ierr = PetscOptionsEnum("-ksp_k2_type","Augmented Lagrangian matrix type","",K2Types, bsscr->k2type,(PetscEnum*)&bsscr->k2type,&flg);CHKERRQ(ierr);
    //if(flg){  PetscPrintf( PETSC_COMM_WORLD,  "-----  k2 type is  ------\n"); }
    ierr = PetscOptionsTail();CHKERRQ(ierr);
    PetscFunctionReturn(0);
}
#else
PetscErrorCode KSPSetFromOptions_BSSCR(Stg_PetscOptions *PetscOptionsObject, KSP ksp)
{

    PetscTruth  flg;
    KSP_BSSCR  *bsscr = (KSP_BSSCR *)ksp->data;
    PetscErrorCode ierr;
    PetscFunctionBegin;
    ierr = PetscOptionsHead(PetscOptionsObject,"KSP BSSCR options");CHKERRQ(ierr);
    /* if this ksp has a prefix "XXX_" it will be automatically added to the options. e.g. -ksp_test -> -XXX_ksp_test */
    /* ierr = PetscOptionsTruth("-ksp_test","Test KSP flag","nil",PETSC_FALSE,&test,PETSC_NULL);CHKERRQ(ierr); */
    /* if(test){ PetscPrintf( PETSC_COMM_WORLD,  "\n\n-----  test flag set  ------\n\n"); } */
    ierr = PetscOptionsEnum("-ksp_k2_type","Augmented Lagrangian matrix type","",K2Types, bsscr->k2type,(PetscEnum*)&bsscr->k2type,&flg);CHKERRQ(ierr);
    //if(flg){  PetscPrintf( PETSC_COMM_WORLD,  "-----  k2 type is  ------\n"); }
    ierr = PetscOptionsTail();CHKERRQ(ierr);
    PetscFunctionReturn(0);
}
#endif

#undef __FUNCT__
#define __FUNCT__ "KSPView_BSSCR"
PetscErrorCode KSPView_BSSCR(KSP ksp,PetscViewer viewer)
{
    PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "KSPSetUp_BSSCR"
PetscErrorCode KSPSetUp_BSSCR(KSP ksp)
{
    KSP_BSSCR  *bsscr = (KSP_BSSCR *)ksp->data;
    Mat K;
    Stokes_SLE*  stokesSLE  = (Stokes_SLE*)bsscr->st_sle;
    PetscTruth ismumps,augment,scale,konly,found,conp,checkerp;

    PetscFunctionBegin;

    BSSCR_PetscExtStokesSolversInitialize();

    K = stokesSLE->kStiffMat->matrix;
    bsscr->K2=PETSC_NULL;

    BSSCR_MatStokesBlockScalingCreate( &(bsscr->BA) );/* allocate memory for scaling struct */
    found = PETSC_FALSE;
    augment = PETSC_TRUE;
    PetscOptionsGetTruth(PETSC_NULL, "-augmented_lagrangian", &augment, &found);
    if(augment){
        bsscr->buildK2 = bsscr_buildK2; }
    else {
        bsscr->buildK2 = PETSC_NULL; }

    /***************************************************************************************************************/
    /** Do scaling *************************************************************************************************/
    /***************************************************************************************************************/
    found = PETSC_FALSE;
    scale = PETSC_FALSE;/* scaling off by default */
    PetscOptionsGetTruth(PETSC_NULL, "-rescale_equations", &scale, &found);
    Stg_PetscObjectTypeCompare((PetscObject)K, "mataijmumps", &ismumps);/** older versions of petsc have this */
    if(ismumps && scale){
        PetscPrintf( PETSC_COMM_WORLD, "\t* Not applying scaling to matrices as MatGetRowMax operation not defined for MATAIJMUMPS matrix type \n");
        scale = PETSC_FALSE;
    }
    if( scale ) {
        bsscr->scale       = KSPScale_BSSCR;
        bsscr->unscale     = KSPUnscale_BSSCR;
        bsscr->do_scaling  = PETSC_TRUE;
        bsscr->scaletype   = KONLY;
        konly = PETSC_TRUE;
        found = PETSC_FALSE;
        PetscOptionsGetTruth(PETSC_NULL, "-k_scale_only", &konly, &found);
        if(!konly){ bsscr->scaletype = DEFAULT; }
    }

    /***************************************************************************************************************/
    /**  Set up functions for building Pressure Null Space Vectors *************************************************/
    /***************************************************************************************************************/
    found = PETSC_FALSE;
    checkerp = PETSC_FALSE;
    PetscOptionsGetTruth(PETSC_NULL, "-remove_checkerboard_pressure_null_space", &checkerp, &found );
    if(checkerp){
        bsscr->check_cb_pressureNS    = PETSC_TRUE;
        bsscr->check_pressureNS       = PETSC_TRUE;
        bsscr->buildPNS               = KSPBuildPressure_CB_Nullspace_BSSCR;
    }
    found = PETSC_FALSE;
    conp = PETSC_FALSE;
    PetscOptionsGetTruth(PETSC_NULL, "-remove_constant_pressure_null_space", &conp, &found );
    if(conp){
        bsscr->check_const_pressureNS = PETSC_TRUE;
        bsscr->check_pressureNS       = PETSC_TRUE;
        bsscr->buildPNS               = KSPBuildPressure_Const_Nullspace_BSSCR;
    }
    /***************************************************************************************************************/
    PetscFunctionReturn(0);
}

EXTERN_C_BEGIN
#undef __FUNCT__
#define __FUNCT__ "KSPCreate_BSSCR"
PetscErrorCode PETSCKSP_DLLEXPORT KSPCreate_BSSCR(KSP ksp)
{
    KSP_BSSCR  *bsscr;
    PetscErrorCode ierr;
    PetscFunctionBegin;
    ierr = Stg_PetscNew(KSP_BSSCR,&bsscr);CHKERRQ(ierr);
    ierr = PetscLogObjectMemory((PetscObject)ksp,sizeof(KSP_BSSCR));CHKERRQ(ierr);
    //ierr = PetscNewLog(ksp,KSP_BSSCR,&bsscr);CHKERRQ(ierr);
    ksp->data                              = (void*)bsscr;

    #if ( (PETSC_VERSION_MAJOR >= 3) && (PETSC_VERSION_MINOR >= 2 ) )
    ierr = KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,0);CHKERRQ(ierr);
    ierr = KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,1);CHKERRQ(ierr);
    ierr = KSPSetSupportedNorm(ksp,KSP_NORM_NATURAL,PC_LEFT,0);CHKERRQ(ierr);
    ierr = KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_LEFT,1);CHKERRQ(ierr);
    #endif
    /*
       Sets the functions that are associated with this data structure
       (in C++ this is the same as defining virtual functions)
    */
    ksp->ops->setup                = KSPSetUp_BSSCR;
    ksp->ops->solve                = KSPSolve_BSSCR;
    ksp->ops->destroy              = KSPDestroy_BSSCR;
    ksp->ops->view                 = KSPView_BSSCR;
    ksp->ops->setfromoptions       = KSPSetFromOptions_BSSCR;
    ksp->ops->buildsolution        = KSPDefaultBuildSolution;
    ksp->ops->buildresidual        = KSPDefaultBuildResidual;

//    bsscr->k2type=K2_GMG;
    bsscr->k2type      = 0;
    bsscr->do_scaling  = PETSC_FALSE;
    bsscr->scaled      = PETSC_FALSE;
    bsscr->K2built     = PETSC_FALSE;
    bsscr->check_cb_pressureNS     = PETSC_FALSE;/* checker board nullspace */
    bsscr->check_const_pressureNS  = PETSC_FALSE;/* constant nullspace */
    bsscr->check_pressureNS        = PETSC_FALSE;/* is true if either of above two are true */
    bsscr->t           = NULL;/* null space vectors for pressure */
    bsscr->v           = NULL;
    bsscr->nstol       = 1e-7;/* null space detection tolerance */
    bsscr->uStar       = NULL;
    bsscr->been_here   = 0;
    PetscFunctionReturn(0);
}
EXTERN_C_END


#include <config.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_vector.h>

/* Compile all the inline matrix functions */

#define COMPILE_INLINE_STATIC
#include "build.h"
#include <gsl/gsl_matrix.h>


#include <gsl/gsl_math.h>
#include "gsl_cblas.h"
#include "cblas.h"

void
cblas_dcopy (const int N, const double *X, const int incX, double *Y,
	     const int incY)
{
#define BASE double
#include "source_copy_r.h"
#undef BASE
}


/* interpolation/gsl_interp.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman
 *
 * 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 2 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.
 */

/* Author:  G. Jungman
 */
#ifndef __GSL_INTERP_H__
#define __GSL_INTERP_H__
#include <stdlib.h>
#include <gsl/gsl_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

/* evaluation accelerator */
typedef struct {
  size_t  cache;        /* cache of index   */
  size_t  miss_count;   /* keep statistics  */
  size_t  hit_count;
}
gsl_interp_accel;

/* interpolation object type */
typedef struct {
  const char * name;
  unsigned int min_size;
  void *  (*alloc) (size_t size);
  int     (*init)    (void *, const double xa[], const double ya[], size_t size);
  int     (*eval)    (const void *, const double xa[], const double ya[], size_t size, double x, gsl_interp_accel *, double * y);
  int     (*eval_deriv)  (const void *, const double xa[], const double ya[], size_t size, double x, gsl_interp_accel *, double * y_p);
  int     (*eval_deriv2) (const void *, const double xa[], const double ya[], size_t size, double x, gsl_interp_accel *, double * y_pp);
  int     (*eval_integ)  (const void *, const double xa[], const double ya[], size_t size, gsl_interp_accel *, double a, double b, double * result);
  void    (*free)         (void *);

} gsl_interp_type;

/* general interpolation object */
typedef struct {
  const gsl_interp_type * type;
  double  xmin;
  double  xmax;
  size_t  size;
  void * state;
} gsl_interp;

/* available types */
GSL_VAR const gsl_interp_type * gsl_interp_linear;
GSL_VAR const gsl_interp_type * gsl_interp_polynomial;
GSL_VAR const gsl_interp_type * gsl_interp_cspline;
GSL_VAR const gsl_interp_type * gsl_interp_cspline_periodic;
GSL_VAR const gsl_interp_type * gsl_interp_akima;
GSL_VAR const gsl_interp_type * gsl_interp_akima_periodic;

gsl_interp_accel *
gsl_interp_accel_alloc(void);

size_t
gsl_interp_accel_find(gsl_interp_accel * a, const double x_array[], size_t size, double x);

int
gsl_interp_accel_reset (gsl_interp_accel * a);

void
gsl_interp_accel_free(gsl_interp_accel * a);

gsl_interp *
gsl_interp_alloc(const gsl_interp_type * T, size_t n);

int
gsl_interp_init(gsl_interp * obj, const double xa[], const double ya[], size_t size);

const char * gsl_interp_name(const gsl_interp * interp);
unsigned int gsl_interp_min_size(const gsl_interp * interp);

int
gsl_interp_eval_e(const gsl_interp * obj,
                  const double xa[], const double ya[], double x,
                  gsl_interp_accel * a, double * y);

double
gsl_interp_eval(const gsl_interp * obj,
                const double xa[], const double ya[], double x,
                gsl_interp_accel * a);

int
gsl_interp_eval_deriv_e(const gsl_interp * obj,
                        const double xa[], const double ya[], double x,
                        gsl_interp_accel * a,
                        double * d);

double
gsl_interp_eval_deriv(const gsl_interp * obj,
                      const double xa[], const double ya[], double x,
                      gsl_interp_accel * a);

int
gsl_interp_eval_deriv2_e(const gsl_interp * obj,
                         const double xa[], const double ya[], double x,
                         gsl_interp_accel * a,
                         double * d2);

double
gsl_interp_eval_deriv2(const gsl_interp * obj,
                       const double xa[], const double ya[], double x,
                       gsl_interp_accel * a);

int
gsl_interp_eval_integ_e(const gsl_interp * obj,
                        const double xa[], const double ya[],
                        double a, double b,
                        gsl_interp_accel * acc,
                        double * result);

double
gsl_interp_eval_integ(const gsl_interp * obj,
                      const double xa[], const double ya[],
                      double a, double b,
                      gsl_interp_accel * acc);

void
gsl_interp_free(gsl_interp * interp);

size_t gsl_interp_bsearch(const double x_array[], double x,
                          size_t index_lo, size_t index_hi);

#ifdef HAVE_INLINE
extern inline size_t
gsl_interp_bsearch(const double x_array[], double x,
                   size_t index_lo, size_t index_hi);

extern inline size_t
gsl_interp_bsearch(const double x_array[], double x,
                   size_t index_lo, size_t index_hi)
{
  size_t ilo = index_lo;
  size_t ihi = index_hi;
  while(ihi > ilo + 1) {
    size_t i = (ihi + ilo)/2;
    if(x_array[i] > x)
      ihi = i;
    else
      ilo = i;
  }

  return ilo;
}
#endif

#ifdef HAVE_INLINE
extern inline size_t
gsl_interp_accel_find(gsl_interp_accel * a, const double xa[], size_t len, double x)
{
  size_t x_index = a->cache;

  if(x < xa[x_index]) {
    a->miss_count++;
    a->cache = gsl_interp_bsearch(xa, x, 0, x_index);
  }
  else if(x > xa[x_index + 1]) {
    a->miss_count++;
    a->cache = gsl_interp_bsearch(xa, x, x_index, len-1);
  }
  else {
    a->hit_count++;
  }

  return a->cache;
}
#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_INTERP_H__ */


/*
 * MIT License
 *
 * Copyright (c) 2017 Intel Corporation
 *
 * 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.
 *
 *
 * Abstract: misc util functions and macros
 */

#ifndef __UTIL_H__
#define __UTIL_H__

#include <algorithm>
#include <gsl/span>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

typedef gsl::span<const uint8_t> cbspan;

#ifndef block_round
#define block_round(ODD, BLK)                                                  \
    ((ODD) + (((BLK) - ((ODD) & ((BLK)-1))) & ((BLK)-1)))
#endif

template <class TContainer>
static inline bool starts_with(const TContainer& haystack,
                               const TContainer& needle)
{
    return haystack.size() >= needle.size() &&
           std::equal(needle.begin(), needle.end(), haystack.begin());
}

static inline void split(const std::string& s, char delim,
                         std::vector<std::string>& result)
{
    std::string::size_type prev_pos = 0, pos = 0;
    do
    {
        pos = s.find(delim, pos);
        if (pos == std::string::npos)
        {
            result.emplace_back(std::move(s.substr(prev_pos)));
        }
        else
        {
            result.emplace_back(std::move(s.substr(prev_pos, pos - prev_pos)));
            prev_pos = ++pos;
        }
    } while (pos != std::string::npos);
}

static inline std::vector<std::string> split(const std::string& s, char delim)
{
    std::vector<std::string> elems;
    split(s, delim, elems);
    return elems;
}

static constexpr uint64_t prime = 0x100000001B3ull;
static constexpr uint64_t basis = 0xCBF29CE484222325ull;

static constexpr uint64_t const_hash(const char* str,
                                     uint64_t last_value = basis)
{
    return *str ? const_hash(str + 1, (*str ^ last_value) * prime) : last_value;
}

static inline uint64_t hash(const std::string& str)
{
    uint64_t ret{basis};

    for (auto i : str)
    {
        ret ^= static_cast<uint64_t>(i);
        ret *= prime;
    }

    return ret;
}

#endif /* __UTIL_H__ */


#include <gsl/gsl_math.h>
#include "gsl_cblas.h"
#include "cblas.h"

void
cblas_sswap (const int N, float *X, const int incX, float *Y, const int incY)
{
#define BASE float
#include "source_swap_r.h"
#undef BASE
}


/*
  C code for actionAngle calculations
*/
#ifndef __GALPY_ACTIONANGLE_H__
#define __GALPY_ACTIONANGLE_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#include <Python.h>
#endif
#include <stdbool.h>
#include <gsl/gsl_roots.h>
#include <gsl/gsl_spline.h>
#include "interp_2d.h"
/*
  Macro for dealing with potentially unused variables due to OpenMP
 */
/* If we're not using GNU C, elide __attribute__ if it doesn't exist*/
#ifndef __has_attribute      // Compatibility with non-clang compilers.
#define __has_attribute(x) 0
#endif
#if defined(__GNUC__) || __has_attribute(unused)
#  define UNUSED __attribute__((unused))
#else
#  define UNUSED /*NOTHING*/
#endif
/*
  Structure declarations
*/
struct pragmasolver{
  gsl_root_fsolver *s;
};
#ifdef __cplusplus
}
#endif
#endif /* actionAngle.h */


#ifndef CTETRA_TETRA_H
#define CTETRA_TETRA_H

#include <stdlib.h>
#include <gsl/gsl_vector.h>
#include "ecache.h"

typedef double (*tetra_SumFn)(double E, double E1, double E2, double E3, double E4, double num_tetra);

double tetra_SumTetra(tetra_SumFn F, double E, EnergyCache *Ecache);

void sortEs(double Es[4]);

#endif // CTETRA_TETRA_H


#ifndef ARRUS_CORE_COMMON_COLLECTIONS_H
#define ARRUS_CORE_COMMON_COLLECTIONS_H

#include <string>
#include <vector>
#include <numeric>
#include <unordered_set>
#include <type_traits>
#include <bitset>
#include <stdexcept>

#include <gsl/span>
#include <boost/range/combine.hpp>

namespace arrus {

/**
 * Returns an array of range [start, end).
 */
template<typename T>
inline std::vector<T> getRange(T start, T end, T step = 1) {
    std::vector<T> values;
    for(T i = start; i < end; i += step) {
        values.push_back(i);
    }
    return values;
}

template<typename Out, typename In>
inline std::vector<Out> castTo(std::vector<In> values) {
    std::vector<Out> result(values.size());
    std::transform(
        std::begin(values), std::end(values),
        std::begin(result),
        [](In &value) { return Out(value); }
    );
    return result;
}

template<typename Out, typename Iterator>
inline std::vector<Out> castTo(const Iterator begin, const Iterator end) {
    std::vector<Out> result;
    std::transform(begin, end, std::back_inserter(result),
                   [](auto &value) { return Out(value); });
    return result;
}

/**
 * Returns an array that holds given value n times.
 */
template<typename T>
inline std::vector<T> getNTimes(const T value, size_t n) {
    std::vector<T> values;
    for(size_t i = 0; i < n; ++i) {
        values.push_back(value);
    }
    return values;
}

template<typename T>
inline size_t countUnique(const std::vector<T> &values) {
    return std::unordered_set<T>(std::begin(values), std::end(values)).size();
}

template<typename T>
inline bool
setContains(const std::unordered_set<T> &set, const T &value) {
    return set.find(value) != set.end();
}

template<typename T, typename U>
inline std::vector<std::pair<T, U>>
zip(const std::vector<T> &a, const std::vector<U> &b) {
    if(a.size() != b.size()) {
        throw std::runtime_error("Zipped vectors should have the same size.");
    }
    std::vector<std::pair<T, U>> res;
    res.reserve(a.size());
    for(const auto &[x, y] : boost::combine(a, b)) {
        res.emplace_back(x, y);
    }
    return res;
}

template<typename R>
inline std::vector<R>
generate(size_t nElements, std::function<R(size_t)> transformation) {
    std::vector<R> result;
    result.reserve(nElements);
    for(size_t i = 0; i < nElements; ++i) {
        result.emplace_back(transformation(i));
    }
    return result;
}

template<typename T>
inline std::vector<T>
concat(const std::vector<T> &a, const std::vector<T> &b) {
    std::vector<T> result;
    result.reserve(a.size() + b.size());
    result.insert(std::begin(result), std::begin(a), std::end(a));
    result.insert(std::end(result), std::begin(b), std::end(b));
    return result;

}

template<typename T>
inline std::vector<T>
concat(const std::vector<std::vector<T>> &a) {
    std::vector<T> result;
    size_t totalSize = 0;
    for(const auto &v : a) {
        totalSize += v.size();
    }
    result.reserve(totalSize);
    for(const auto &vec : a) {
        result.insert(std::end(result), std::begin(vec), std::end(vec));
    }
    return result;
}

template<typename T>
inline std::vector<T>
permute(const std::vector<T> &input, const std::vector<unsigned short> &perm) {
    std::vector<T> output(perm.size());
    for(size_t i = 0; i < static_cast<size_t>(perm.size()); ++i) {
        output[perm[i]] = input[i];
    }
    return output;
}

template<int size>
inline std::bitset<size>
toBitset(const std::vector<bool> &in) {
    std::bitset<size> result;
    for(size_t i = 0; i < size; ++i) {
        result[i] = in[i];
    }
    return result;
}

template<typename Map, typename K>
inline bool containsKey(Map map, const K &key) {
    return map.find(key) != std::end(map);
}

template<typename T>
inline void setValuesInRange(std::vector<T> &container, size_t start, size_t end, const T &value) {
    for(size_t i = start; i < end; ++i) {
        container[i] = value;
    }
}

template<size_t N>
inline void setValuesInRange(std::bitset<N> &container, size_t start, size_t end, const bool &value) {
    for(size_t i = start; i < end; ++i) {
        container[i] = value;
    }
}

template<typename T>
inline void setValuesInRange(std::vector<T> &container, size_t start, size_t end,
                             const std::function<T(size_t)> &generator) {
    for(size_t i = start; i < end; ++i) {
        container[i] = generator(i);
    }
}

template<typename T>
inline void setValuesInRange(std::vector<T> &container, size_t start, size_t end,
                             const std::vector<T>& source) {
    if(source.size != end-start) {
        throw std::runtime_error("Source vector should have exactly "
                            + std::to_string(end-start) + " elements "
                          "when assigning it to the selected range.");
    }
    for(size_t i = start; i < end; ++i) {
        container[i] = source[i-start];
    }
}

template<class InputIt, class T, class BinaryOp>
inline T reduce(InputIt first, InputIt last, T init, BinaryOp binaryOp) {
    T result = init;
    for(auto it = first; it != last; ++it) {
        result = binaryOp(result, *it);
    }
    return result;
}

}

#endif //ARRUS_CORE_COMMON_COLLECTIONS_H