/*
	mgconvert.cpp
	Convert between micrograph parameter formats
	Author:  Bernard Heymann & David Belnap
	Modifications by:  Bernard Heymann, David Belnap, James Conway, Juha Huiskonen
	Created: 20061101      Modified: 20081028
	Compile with:
		g++ mgconvert.cpp -o mgconvert -I$BSOFT/include -L$BSOFT/lib -lbsoft
*/

#include "mg_processing.h"
#include "rwmg.h"
#include "rwmgSTAR.h"
#include "rwmgXML.h"
#include "mg_ctf.h"
#include "linked_list.h"
#include "utilities.h"
#include "options.h"
#include "timer.h"

#define DATLINELENGTH 120

// Declaration of global variables
extern int 	verbose;		// Level of output to the screen
extern long memory;			// Total memory allocated 

// Function prototypes
Bproject*	read_project_conv(Bstring* file_list);
int			write_project_conv(Bstring& filename, Bproject* project, int mg_select, int rec_select);
int			read_project_dat(Bstring& filename, Bproject* project);
int			write_project_dat(Bstring& filename, Bproject* project, int mg_select, int rec_select);
int			read_project_crd(Bstring& filename, Bproject* project);
int			write_project_crd(Bstring& filename, Bproject* project, int mg_select, int rec_select);
int			project_modify_parameters(Bproject* project, char flags);

// Usage assistence
const char* use[] = {
" ",
"Usage: mgconvert [options] input.star [input2.star]",
"---------------------------------------------------",
"Converts micrograph parameter files.",
"DAT and CRD files only hold one micrograph per file:",
"	multiple micrographs are written as numbered DAT or CRD files.",
"	use -mgselect to select only one micrograph.",
" ",
"Parameters:",
"-verbose 7               Verbosity of output.",
"-sampling 1.5            Sampling (A/pixel).",
"-mgselect 5              Selected micrograph (default all, first micrograph = 1).",
"-recselect 5             Selected reconstruction (default all, first reconstruction = 1).",
"-euler                   Convert views to Euler angles.",
"-omega                   Add or subtract 90 degrees to or from the OMEGA angle.",
"-magnification           Invert the magnification factor:  1/mag.",
" ",
"Output:",
"-output file.star        Output parameter file.",
" ",
NULL
};

int			main(int argc, char** argv)
{
	// Initializing variables
	float			sampling;					// A/pixel
	int				mg_select = -1;
	int				rec_select = -1;
	int				euler = 0;					// Flag to specify Euler angles
	char			flags = 0;					// Flags to modify some input parameters
	Bstring			outfile;					// Output parameter file
	
	int				i, optind;
	Option*			option = get_option_list(use, argc, argv, &optind);
	Option*			curropt;
	for ( curropt = option; curropt; curropt = curropt->next ) {
		if ( strcmp(curropt->tag, "sampling") == 0 )
			if ( sscanf(curropt->value, "%f", &sampling) < 1 )
				fprintf(stderr, "-sampling: A pixel size must be specified\n");
		if ( strcmp(curropt->tag, "mgselect") == 0 )
			if ( sscanf(curropt->value, "%d", &mg_select) < 1 )
				fprintf(stderr, "-mgselect: A number must be specified\n");
		if ( strcmp(curropt->tag, "recselect") == 0 )
			if ( sscanf(curropt->value, "%d", &rec_select) < 1 )
				fprintf(stderr, "-recselect: A number must be specified\n");
		if ( strcmp(curropt->tag, "euler") == 0 )
			euler = 1;
		if ( strcmp(curropt->tag, "magnification") == 0 )
			flags += 1;
		if ( strcmp(curropt->tag, "omega") == 0 )
			flags += 2;
		if ( strcmp(curropt->tag, "output") == 0 )
			outfile = get_option_filename(curropt->value);
    }
	option_kill(option);

	timeval		ti;
	if ( verbose & VERB_TIME )
		ti = timer_start();
	
	// Read all the parameter files
	Bstring*		file_list = NULL;
	while ( optind < argc ) string_add(&file_list, argv[optind++]);
	if ( !file_list ) {
		fprintf(stderr, "Error: No parameter files specified!\n");
		bexit(-1);
	}

	Bproject*		project = read_project_conv(file_list);
	
	string_kill(file_list);
	
	if ( project == NULL )  {
		fprintf(stderr, "Error: No project generated!\n");
		bexit(-1);
	}
	
	if ( sampling > 0.1 )
		project_set_pixel_size(project, sampling);

	if ( flags )
		project_modify_parameters(project, flags);
	
	if ( euler ) project->euler_flag = 1;
	
	// Write an output parameter file if a name is given
	if ( outfile.length() ) {
		project_update_comment(project, argc, argv);
		write_project_conv(outfile, project, mg_select, rec_select);
	}
	
	project_kill(project);
	
	if ( verbose & VERB_TIME )
		timer_report(ti);
	
	bexit(0);
}

