package hep.aida.ref.pdf;

import hep.aida.IFitData;
import hep.aida.IFunction;
import hep.aida.dev.IDevFitData;
import hep.aida.dev.IDevFitDataIterator;
import hep.aida.ext.IFitMethod;
import hep.aida.ext.IOptimizer;
import hep.aida.ext.IOptimizerConfiguration;
import hep.aida.ext.IOptimizerFactory;
import hep.aida.ext.IVariableSettings;
import hep.aida.ref.fitter.fitdata.FitDataCreator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import org.freehep.util.FreeHEPLookup;
import org.openide.util.Lookup;

/**
 * Another implementation of IFitter.
 *
 * @author The FreeHEP team @ SLAC.
 *
 */
public class PdfFitter {

    // The IOptimizer.
    private String engineType;
    private IOptimizer optimizer = null;
    
    // The IFitMethod.
    private String fitMethodType;
    private IFitMethod fitMethod = null;

    // Internal configuration
    private boolean useGradient = true;

    public PdfFitter(String fitMethodType, String engineType) throws IllegalArgumentException {
        setFitMethod(fitMethodType);
        setEngine(engineType);
    }
    
    public void setEngine(String engineType) throws IllegalArgumentException {
        if (engineType == null || engineType.length() == 0) engineType = "uncmin";
        String enType = engineType.toLowerCase();
        
        IOptimizerFactory tmpOptimizerFactory = null;
        Lookup.Template template = new Lookup.Template(IOptimizerFactory.class);
        Lookup.Result result = FreeHEPLookup.instance().lookup(template);
        Collection c = result.allInstances();
        for (Iterator i = c.iterator(); i.hasNext(); ) {
            IOptimizerFactory of = (IOptimizerFactory)i.next();
            String[] names = of.optimizerFactoryNames();
            if ( names == null || names.length == 0 )
                throw new IllegalArgumentException("IOptimizerFactory with illegal names!");
            for ( int j = 0; j < names.length; j++ ) {
                if ( enType.equals( names[j].toLowerCase() ) ) {
                    tmpOptimizerFactory = of;
                    break;
                }
            }
        }
        if (tmpOptimizerFactory == null) throw new IllegalArgumentException("Cannot create IOptimizer of type: "+engineType);
        this.engineType = engineType;
        this.optimizer = tmpOptimizerFactory.create(engineType);
    }
    public String engineName() {
        return engineType;
    }

    public static IFitMethod getFitMethod(String fitMethodType) throws IllegalArgumentException {
        // Check the lookup table to look for the fitMethod of the given type.
        String fitMet = fitMethodType.toLowerCase();

        IFitMethod tmpFitMethod = null;
        Lookup.Template template = new Lookup.Template(IFitMethod.class);
        Lookup.Result result = FreeHEPLookup.instance().lookup(template);
        Collection c = result.allInstances();
        for (Iterator i = c.iterator(); i.hasNext(); ) {
            IFitMethod fm = (IFitMethod)i.next();
            String[] names = fm.fitMethodNames();
            if ( names == null || names.length == 0 )
                throw new IllegalArgumentException("IFitMethod with illegal names!");
            for ( int j = 0; j < names.length; j++ ) {
                if ( fitMet.equals( names[j].toLowerCase() ) ) {
                    tmpFitMethod = fm;
                    break;
                }
            }
        }
        if (tmpFitMethod == null) throw new IllegalArgumentException("Unknown IFitMethod type: "+fitMethodType);
        return tmpFitMethod;
    }

    public void setFitMethod(String fitMethodType) throws IllegalArgumentException {
        if (fitMethodType == null || fitMethodType.length() == 0) fitMethodType = "chi2";
        this.fitMethodType = fitMethodType;
        this.fitMethod = getFitMethod(fitMethodType);
    }
    
    public String fitMethodName() {
        return fitMethodType;
    }
    
    public void fit(Object[] objs, Function[] functions) {
        IFitData[] data = new IFitData[objs.length];
        for ( int i = 0; i < data.length; i++ )
            data[i] = FitDataCreator.create(objs[i]); 
        fit( data, functions);
    }
    
