This is InspectPFunc.m in view mode; [Download] [Up]
/* InspectPFunc.h by Paul Kunz November 1992 * HippoDraw inspector for Minuit fitting * * Copyright (C) 1992 The Board of Trustees of * The Leland Stanford Junior University. All Rights Reserved. */ #import "Draw.subproj/draw.h" #import "InspectPFunc.h" const char InspectPFunc_h_rcsid[] = INSPECTPFUN_H_ID; const char InspectPFunc_m_rcsid[] = "$Id: InspectPFunc.m,v 1.71.2.5 1994/02/08 20:29:36 rensing Exp $"; #import "FineSlider.h" #import "HDrawApp.h" #import "HGraphicView.h" #import "NewInspector.h" #import "Plot.h" #import "PFunction.h" #import "LinearX.h" #import "LinearY.h" #import "Gaussian.h" #import "Quadratic.h" #import "Exponential.h" #import "Zshape.h" #import "PowerLaw.h" #import "Minuit.h" #import <sys/dir.h> #import <float.h> #define FUNC_ALL 0 #define FUNC_PLOT 1 #define VALUE_TAG 0 #define LIMITS_TAG 1 #define PARM_MAX 0 #define PARM_VALUE 1 #define PARM_MIN 2 #define PARM_STEP 3 #define CHISQ_POS 0 #define DOF_POS 1 #define PLOT_INDIVIDUALS 0 #define PLOT_SUM 1 #define GPPCOMPILE //#define GPPLIBRARY "/usr/local/lib/libg++.a" #define GPPLIBRARY "" #define GPPINCLUDEDIR "/usr/local/lib/g++-include" #define PANEL_NAME "Plot Functions" @interface InspectPFunc(Private) - (NXBundle *) compile:(const char *)directory :(const char *)file; /* * Compiles, links, source file into a bundle and returns the intialized * bundle */ - loadFunction:(const char *)directory :(const char *)file; /* * Loads the PFunction in directory/file and adds it to the * available function list and to the dynamically loaded function * list. */ - getFitData; /* * Get the data needed for a fit out of the display */ - loadMinuit; /* * Load Minuit with the current list of parameters */ - enableButtons:(BOOL) flag; /* * Enables or disables al buttons according to value of flag. */ - updateChiSq: (float) chi2; /* * Update chi^2 form with given value. */ - updateDoF; /* * update the degrees of freedom form */ - doSingleFit:sender; /* fit a single plot */ @end static id fitObject = nil; static NXRect stopButtonFrame; static double old_fcn_value; static char *emptyBinTitle[] = {"ignore","set error to 1","disable fitting"}; static char *doFitTitle[] = {"unbinned","integral/fixed norm","integral over bin", "average over bin","1 sample per bin"}; static char *lineStyleTitle[] = {"Solid","Dash","Dot","DotDash","Invisible"}; @implementation InspectPFunc /* Function called by Minuit FCN */ void refreshdisplay_(double *fcn_value, int *iflag, int *quit_minuit) { NXEvent *event; NXPoint where; float cutoff = 0.025; double delta; if ( *iflag >= 2 ) { delta = (*fcn_value - old_fcn_value) / old_fcn_value; if (delta < -cutoff) { old_fcn_value = MAX(fabs(*fcn_value), 1e-06); [fitObject updateParmForm]; [fitObject updateChiSq: *fcn_value]; [fitObject updatePlot]; } } *quit_minuit = 0; if ((event = [NXApp peekAndGetNextEvent:NX_MOUSEDOWNMASK]) != NULL) { where = event->location; if (NXPointInRect(&where, &stopButtonFrame)) { if (NXRunAlertPanel("Cancel fitting warning", "Do you really want to cancel this fit ?", "OK", "continue fitting", NULL) == NX_ALERTDEFAULT) { *quit_minuit = 1; } } } return; } void loadParams(double *parm) { [fitObject loadParams:parm]; } - initInspFor:aDraw { NXBundle *bundle; PopUpList *popup; PFunction *func; char buf[MAXPATHLEN+1]; int itype; [super initInspFor:aDraw]; /* Initial Function List */ availFuncList = [[List allocFromZone:[self zone]] initCount:0]; dynamFuncList = [[List allocFromZone:[self zone]] initCount:0]; func = [[Gaussian allocFromZone:[self zone]] init]; [availFuncList addObject:func]; func = [[LinearX allocFromZone:[self zone]] init]; [availFuncList addObject:func]; func = [[LinearY allocFromZone:[self zone]] init]; [availFuncList addObject:func]; func = [[Quadratic allocFromZone:[self zone]] init]; [availFuncList addObject:func]; func = [[Exponential allocFromZone:[self zone]] init]; [availFuncList addObject:func]; func = [[PowerLaw allocFromZone:[self zone]] init]; [availFuncList addObject:func]; func = [[Zshape allocFromZone:[self zone]] init]; [availFuncList addObject:func]; /* Load interface */ bundle = [NXBundle bundleForClass:[self class]]; if ( [bundle getPath:buf forResource:"InspectPFunc" ofType:"nib"] ) { [NXApp loadNibFile:buf owner:self withNames:NO fromZone:[self zone]]; } [funcBrowser setMinColumnWidth:1]; [funcBrowser setMaxVisibleColumns:2]; [funcBrowser setTitle:"Functions" ofColumn:0]; [funcBrowser loadColumnZero]; [funcBrowser addColumn]; [self updateBrowser]; [funcRadio sendAction]; [theInspector addView:[contentBox contentView] withName:"Plot Functions" withSupervisor:self]; [theInspector showPanelWithName:PANEL_NAME]; popup = [emptyBinButton target]; emptyBinMatrix = [popup itemList]; [popup setTarget:self]; [popup setAction:@selector(ebTypeChanged:)]; popup = [fitTypeButton target]; fitTypeMatrix = [popup itemList]; [popup setTarget:self]; [popup setAction:@selector(fitTypeChanged:)]; itype = FIT_ONESAMPLE; [fitTypeMatrix selectCellWithTag:itype]; [fitTypeButton setTitle:doFitTitle[itype]]; popup = [plotFuncButton target]; plotFuncMatrix = [popup itemList]; [popup setTarget:self]; [popup setAction:@selector(plotFuncLineStyleChanged:)]; [plotFuncMatrix selectCellWithTag:0]; [plotFuncButton setTitle:lineStyleTitle[0]]; popup = [plotFSumButton target]; plotFSumMatrix = [popup itemList]; [popup setTarget:self]; [popup setAction:@selector(plotFSumLineStyleChanged:)]; [plotFSumMatrix selectCellWithTag:0]; [plotFSumButton setTitle:lineStyleTitle[0]]; fitObject = self; return self; } - setFitter:anObject { fitter = anObject; return self; } /* Action Methods */ - add:sender { List *list; parm_t ptype; id matrix; display disp; graphtype_t type; id func, newFunc; int i, irc; if ( !selectedPlot ) return self; ptype = [parmRadio selectedRow]; if ( ptype != PLAY_VALUES ) { list = [selectedPlot functionList]; [list makeObjectsPerform:@selector(copyToVaried:) with:(id)&ptype]; [parmRadio selectCellAt:PLAY_VALUES :0]; ptype = PLAY_VALUES; } matrix = [funcBrowser matrixInColumn:0]; i = [matrix selectedRow]; if ( i < 0 ) { return self; } disp = [selectedPlot histDisplay]; type = h_getDispType( disp ); if ( (type == XYPLOT || type == STRIPCHART ) && h_getBinding(disp,YERROR) < 0 ) { irc = NXRunAlertPanel( "Warning", "Chi-Square and errors from fitting will have no" " meaning without y-errors assigned to plot.", "Proceed", "Cancel", NULL ); if ( irc != NX_ALERTDEFAULT ) return self; } func = [availFuncList objectAt:i]; newFunc = [func copyFromZone:[selectedPlot zone]]; [selectedPlot addFunction:newFunc]; list = [selectedPlot functionList]; [newFunc setInitialValues]; i = [[fitTypeMatrix selectedCell] tag]; [newFunc setFitType:&i]; [[funcRadio selectCellAt:0 :FUNC_PLOT] sendAction]; i = [plotFuncMatrix selectedRow]; [newFunc setFuncLineStyle:&i]; [list makeObjectsPerform:@selector(updateFromType:)with:(id)&ptype]; [self updatePlotMatrix]; [self updatePlot]; [self updateChiSq]; [[[graphicView window] delegate] dirty:self]; return self; } - remove:sender { if (!selectedPlot) return self; if (!plotFunction) return self; [selectedPlot removeFunction:plotFunction]; [plotFunction free]; lastPlot = nil; [self updatePlotMatrix]; [self updatePlot]; [self updateView]; [self updateChiSq]; [[[graphicView window] delegate] dirty:self]; return self; } - browserClicked:sender { List *funcList; Matrix *matrix; int i; if ( [funcRadio selectedCol] == FUNC_ALL ) { [self enableButtons:NO]; return self; } if ( !selectedPlot ) { [self enableButtons:NO]; return self; } funcList = [selectedPlot functionList]; matrix = [funcBrowser matrixInColumn:0]; i = [matrix selectedRow]; if ( (i < 0) && [matrix cellCount] ) { i = 0; /* on coming forward, it's not yet set */ } if ( i < 0 ) { plotFunction = nil; [self enableButtons:NO]; return self; } plotFunction = [funcList objectAt:i]; matrix = [funcBrowser matrixInColumn:1]; i = [matrix selectedRow]; if ( (i < 0) && [matrix cellCount] ) { i = 0; /* on coming forward, it's not yet set */ } if ( i < 0 ) { [self enableButtons:NO]; return self; } pfIndex = i; [self enableButtons:YES]; [self updateParmForm]; [self updatePlotMatrix]; return self; } - animateLimits:sender { Storage *parmList; fitParm *parm; parm_t type; double amplitude, initialAngle, angle; double initialValue; float twoPi; double min_value, mean_value, max_value; int steps = 30; type = [parmRadio selectedRow]; parmList = [plotFunction parmListOfType:type]; parm = [parmList elementAt:pfIndex]; initialValue = parm->value; min_value = [ parmSlider mminValue ]; max_value = [ parmSlider mmaxValue ]; mean_value = 0.5*(max_value + min_value); if (max_value == min_value) return self; amplitude = 0.5*(max_value - min_value); initialAngle = asin( (initialValue-mean_value)/amplitude ); twoPi = 2.0 * M_PI; for (angle = 0.; angle <= twoPi; angle += twoPi / steps) { parm->value = mean_value + amplitude * sin(initialAngle + angle); [parmSlider setFloatValue:parm->value]; [plotFunction updateFromType:&type]; [self updatePlot]; [self updateChiSq]; } parm->value = initialValue; [plotFunction updateFromType:&type]; [parmSlider setFloatValue:initialValue ]; return self; } - sliderDragged:sender { List *list; parm_t type; float value; type = [parmRadio selectedRow]; if ( type != PLAY_VALUES ) { list = [selectedPlot functionList]; [list makeObjectsPerform:@selector(copyToVaried:) with:(id)&type]; [[parmRadio selectCellAt:PLAY_VALUES :0] sendAction]; } value = [parmSlider floatValue]; [plotFunction setFloatValue:value at:pfIndex]; [parmForm setFloatValue:value at:PARM_VALUE]; [self updatePlot]; [self updateChiSq]; return self; } - sliderNudged:sender { Storage *parmList; fitParm *parm; List *list; parm_t type; float value; int nudge; type = [parmRadio selectedRow]; if ( type != PLAY_VALUES ) { list = [selectedPlot functionList]; [list makeObjectsPerform:@selector(copyToVaried:) with:(id)&type]; [[parmRadio selectCellAt:PLAY_VALUES :0] sendAction]; } parmList = [plotFunction parmListOfType:type]; parm = [parmList elementAt:pfIndex]; nudge= [sender tag]; if ( nudge < 0 ) { value = parm->value - parm->step_size; } else { value = parm->value + parm->step_size; } [plotFunction setFloatValue:value at:pfIndex]; [parmForm setFloatValue:value at:PARM_VALUE]; [self updatePlot]; [self updateChiSq]; return self; } - checkFitValid { List *list; parm_t type; type = [parmRadio selectedRow]; if ( type == FIT_VALUES && ![selectedPlot isFitted] ) { list = [selectedPlot functionList]; [list makeObjectsPerform:@selector(copyToVaried:) with:(id)&type]; [self setParmType:PLAY_VALUES]; } if ( ![selectedPlot isFitted] ) { [[parmRadio cellAt:FIT_VALUES :0] setEnabled:NO ]; } return self; } - textDidEnd:sender endChar:(unsigned short)whyEnd { float lower, upper, value, step; parm_t type = [parmRadio selectedRow]; if (selectedPlot == NULL) return self; upper = [parmForm floatValueAt:PARM_MAX]; value = [parmForm floatValueAt:PARM_VALUE]; lower = [parmForm floatValueAt:PARM_MIN]; step = [parmForm floatValueAt:PARM_STEP]; if ( [parmRadio selectedRow] != PLAY_VALUES ) { [[selectedPlot functionList] makeObjectsPerform:@selector(copyToVaried:) with:(id)&type]; [[parmRadio selectCellAt:PLAY_VALUES :0] sendAction]; } switch ([parmForm selectedRow]) { case PARM_MIN : if ( lower > upper ) { upper = lower + (upper - value); } if ( lower > value ) { value = lower; } step = (upper - lower)/ 100.0; break; case PARM_MAX: if ( upper < lower ) { lower = upper - (value - lower); } if ( upper < value ) { value = upper; } step = (upper - lower)/ 100.0; break; case PARM_VALUE: if ( value < lower ) { lower = value - (upper-value); } if ( value > upper ) { upper = value + (value-lower); } step = (upper - lower)/ 100.0; break; case PARM_STEP: if ( upper < (lower + 100*step) ) { upper = lower + 100*step; } if ( lower > (upper + 100*step) ) { lower = upper - 100*step; } break; } [parmForm setFloatValue:upper at:PARM_MAX]; [parmForm setFloatValue:value at:PARM_VALUE]; [parmForm setFloatValue:lower at:PARM_MIN]; [parmForm setFloatValue:step at:PARM_STEP]; [[parmForm window] disableDisplay]; [parmSlider setMaxValue:upper]; [parmSlider setMinValue:lower]; [parmSlider setFloatValue:value]; [[parmForm window] reenableDisplay]; [[parmForm window] displayIfNeeded]; return self; } - parmFormChanged:sender { Storage *parmList; fitParm *parm; parm_t type; type = [parmRadio selectedRow]; parmList = [plotFunction parmListOfType:type]; parm = [parmList elementAt:pfIndex]; if ( !parm ) return self; parm->upper_limit = [parmForm floatValueAt:PARM_MAX]; parm->value = [parmForm floatValueAt:PARM_VALUE]; parm->lower_limit = [parmForm floatValueAt:PARM_MIN]; parm->step_size = [parmForm floatValueAt:PARM_STEP]; [plotFunction updateFromType:&type]; [self updatePlot]; [self updateChiSq]; return self; return self; } - changeFix:sender { Storage *parmList; fitParm *parm; parm_t type; int row; BOOL yesno; type = [parmRadio selectedRow]; parmList = [plotFunction parmListOfType:type]; parm = [parmList elementAt:pfIndex]; row = [sender selectedRow]; switch (row) { case VALUE_TAG: yesno = [[fixMatrix cellAt:VALUE_TAG :0] state]; parm->fixedValue = yesno; if (yesno) { parm->step_size = 0.0; } else { parm->step_size = 0.01*(parm->upper_limit - parm->lower_limit); if (parm->step_size == 0.0) parm->step_size = 0.1; } [[parmForm cellAt:PARM_VALUE :0] setEnabled:!(yesno)]; [[parmForm cellAt:PARM_STEP :0] setEnabled:!(yesno)]; [self updateDoF]; break; case LIMITS_TAG: yesno = [[fixMatrix cellAt:LIMITS_TAG :0] state]; parm->fixedLimits = yesno; [[parmForm cellAt:PARM_MAX :0] setEnabled:!(yesno)]; [[parmForm cellAt:PARM_MIN :0] setEnabled:!(yesno)]; break; } return self; } - funcRadioChanged:sender { unsigned int functype; functype = [funcRadio selectedCol]; switch (functype) { case FUNC_ALL: [addButton setTitle:"Add"]; [addButton setAction:@selector(add:)]; break; case FUNC_PLOT: [addButton setTitle:"Remove"]; [addButton setAction:@selector(remove:)]; break; default: ; } [self updateBrowser]; [self browserClicked:self]; return self; } - parmRadioChanged:sender { List *funcList; /* current function List */ int type; if ( !selectedPlot ) return self; type = [parmRadio selectedRow]; funcList = [selectedPlot functionList]; [funcList makeObjectsPerform:@selector(updateFromType:)with:(id)&type]; [self updatePlot]; /* updating the plot will force the rest */ [self updateChiSq]; [self updateParmForm]; return self; } - fitTypeChanged:sender { List *funcList; enum FCNType_t type; if (!selectedPlot ) return self; funcList = [selectedPlot functionList]; if (!funcList ) return self; type = (enum FCNType_t) [[fitTypeMatrix selectedCell] tag]; [funcList makeObjectsPerform:@selector(setFitType:) with:(id)&type]; if ( type == FIT_MAXLIKE ) [emptyBinButton setEnabled:NO]; else if (h_getDispType( [selectedPlot histDisplay] ) == HISTOGRAM) [emptyBinButton setEnabled:YES]; [self updateChiSq]; return self; } - ebTypeChanged:sender { List *funcList; int type; if (!selectedPlot ) return self; funcList = [selectedPlot functionList]; if (!funcList ) return self; type = [emptyBinMatrix selectedRow]; [funcList makeObjectsPerform:@selector(setEbType:) with:(id)&type]; [self updateChiSq]; return self; } - plotFuncLineStyleChanged:sender { List *funcList; int type; id matrix; int i; PFunction *func; if (!selectedPlot ) return self; funcList = [selectedPlot functionList]; if (!funcList ) return self; type = [[plotFuncMatrix selectedCell] tag]; matrix = [funcBrowser matrixInColumn:0]; i = [matrix selectedRow]; if (i < 0) return self; func = [funcList objectAt:i]; [func setFuncLineStyle:&type]; [self updatePlotMatrix]; [self updatePlot]; [[[graphicView window] delegate] dirty:self]; return self; } - plotFSumLineStyleChanged:sender { display disp; int type; if (!selectedPlot ) return self; disp = [selectedPlot histDisplay]; type = [[plotFSumMatrix selectedCell] tag]; h_setFSumLineStyle(disp, (linestyle_t)type); [self updatePlotMatrix]; [self updatePlot]; [[[graphicView window] delegate] dirty:self]; return self; } - doFit:sender { List *myslist; int scount; Graphic *g; id s1, s2; NXRect bbox; myslist = [graphicView selectedGraphics]; scount = [myslist count]; if (scount == 1) [self doSingleFit:sender]; else { if (NXRunAlertPanel("Multi-plot Fit", "Do you really want to fit all plots in the selection?", "Yes", "NO", NULL) != NX_ALERTDEFAULT) { return self; } s1 = selectedPlot; /* save values and restore after */ s2 = firstPlot; while (scount--) { g = [myslist objectAt:scount]; if ([g isKindOf:[Plot class]]) { selectedPlot = (Plot *)g; firstPlot = (Plot *)g; [g getBounds:&bbox]; [graphicView scrollRectToVisible:&bbox]; [self doSingleFit:sender]; } } selectedPlot = s1; firstPlot = s2; } return self; } - addToAvailFuncs:sender { OpenPanel *openpanel = [[OpenPanel new] allowMultipleFiles:YES]; Matrix *matrix; const char *const fileTypes[2] = { "m", NULL }; const char *directory; const char *const *files; int row; if ([openpanel runModalForTypes:fileTypes]) { directory = [openpanel directory]; files = [openpanel filenames]; while (*files) { [self loadFunction:directory :*files]; files++; } } [theInspector showPanelWithName:PANEL_NAME]; [theInspector orderFrontPanel:self]; [[funcRadio selectCellAt:0 :FUNC_ALL] sendAction]; matrix = [funcBrowser matrixInColumn:0]; row = [matrix cellCount] -1; [matrix selectCellAt:row :0]; [matrix scrollCellToVisible:row :0]; return self; } - startArchivingTo:(const char *)directory { List *plotList; List *funcList; List *saveFuncList; Plot *plot; PFunction *func, *dynfunc; const char *filename; unsigned int i, j, k; if ( !(k = [dynamFuncList count]) ) return self; saveFuncList = [[List allocFromZone:[self zone]] initCount:0]; plotList = [graphicView plotList]; if ( !plotList ) return self; if ( !(i = [plotList count]) ) return self; while ( i-- ) { plot = [plotList objectAt:i]; funcList = [plot functionList]; if ( funcList && (j = [funcList count]) ) { while ( j-- ) { func = [funcList objectAt:j]; k = [dynamFuncList count]; while ( k-- ) { dynfunc = [dynamFuncList objectAt:k]; if ( [dynfunc isKindOf:[func class]] ) { [saveFuncList addObjectIfAbsent:dynfunc]; } } } } } if ( !(i = [saveFuncList count]) ) return self; while ( i-- ) { dynfunc = [saveFuncList objectAt:i]; filename = [dynfunc filename]; [dynfunc writeFile:directory :filename]; } return self; } - startUnarchivingFrom:(const char *)directory { DIR *dirp; struct direct *dp; char *ptr; dirp = opendir( directory ); for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { ptr = strrchr( dp->d_name, '.' ); if ( ptr && !strcmp(ptr, ".m") ) { [self loadFunction:directory :dp->d_name]; } } closedir(dirp); return self; } /* Internal methods */ - fetchMinuit { List *funcList; Storage *parmList; PFunction *func; fitParm *parm; parm_t type; unsigned int i, j, k, num_funcs, num_parms; type = [parmRadio selectedRow]; if ( type != FIT_VALUES ) return self; funcList = [selectedPlot functionList]; num_funcs = [funcList count]; k = 0; for ( i = 0; i < num_funcs; i++ ) { func = [funcList objectAt:i]; parmList = [func parmListOfType:type]; num_parms = [parmList count]; for ( j = 0; j < num_parms; j++ ) { parm = [parmList elementAt:j]; k++; [fitter getParms:parm at:k]; } [func updateFromType:&type]; } return self; } - loadParams:(double *)param { List *funcList; Storage *parmList; PFunction *func; fitParm *parm; parm_t type; int i, j, k, num_funcs, num_parms; type = [parmRadio selectedRow]; funcList = [selectedPlot functionList]; num_funcs = [funcList count]; k = 0; for ( i = 0; i < num_funcs; i++ ) { func = [funcList objectAt:i]; parmList = [func parmListOfType:type]; num_parms = [parmList count]; for ( j = 0; j < num_parms; j++ ) { parm = [parmList elementAt:j]; parm->value = param[k++]; } [func updateFromType:&type]; } return self; } - setParmType:(int)type { [[parmRadio cellAt:type :0] setEnabled:YES ]; [parmRadio selectCellAt:type :0 ]; return self; } - updatePlot { [graphicView graphicsPerformNOP:selectedPlot]; [[[graphicView window] flushWindow] makeKeyWindow]; return self; } - (List *) functionList { List *funcList; unsigned int functype; functype = [funcRadio selectedCol]; switch (functype) { case FUNC_ALL: funcList = availFuncList; break; case FUNC_PLOT: funcList = [selectedPlot functionList]; break; default: funcList = nil; } return funcList; } /* Methods for updating Inspector */ - fullUpdate { graphtype_t type; if ( [selectedPlot isKindOf:[Plot class]] ) { [addButton setEnabled:YES]; } else { [addButton setEnabled:NO]; } type = h_getDispType( [selectedPlot histDisplay] ); if ( !( type == XYPLOT || type == STRIPCHART || type == HISTOGRAM ) ) { [addButton setEnabled:NO]; } [self updateDispType:selectedPlot]; if ( [selectedPlot hasFunction] ) { [funcRadio selectCellAt:0 :FUNC_PLOT]; } else { [funcRadio selectCellAt:0 :FUNC_ALL]; } [self updateParmType]; [self funcRadioChanged:self]; [self browserClicked:self]; [self updatePlotMatrix]; // update chi^2 AFTER updating parmType if ( [selectedPlot hasFunction] ) { [self updateChiSq]; } [self checkFitValid]; lastPlot = selectedPlot; [self updateBrowser]; return self; } - updateView { if ( selectedPlot != lastPlot ) [self fullUpdate]; return self; } - updateEmptySelection { if ( lastPlot == nil ) return self; [addButton setEnabled:NO]; [self enableButtons:NO]; [self updateBrowser]; [self updatePlotMatrix]; [self updateChiSq]; lastPlot = nil; return self; } - updateMultiSelection { if ( lastPlot == nil ) return self; [addButton setEnabled:NO]; [self updateBrowser]; lastPlot = nil; return self; } - updateBrowser { [funcBrowser loadColumnZero]; [funcBrowser addColumn]; [funcBrowser displayAllColumns]; return self; } - updateChiSq { List *funcList; Storage *parmList; PFunction *func; fitParm *parm; double *values; double fcnValue = 0.0; unsigned int i, j, k, num_funcs, num_parms, tot_parms; parm_t type; funcList = [selectedPlot functionList]; if (!funcList) { [chiSqForm setEnabled:NO]; return self; } else { [chiSqForm setEnabled:YES]; } [self getFitData]; type = [parmRadio selectedRow]; funcList = [selectedPlot functionList]; num_funcs = [funcList count]; tot_parms = 0; for ( i = 0; i < num_funcs; i++ ) { func = [funcList objectAt:i]; tot_parms += [func numberArgs]; } NX_MALLOC( values, double, tot_parms ); k = 0; for ( i = 0; i < num_funcs; i++ ) { func = [funcList objectAt:i]; parmList = [func parmListOfType:type]; num_parms = [parmList count]; for ( j = 0; j < num_parms; j++ ) { parm = [parmList elementAt:j]; values[k++] = parm->value; } } minuitfcn_(&fcnValue, values, &tot_parms, &fcnParms); [self updateChiSq:fcnValue]; [self updateDoF]; NX_FREE(values); return self; } - updateParmForm { Storage *parmList; fitParm *parm; parm_t type; type = [parmRadio selectedRow]; parmList = [plotFunction parmListOfType:type]; parm = [parmList elementAt:pfIndex]; if ( !parm ) return self; [parmForm setFloatValue:parm->upper_limit at:PARM_MAX]; [parmForm setFloatValue:parm->value at:PARM_VALUE]; [parmForm setFloatValue:parm->lower_limit at:PARM_MIN]; if ( type == FIT_VALUES ) { [parmForm setTitle:"Error" at:PARM_STEP]; [parmForm setFloatValue:parm->error at:PARM_STEP]; } else { [parmForm setTitle:"Step" at:PARM_STEP]; [parmForm setFloatValue:parm->step_size at:PARM_STEP]; } [[parmForm cellAt:PARM_VALUE :0] setEnabled:!(parm->fixedValue)]; [[parmForm cellAt:PARM_STEP :0] setEnabled:!(parm->fixedValue)]; [[parmForm cellAt:PARM_MAX :0] setEnabled:!(parm->fixedLimits)]; [[parmForm cellAt:PARM_MIN :0] setEnabled:!(parm->fixedLimits)]; [[fixMatrix cellAt:VALUE_TAG :0] setState:parm->fixedValue ]; [[fixMatrix cellAt:LIMITS_TAG :0] setState:parm->fixedLimits]; [fixMatrix display]; [[parmSlider window] disableDisplay]; [parmSlider setMaxValue: [parmForm floatValueAt:PARM_MAX]]; [parmSlider setMinValue: [parmForm floatValueAt:PARM_MIN]]; [parmSlider setFloatValue:[parmForm floatValueAt:PARM_VALUE]]; [[parmSlider window] reenableDisplay]; [parmSlider display]; return self; } - updateParmType { List *funcList; PFunction *func; parm_t type; if ( !selectedPlot ) return self; funcList = [selectedPlot functionList]; if ( funcList && [funcList count] ) { func = [funcList lastObject]; type = [func currentType]; [self setParmType:type]; } return self; } - updatePlotMatrix { display disp; List *funcList; PFunction *func; int itype; id matrix; int i; if (!selectedPlot || [funcRadio selectedCol] == FUNC_ALL) { [plotFuncButton setEnabled:NO]; [plotFSumButton setEnabled:NO]; return self; } disp = [selectedPlot histDisplay]; h_setPlotFuncs(disp, 1); // just to be sure h_setPlotFuncSum(disp, 1); funcList = [selectedPlot functionList]; matrix = [funcBrowser matrixInColumn:0]; i = [matrix selectedRow]; if (i < 0) { [plotFuncButton setEnabled:NO]; } else { [plotFuncButton setEnabled:YES]; func = [funcList objectAt:i]; itype = [func funcLineStyle]; [plotFuncMatrix selectCellWithTag:itype]; [plotFuncButton setTitle:lineStyleTitle[itype]]; } itype = h_getFSumLineStyle(disp); [plotFSumMatrix selectCellWithTag:itype]; [plotFSumButton setTitle:lineStyleTitle[itype]]; [plotFSumButton setEnabled:YES]; return self; } - updateDispType:(Plot *)plot { List *funcList; PFunction *func; graphtype_t dtype; int itype; dtype = h_getDispType( [plot histDisplay] ); [ [fitTypeMatrix findCellWithTag:FIT_ONESAMPLE] setEnabled:YES ]; if ( dtype == XYPLOT || dtype == STRIPCHART ) { [ [fitTypeMatrix findCellWithTag:FIT_INTEGRAL] setEnabled:NO ]; // [ [fitTypeMatrix findCellWithTag:FIT_INTFIXEDNORM] setEnabled:NO ]; [ [fitTypeMatrix findCellWithTag:FIT_AVERAGE] setEnabled:YES ]; // [ [fitTypeMatrix findCellWithTag:FIT_MAXLIKE] setEnabled:NO ]; [emptyBinButton setEnabled:NO]; } else { [ [fitTypeMatrix findCellWithTag:FIT_INTEGRAL] setEnabled:YES ]; // [ [fitTypeMatrix findCellWithTag:FIT_INTFIXEDNORM] setEnabled:YES ]; [ [fitTypeMatrix findCellWithTag:FIT_AVERAGE] setEnabled:NO ]; // [ [fitTypeMatrix findCellWithTag:FIT_MAXLIKE] setEnabled:YES ]; [emptyBinButton setEnabled:YES]; } funcList = [plot functionList]; itype = [fitTypeMatrix selectedRow]; if ( funcList && [funcList count] ) { func = [funcList objectAt:0]; itype = [func ebType]; [emptyBinMatrix selectCellAt:itype :0]; [emptyBinButton setTitle:emptyBinTitle[itype]]; itype = [func fitType]; [fitTypeMatrix selectCellWithTag:itype]; [fitTypeButton setTitle:doFitTitle[itype]]; } if (! [[fitTypeMatrix selectedCell] isEnabled]) { itype = FIT_ONESAMPLE; [fitTypeMatrix selectCellWithTag:itype]; [fitTypeButton setTitle:doFitTitle[itype]]; [self fitTypeChanged:self]; } if ( itype == FIT_MAXLIKE ) [emptyBinButton setEnabled:NO]; return self; } /* Delegate Methods for NXBrowsers */ - (int) browser: sender fillMatrix: matrix inColumn: (int) column { unsigned int count; switch (column) { case 0: count = [self fillColumnZeroMatrix:matrix]; break; case 1: count = [self fillColumnOneMatrix:matrix]; break; default: count = 0; } return count; } - (int) fillColumnZeroMatrix:matrix { List *funcList; NXBrowserCell *aCell; unsigned int i, count; funcList = [self functionList]; count = [funcList count]; for ( i = 0; i < count; i++ ) { [matrix insertRowAt:i]; aCell = [matrix cellAt:i :0]; [aCell setStringValue:[[funcList objectAt:i] title]]; [aCell setLeaf:NO]; [aCell setLoaded:YES]; } return count; } - (int) fillColumnOneMatrix:matrix { List *funcList; Matrix *funcMatrix; NXBrowserCell *aCell; PFunction *func; unsigned int count; int i; count = 0; funcMatrix = [funcBrowser matrixInColumn:0]; i = [funcMatrix selectedRow]; if ( i < 0 ) { i = 0; } funcList = [self functionList]; func = [funcList objectAt:i]; if ( !func ) return count; count = [func numberArgs]; for ( i = 0; i < count; i++ ) { [matrix insertRowAt:i]; aCell = [matrix cellAt:i :0]; [aCell setStringValue:[func argNameAt:i]]; [[aCell setLeaf:YES] setLoaded:YES]; } return count; } @end /* Private Methods */ @implementation InspectPFunc(Private) - (NXBundle *) compile:(const char *)directory :(const char *)file { NXBundle *bundle; struct stat statbuf; char basename[MAXNAMLEN+1]; char ofile[MAXPATHLEN+1]; char sys_cmd[MAXPATHLEN+1]; char inclpath[MAXPATHLEN+1]; char *ptr; BOOL ok; strcpy( basename, file ); ptr = strrchr( basename, '.' ); *ptr = '\0'; sprintf( ofile, "/tmp/%s", basename ); strcat( ofile, ".bundle"); if ( stat(ofile, &statbuf) ) { sprintf( sys_cmd, "mkdir %s", ofile ); if ( system( sys_cmd ) ) { return nil; } } strcat( ofile, "/"); strcat( ofile, basename ); chdir(directory); ok = [[NXBundle mainBundle] getPath:inclpath forResource:"PFunction" ofType:"h"]; if ( !ok ) { NXRunAlertPanel( "Error", "Can not find needed include files in HippoDraw.app", "OK", NULL, NULL ); return nil; } ptr = strrchr(inclpath, '/'); *ptr = '\0'; #ifdef GPPCOMPILE sprintf(sys_cmd, "cc -ObjC++ -g -O -Wall -I%s -I%s -c %s -o %s.o", inclpath, GPPINCLUDEDIR, file, ofile ); #else sprintf(sys_cmd, "cc -g -O -Wall -I%s -c %s -o %s.o", inclpath, file, ofile ); #endif if ( system( sys_cmd ) ) { return nil; } #ifdef GPPCOMPILE sprintf( sys_cmd, "ld -r -o %s %s.o %s", ofile, ofile, GPPLIBRARY ); #else sprintf( sys_cmd, "ld -r -o %s %s.o", ofile, ofile); #endif if ( system( sys_cmd ) ) { return nil; } sprintf( sys_cmd, "rm -f %s.o", ofile); system( sys_cmd ); ptr = strrchr( ofile, '/' ); *ptr = '\0'; bundle = [[NXBundle alloc] initForDirectory:ofile]; return bundle; } - enableButtons:(BOOL) flag { [parmForm setEnabled:flag]; [parmSlider setEnabled:flag]; [parmSliderU setEnabled:flag]; [parmSliderD setEnabled:flag]; [fixMatrix setEnabled:flag]; [doFitButton setEnabled:flag]; return self; } - getFitData { id funcList = [selectedPlot functionList]; if (!funcList) return self; if (fitNtuple == NULL) fitNtuple = h_new( 4 ); fcnParms.disp = [selectedPlot histDisplay]; fcnParms.fitType = (FCNType) [[funcList objectAt:0] fitType]; h_fillWithFitData(fcnParms.disp, fitNtuple, (fcnParms.fitType == FIT_MAXLIKE) ); fcnParms.x = h_getNtColumn( fitNtuple, 0 ); fcnParms.xerr = h_getNtColumn( fitNtuple, 1 ); fcnParms.y = h_getNtColumn( fitNtuple, 2 ); fcnParms.yerr = h_getNtColumn( fitNtuple, 3 ); fcnParms.npts = h_getNtNdata( fitNtuple ); fcnParms.ebType = [[funcList objectAt:0] ebType]; return self; } - loadFunction:(const char *)directory :(const char *)file { NXBundle *bundle; PFunction *func; bundle = [self compile:directory :file]; if ( bundle ) { func = [[[bundle principalClass] allocFromZone:[self zone]] init]; [availFuncList addObject:func]; [dynamFuncList addObject:func]; [func readFile:directory :file]; } return self; } - loadMinuit { List *funcList; /* current function List */ int nFunc; Storage *parmList; int nParms; int type; int i, j; int iparm = 1; /* the Minuit index of a parameter */ fitParm *parm; if ( ![selectedPlot hasFunction] ) return self; [fitter clearParms]; funcList = [selectedPlot functionList]; nFunc = [funcList count]; type = [parmRadio selectedRow]; for ( i = 0; i < nFunc; i++) { parmList = [[funcList objectAt:i] parmListOfType:type]; nParms = [parmList count]; for ( j = 0; j < nParms; j++ ) { parm = (fitParm *)[parmList elementAt:j]; [fitter setParms:parm at:iparm]; iparm++; } } /* * For fixed normalization fits, add Lagrange multiplier. */ if ([[funcList objectAt:0] fitType] == FIT_INTFIXEDNORM) { [fitter setLagrangeAt:iparm]; } return self; } - updateChiSq: (float) chi2 { [chiSqForm setDoubleValue:chi2 at:CHISQ_POS]; // don't update DoF form. it won't have changed return self; } - updateDoF { List *funcList = [selectedPlot functionList]; Storage *parmList; PFunction *func; fitParm *parm; parm_t type = [parmRadio selectedRow]; int i, j, num_parms; int dof; if (fitNtuple == NULL) [self getFitData]; dof = h_getNtNdata( fitNtuple ); if (!funcList) { [chiSqForm setEnabled:NO]; return self; } else { [chiSqForm setEnabled:YES]; } for ( i = [funcList count]-1; i>=0 ; i-- ) { func = [funcList objectAt:i]; dof -= [func numberArgs]; parmList = [func parmListOfType:type]; num_parms = [parmList count]; for ( j = 0; j < num_parms; j++ ) { parm = [parmList elementAt:j]; if (parm->fixedValue) dof++; } } [chiSqForm setIntValue:dof at:DOF_POS]; return self; } - doSingleFit:sender { List *funcList; /* current function List */ parm_t type; int i; if ( !selectedPlot ) return self; funcList = [selectedPlot functionList]; if ( !funcList ) return self; if ( !fitter ) { [hDraw loadMinuit:self]; } [sender getFrame:&stopButtonFrame]; old_fcn_value = FLT_MAX; type = [parmRadio selectedRow]; [funcList makeObjectsPerform:@selector(copyToInitial:) with:(id)&type]; [self getFitData]; /* * check if there are bins with error = 0 and flag if desired. */ if ( (fcnParms.ebType == EB_NOFIT) && (fcnParms.fitType == FIT_ONESAMPLE || fcnParms.fitType == FIT_INTEGRAL || fcnParms.fitType == FIT_INTFIXEDNORM) ) { for ( i = 0; i < fcnParms.npts; i++ ) { if ( fcnParms.y[i] == 0.0 ) { NXRunAlertPanel( "Alert", "Histogram has bins that are empty. " "No fit will been done. " "Check empty bins options in Fit Options Inspector.", NULL, NULL, NULL ); return self; } } } [self loadMinuit]; [funcList makeObjectsPerform:@selector(copyToFitted:) with:(id)&type]; [self setParmType:FIT_VALUES]; [fitter doFitWith:&fcnParms]; // Fit is done. Update the displays NXBeep(); [self fetchMinuit]; [self updateParmForm]; [self updateChiSq]; [self updatePlot]; [selectedPlot setFitted:YES]; [[[graphicView window] delegate] dirty:self]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.