Bproject*	read_project_conv(Bstring* file_list)
{
	if ( !file_list ) {
		fprintf(stderr, "Error: No micrograph parameter filename!\n");
		return(NULL);
	}
	
	Bstring			ext;
	Bstring*		thisfile;
	
	if ( verbose & VERB_LABEL ) {
		printf("Parameter filenames:");
		for ( thisfile = file_list; thisfile; thisfile = thisfile->next )
			printf(" %s", thisfile->c_str());
		printf("\n");
	}
	
	int					err;
	Bproject*			project = project_init();
	Bfield*				field = NULL;
	Bmicrograph*		mg = NULL;
	Breconstruction*	rec = NULL;
	project->filename = *file_list;
	
	for ( thisfile = file_list; thisfile; thisfile = thisfile->next ) {
		for ( field = project->field; field && field->next; field = field->next ) ;
		if ( field ) for ( mg = field->mg; mg && mg->next; mg = mg->next ) ;
		for ( rec = project->rec; rec && rec->next; rec = rec->next) ;
//		printf("read_project: %s\n", thisfile->c_str());
		ext = thisfile->extension();
		if ( ext.contains("star") ) {
			err = read_project_star(*thisfile, project);
		} else if ( ext.contains("xml") ) {
			err = read_project_xml(*thisfile, project);
		} else if ( ext.contains("dat") ) {
			err = read_project_dat(*thisfile, project);
		} else if ( ext.contains("crd") ) {
			err = read_project_crd(*thisfile, project);
		} else {
			fprintf(stderr, "Error: Extension \"%s\" not valid for parameter files!\n", ext.c_str());
			fprintf(stderr, "	Parameter file \"%s\" not read.\n", thisfile->c_str());
			err = -1;
		}
		if ( !err ) {
			if ( !field ) field = project->field;
			else field = field->next;
			if ( field ) {
				if ( !mg ) mg = field->mg;
				else mg = mg->next;
//				if ( mg ) field_resolve_file_access(field, mg, *thisfile);
			}
			if ( !rec ) rec = project->rec;
			else rec = rec->next;
//			if ( rec ) reconstruction_resolve_file_access(rec, *thisfile);
		}
	}

	if ( err < 0 ) {
		error_show(file_list->c_str(), __FILE__, __LINE__);
		project_kill(project);
		return(NULL);
	}
	
	project_update_first_zero(project);
	
//	project_check(project);
	
//	if ( verbose & VERB_PROCESS )
//		project_display_counts(project);
	
	return(project);
}

int			write_project_conv(Bstring& filename, Bproject* project, int mg_select, int rec_select)
{
	int				err = 0;
	
	if ( filename.empty() ) {
		fprintf(stderr, "Error: No micrograph parameter filename!\n");
		return(-1);
	}
	
	project_update_first_zero(project);
	
//	project_check(project);
	
//	if ( verbose & VERB_PROCESS )
//		project_display_counts(project);
	
	Bstring			ext = filename.extension();

	if ( ext.contains("star") && project->split == 9 ) {
		err = write_project_star(filename, project, mg_select, rec_select);
		return(err);
	}
	
	if ( verbose & VERB_LABEL )
		printf("Parameter filename: %s\n", filename.c_str());

    if ( ext.contains("star") ) {
		err = write_project_star(filename, project, mg_select, rec_select);
	} else if ( ext.contains("xml") ) {
		err = write_project_xml(filename, project, mg_select, rec_select);
    } else if ( ext.contains("dat") ) {
		err = write_project_dat(filename, project, mg_select, rec_select);
    } else if ( ext.contains("crd") ) {
		err = write_project_crd(filename, project, mg_select, rec_select);
	} else {
		fprintf(stderr, "Error: Extension \"%s\" not valid for parameter files!\n", ext.c_str());
		fprintf(stderr, "	Parameter file \"%s\" not written.\n", filename.c_str());
		err = -1;
	}
	
	if ( err < 0 )
		error_show(filename.c_str(), __FILE__, __LINE__);
	
	return(err);
}