    public void fit(IFitData[] data, Function[] functions) {
        int nData = data.length;        
        if ( nData != functions.length )
            throw new IllegalArgumentException("Inconsistent number of data sets ("+nData+") and functions ("+functions.length+").");
        
        int fitType = fitMethod.fitType();
        for ( int i = 0; i < nData; i++ ) {
            if ( fitType != ( (IDevFitData) data[i] ).fitType() ) throw new IllegalArgumentException("This FitData is incompatible with the selected fit method");
            if ( data[i].dimension() != functions[i].numberOfDependents() ) throw new IllegalArgumentException("Dimension mismatch!! Function's dimension "+functions[i].numberOfDependents()+" FitData's dimension "+data[i].dimension());
        }

        // For simultaneous fits the normalization parameter of the functions have to have different names.
        // The name is changed before the fit and changed back after the fit.
        if ( nData > 1 )
            for ( int i = 0; i < nData; i++ )
                functions[i].getNormalizationParameter().setName("norm_"+i);
        
        
        
        fitMethod.clear();
        optimizer.reset();
        
        setErrorDefinition();
        
        boolean normalizeFunction = fitType == IFitMethod.UNBINNED_FIT; 
        for ( int i = 0; i < nData; i++ ) 
            functions[i].normalize(normalizeFunction);
        
        InternalObjectiveFunction objectiveFunction = new InternalObjectiveFunction(data, functions, fitMethod);
        
        for( int i = 0; i < objectiveFunction.dimension(); i++ ) {
            Parameter p = objectiveFunction.getVariable(i);
            IVariableSettings varSet = optimizer.variableSettings(p.name());
            varSet.setValue( p.value() );
            varSet.setFixed( p.isFixed() );
                        
            double stepSize = p.stepSize();
            if ( Double.isNaN( stepSize ) ) {
                stepSize = 0.1*Math.abs(p.value());
                if ( stepSize < 1 ) stepSize = 1;
            }
            varSet.setStepSize( stepSize );
            if ( p.useBounds() )
                varSet.setBounds( p.lowerBound(), p.upperBound() );
        }
        
        optimizer.setFunction(objectiveFunction);
        
        optimizer.configuration().setUseFunctionGradient(objectiveFunction.providesGradient() && useFunctionGradient());
        
        optimizer.configuration().setMaxIterations(500);
        //        optimizer.configuration().setPrintLevel(-2);

        optimizer.optimize();
        
        // Change back the name of the normalization parameter.
        if ( nData > 1 )
            for ( int i = 0; i < nData; i++ )
                functions[i].getNormalizationParameter().setName("norm");
        
    }
    
    public void fit(Object obj, Function function) {
        IFitData data = FitDataCreator.create(obj); 
        fit( data, function);
    }
    
    public void fit(IFitData data, Function function) {
        
        fit( new IFitData[] {data}, new Function[] { function } );

        /*
        int status = optimizer.result().optimizationStatus();
        int dataEntries = ((FitFunction) fitFunction).dataEntries();
        int freePars = ((FitFunction) fitFunction).nFreePars();
        int nDoF = dataEntries - freePars;
        double funcVal = fitFunction.value(f.parameters());
        
        IDevFitResult result = new FitResult(fitFunction.dimension(), fitSeconds);
        result.setConstraints( constraints() );
        result.setDataDescription( d.dataDescription() );
        result.setEngineName( engineName() );
        result.setFitMethodName( fitMethodName() );
        result.setFitStatus( status );
        result.setFittedFunction( f ); // FIX ME! Replace with clone.
        result.setIsValid( true ); ////??????
        result.setNdf( nDoF );
        
        if ( fitMethod.fitType() == IFitMethod.UNBINNED_FIT )
            result.setQuality( funcVal/nDoF/Math.sqrt(2.) );
        else
            result.setQuality( funcVal/nDoF );
         */
    }


    public boolean useFunctionGradient() {
        return useGradient;
    }
    public void setUseFunctionGradient(boolean useGradient) {
        this.useGradient = useGradient;
    }
    
    private void setErrorDefinition() {
        if ( fitMethod.fitType() == IFitMethod.BINNED_FIT )
            optimizer.configuration().setErrorDefinition(IOptimizerConfiguration.CHI2_FIT_ERROR);
        else
            optimizer.configuration().setErrorDefinition(IOptimizerConfiguration.LOGL_FIT_ERROR);
    }

}
 

Ads help maintain this website.