/************************************************************************
@Function: read_project_dat
@Description:
	Reading micrograph parameters from a DAT file.
@Algorithm:
	.
@Arguments:
	Bstring& filename		file name (or comma-delimited list).
	Bproject* project		initialized project structure.
@Returns:
	int						error code (<0 means failure).
**************************************************************************/
int			read_project_dat(Bstring& filename, Bproject* project)
{
	int					err = 0;
	char				inputLine[1024];
	int					unitsInHeaderI;
	char				unitsInHeaderC[10];   // "angstrom", "nm" or "pixel"

	Bstring				field_id = filename.base();
	Bstring				mg_id = field_id;
	Bfield*				field = field_add(&project->field, field_id);
	Bmicrograph*		mg = micrograph_add(&field->mg, mg_id);
	Bparticle*			part = NULL;
	CTF*				ctf = mg->ctf = ctf_init();

	if ( verbose ) printf("Reading a DAT file:             %s\n", filename.c_str());
	
    /*========================
       Read DAT-format file
    ========================*/
    FILE*			fdat = fopen(filename.c_str(), "r");
    if (!fdat)  {                       // make sure input file exists
		fprintf(stderr, "File %s does not exist!.  Exit program.\n", filename.c_str());
		bexit(-1);
    }
	
    fgets(inputLine, 1023, fdat);
	mg->fpart = inputLine;
	mg->fpart = mg->fpart.remove(' ');
	mg->fpart = mg->fpart.remove('\n');
    if ( mg->fpart.empty() )  {
		fprintf(stderr, "ERROR reading line 1 of PFT-format DAT file.  Exit program\n");
		exit(-1);
    }
	
	// General micrograph parameters
	
	if (fgets(inputLine, 1023, fdat) == NULL)  {
        printf("ERROR reading line 2 of PFT-format DAT file.  Exit program\n");
        exit(-1);
	}
	if ( sscanf(inputLine, "%f,%d,%f,%f,%f,%f,%f,%f\n", &mg->pixel_size, &unitsInHeaderI,
				&ctf->volt, &ctf->amp, &ctf->def_avg, &ctf->def_dev, &ctf->ast_ang, &ctf->Cs) == 8)  {
		switch(unitsInHeaderI)  {
			case 0:
				strcpy(unitsInHeaderC, "pixels");
				break;
			case 1:
				strcpy(unitsInHeaderC, "angstroms");
				break;
			case 2:
				strcpy(unitsInHeaderC, "nm");
			default:
			break;
		}
	} else if ( sscanf(inputLine, "%f,%f,%f,%f,%f,%f,%f\n", &mg->pixel_size, &ctf->volt,
					&ctf->amp, &ctf->def_avg, &ctf->def_dev, &ctf->ast_ang, &ctf->Cs) == 7)  {
	} else {
			printf("ERROR interpreting line 2 of PFT-format DAT file.  Exit program\n");
			exit(-1);
    }
    if ( ctf->volt < 1000.0 ) ctf->volt *= 1000;		// Volt units for STAR-format file
    ctf->Cs *= 10000000;								// Angstrom units for STAR-format file
	if ( ctf->def_avg < 100 ) ctf->def_avg *= 1e4;		// Angstrom units for STAR-format file
	if ( ctf->def_dev < 100 ) ctf->def_dev *= 1e4;		// Angstrom units for STAR-format file
	ctf->def_avg = (ctf->def_avg + ctf->def_dev)/2;
	ctf->def_dev -= ctf->def_avg;
	ctf->ast_ang *= M_PI/180.0;

    char				line[DATLINELENGTH];
	int					numpart = 0, pid;
	float				theta, phi, omega, ox, oy, mag, fom1, fom2, fom3;
    
	while ( fgets(line, DATLINELENGTH, fdat) ) {
		if ( sscanf(line, "%d,%f,%f,%f,%f,%f,%f,%f,%f,%f", &pid, &theta, &phi, &omega, &ox, &oy, &mag, &fom1, &fom2, &fom3) > 6 )  {
			part = particle_add(&part, pid);
			if ( !mg->part ) mg->part = part;
			part->ori[0] = ox;
			part->ori[1] = oy;
			part->mag = mag;
			part->fom[0] = fom1;
			part->fom[1] = fom2;
			part->fom[2] = fom3;
			part->view = view_from_psi_theta_phi(-omega*M_PI/180.0, 
					theta*M_PI/180.0, phi*M_PI/180.0);
			numpart++;
		}
    }
	
    fclose(fdat);         // close input DAT file

	if ( verbose ) printf("Number of particles read:       %d\n", numpart);
	
	return(err);
}

/************************************************************************
@Function: write_project_dat
@Description:
	Writing micrograph parameters to a DAT file.
@Algorithm:
	.
@Arguments:
	const char* filename	file name.
	Bproject* project		project structure.
	int mg_select			flag to select micrograph.
	int rec_select			flag to select reconstruction.
@Returns:
	int						error code (<0 means failure).
**************************************************************************/
int			write_project_dat(Bstring& filename, Bproject* project, int mg_select, int rec_select)
{
	int					err = 0;
	int					i, f, numpart = 0;
	float				def_min, def_max;
	Euler				euler;
	Bfield*				field = NULL;
	Bmicrograph*		mg = NULL;
	Bparticle*			part = NULL;
	CTF*				ctf;
    FILE*				fdat = NULL;
	Bstring				outname = filename;

	if ( verbose ) printf("Writing a DAT file:             %s\n", filename.c_str());

	if ( project_count_micrographs(project) < 2 ) mg_select = 1;

	for ( i=1, field = project->field; field; field = field->next ) {
		for ( mg = field->mg; mg; mg = mg->next, i++ ) if ( mg_select < 1 || mg_select == i ) {
			if ( mg_select < 1 ) outname = filename.pre_rev('.') + Bstring(i, "_%06d.") + filename.post_rev('.');
			ctf = mg->ctf;
			if ( !ctf ) ctf = mg->ctf = ctf_init();
			def_min = ctf->def_avg - ctf->def_dev;
			def_max = ctf->def_avg + ctf->def_dev;
			fdat = fopen(outname.c_str(), "w");
			if ( !fdat )  {                       // make sure input file exists
				fprintf(stderr, "Unable to create file %s!.  Exit program.\n", filename.c_str());
				bexit(-1);
			}
			fprintf(fdat, "%s\n", mg->fpart.c_str());
			fprintf(fdat, "%9.4f, %d, %7.1f, %7.3f, %10.4f, %10.4f, %9.3f, %7.2f\n", 
					mg->pixel_size, 1, ctf->volt, ctf->amp,
					def_min/1e4, def_max/1e4, ctf->ast_ang*180.0/M_PI, ctf->Cs/1e7);
			for ( part = mg->part; part; part = part->next, numpart++ ) {
				euler = euler_from_view(part->view);
				fprintf(fdat, "%6d, %7.3f, %7.3f, %7.2f, %7.3f, %7.3f, %5.3f",
						part->id, euler.theta*180.0/M_PI, euler.phi*180.0/M_PI, -euler.psi*180.0/M_PI, 
						part->ori.x(), part->ori.y(), part->mag);
//				for ( f=0; f<NFOM; f++ ) fprintf(fdat, ", %5.3f", part->fom[f]);
				for ( f=0; f<3; f++ ) fprintf(fdat, ", %5.3f", part->fom[f]);
				fprintf(fdat,"\n");
			}
			fclose(fdat);
		}
	}

	if ( verbose ) printf("Number of particles written:    %d\n", numpart);
	
	return(err);
}

/************************************************************************
@Function: read_project_crd
@Description:
	Reading micrograph parameters from a CRD file.
@Algorithm:
	.
@Arguments:
	Bstring& filename		file name (or comma-delimited list).
	Bproject* project		initialized project structure.
@Returns:
	int						error code (<0 means failure).
 **************************************************************************/
int			read_project_crd(Bstring& filename, Bproject* project)
{
	int					err = 0;
    char				line[DATLINELENGTH];
	char*				value;
	double				d;
	
	Bstring				field_id = filename.base();
	Bstring				mg_id = field_id;
	Bfield*				field = field_add(&project->field, field_id);
	Bmicrograph*		mg = micrograph_add(&field->mg, mg_id);
	Bparticle*			part = NULL;
	Bbadarea*			bad = NULL;
	Bstring				part_prefix;
	Bstring				part_ext;
	
	if ( verbose ) printf("Reading a CRD file:             %s\n", filename.c_str());
	
    /*========================
	 Read CRD-format file
	 ========================*/
    FILE*			fcrd = fopen(filename.c_str(), "r");
    if (!fcrd)  {                       // make sure input file exists
		fprintf(stderr, "File %s does not exist!.  Exit program.\n", filename.c_str());
		bexit(-1);
    }
	
    fgets(line, DATLINELENGTH, fcrd);	// First line
	
	// General micrograph parameters
	while ( fgets(line, DATLINELENGTH, fcrd) && !strstr(line, "$END") ) {
		value = strchr(line, '=') + 1;
		while ( isspace(value[0]) ) value++; 
		if ( strstr(line, "PIC_FILENAME") ) {
			mg->fmg = value;
			mg->fmg = mg->fmg.remove('\n');
			mg->fmg = mg->fmg.remove(',');
			mg->fmg = mg->fmg.remove('\'');
		} else if ( strstr(line, "OUTFILE_PREFIX") ) {
			part_prefix = value;
			part_prefix = part_prefix.remove('\n');
			part_prefix = part_prefix.remove(',');
			part_prefix = part_prefix.remove('\'');
		} else if ( strstr(line, "OUTFILE_TYPE") ) {
			part_ext = value;
			part_ext = part_ext.remove('\n');
			part_ext = part_ext.remove(',');
			part_ext = part_ext.remove('\'');
		} else if ( strstr(line, "ANGSTROMS") ) {
			sscanf(value, "%lf", &d);
			if ( d > 0 ) mg->pixel_size = d;
		} else if ( strstr(line, "RADIUS_PICK") ) {
			sscanf(value, "%lf", &d);
			mg->box_radius[0] = mg->box_radius[1] = mg->box_radius[2] = d;
		} else if ( strstr(line, "RADIUS_BAD") ) {
			sscanf(value, "%f", &mg->bad_radius);
		}
	}
	
	if ( part_prefix.length() )
		mg->fpart = part_prefix + "." + part_ext;
	
	int					numpart = 0, numbad = 0, pid;
	float				x, y;
    
	while ( fgets(line, DATLINELENGTH, fcrd) ) {
		if ( sscanf(line, "%d %f %f", &pid, &x, &y) > 2 )  {
			if ( pid > 0 ) {
				part = particle_add(&part, pid);
				if ( !mg->part ) mg->part = part;
				part->loc[0] = x;
				part->loc[1] = y;
				numpart++;
			} else {
				bad = (Bbadarea *) add_item((char **) &bad, sizeof(Bbadarea));
				if ( !mg->bad ) mg->bad = bad;
				bad->loc[0] = x;
				bad->loc[1] = y;
				numbad++;
			}
		}
    }
	
    fclose(fcrd);         // close input CRD file
	
	if ( verbose ) printf("Number of particles read:       %d (%d)\n\n", numpart, numbad);
	
	return(err);
}

/************************************************************************
@Function: write_project_crd
@Description:
	Writing micrograph parameters to a CRD file.
@Algorithm:
	.
@Arguments:
	const char* filename	file name.
	Bproject* project		project structure.
	int mg_select			flag to select micrograph.
	int rec_select			flag to select reconstruction.
@Returns:
	int						error code (<0 means failure).
 **************************************************************************/
int			write_project_crd(Bstring& filename, Bproject* project, int mg_select, int rec_select)
{
	int					err = 0;
	int					i, f, numpart = 0, numbad = 0;
	Bfield*				field = NULL;
	Bmicrograph*		mg = NULL;
	Bparticle*			part = NULL;
	Bbadarea*			bad = NULL;
    FILE*				fcrd = NULL;
	Bstring				outname = filename;
	
	if ( verbose ) printf("Writing a CRD file:             %s\n", filename.c_str());
	
	if ( project_count_micrographs(project) < 2 ) mg_select = 1;
	
	for ( i=1, field = project->field; field; field = field->next ) {
		for ( mg = field->mg; mg; mg = mg->next, i++ ) if ( mg_select < 1 || mg_select == i ) {
			if ( mg_select < 1 ) outname = filename.pre_rev('.') + Bstring(i, "_%06d.") + filename.post_rev('.');
			fcrd = fopen(outname.c_str(), "w");
			if ( !fcrd )  {                       // make sure input file exists
				fprintf(stderr, "Unable to create file %s!.  Exit program.\n", filename.c_str());
				bexit(-1);
			}
			fprintf(fcrd, " $TRIMNEWPARAMETERS\n");
			fprintf(fcrd, " CRD_VERSION     = 3,\n");
			if ( mg->fmg.length() ) fprintf(fcrd, " PIC_FILENAME    = '%s',\n", mg->fmg.c_str());
			else fprintf(fcrd, " PIC_FILENAME    = '',\n");
			fprintf(fcrd, " PIC_FLIPFLAG    = F,\n");
			fprintf(fcrd, " FLIPALLROWSFLAG = F,\n");
			fprintf(fcrd, " FLIPALLCOLSFLAG = F,\n");
			fprintf(fcrd, " INVERT_INTENSTY = F,\n");
			fprintf(fcrd, " ANGSTROMS       = %g,\n", mg->pixel_size);
			fprintf(fcrd, " CONTRAST        = 1.380000\n");
			fprintf(fcrd, " BRIGHTNESS      = 0.120000\n");
			if ( mg->fpart.length() ) fprintf(fcrd, " OUTFILE_PREFIX  = '%s',\n", (mg->fpart.pre_rev('.')).c_str());
			else fprintf(fcrd, " OUTFILE_PREFIX  = '',\n");
			fprintf(fcrd, " OUTFILE_START   = 1,\n");
			fprintf(fcrd, " OUTFILE_WIDTH   = 3,\n");
			if ( mg->fpart.length() ) fprintf(fcrd, " OUTFILE_TYPE    = '%s',\n", (mg->fpart.post_rev('.')).c_str());
			else fprintf(fcrd, " OUTFILE_TYPE    = '',\n");
			fprintf(fcrd, " OD_CONVERT      = F,\n");
			fprintf(fcrd, " RADIUS          = 50,\n");
			fprintf(fcrd, " RADIUS_BAD      = %g,\n", mg->bad_radius);
			fprintf(fcrd, " RADIUS_PICK     = %g,\n", mg->box_radius.x());
			fprintf(fcrd, " FADE            = 9,\n");
			fprintf(fcrd, " EXTRACT_DX      = 501,\n");
			fprintf(fcrd, " EXTRACT_DY      = 501,\n");
			fprintf(fcrd, " FINAL_DX        = 401,\n");
			fprintf(fcrd, " FINAL_DY        = 401,\n");
			fprintf(fcrd, " FINAL_MEAN      = 127,\n");
			fprintf(fcrd, " FINAL_STDDEV    = 40,\n");
			fprintf(fcrd, " SKIPMASKFLAG    = F,\n");
			fprintf(fcrd, " SKIPGRADIENTFLAG= T\n");
			fprintf(fcrd, " SELECTEXTENDED  = T\n");
			fprintf(fcrd, " SELECTEXTLENMODE= FIXED\n");
			fprintf(fcrd, " SELECTEXTFLENGTH= 40\n");
			fprintf(fcrd, " $END\n");
			for ( part = mg->part; part; part = part->next, numpart++ )
				fprintf(fcrd, "%6d%8.0f%8.0f\n", part->id, part->loc.x(), part->loc.y());
			for ( bad = mg->bad; bad; bad = bad->next, numbad++ )
				fprintf(fcrd, "%6d%8.0f%8.0f\n", -numbad-1, bad->loc.x(), bad->loc.y());
			fclose(fcrd);
		}
	}
	
	if ( verbose ) printf("Number of particles written:    %d (%d)\n\n", numpart, numbad);
	
	return(err);
}

/************************************************************************
@Function: project_modify_parameters
@Description:
	Modifies some micrograph parameters.
@Algorithm:
	.
@Arguments:
	Bproject* project		project structure.
	char flags				bit 0 = omega 90 flag, bit 1 = mag flag.
@Returns:
	int						error code (<0 means failure).
**************************************************************************/
int			project_modify_parameters(Bproject* project, char flags)
{
	Bfield*				field = NULL;
	Bmicrograph*		mg = NULL;
	Bparticle*			part = NULL;

	for ( field = project->field; field; field = field->next ) {
		for ( mg = field->mg; mg; mg = mg->next ) {
			for ( part = mg->part; part; part = part->next ) {
				if ( flags & 1 ) part->mag = 1.0/part->mag;
				if ( flags & 2 ) part->view.a -= M_PI_2;
			}
		}
	}
	
	return(0);
}
