package etomica.data.meter;

import etomica.EtomicaInfo;
import etomica.atom.AtomLeaf;
import etomica.atom.iterator.AtomIteratorLeafAtoms;
import etomica.atom.iterator.AtomIteratorPhaseDependent;
import etomica.data.DataSourceScalar;
import etomica.math.geometry.Polytope;
import etomica.phase.Phase;
import etomica.species.Species;
import etomica.units.Fraction;

/**
 * Meter for measurement of species mole fraction within a specified subvolume
 */

public abstract class MeterLocalMoleFraction extends DataSourceScalar implements Meter
{
    public MeterLocalMoleFraction() {
        super("Local Mole Fraction",Fraction.DIMENSION);
        setSpecies(null);
    }

    public static EtomicaInfo getEtomicaInfo() {
        EtomicaInfo info = new EtomicaInfo("Local number density in a subregion of a phase");
        return info;
    }
    
    public void setShape(Polytope shape) {
        this.shape = shape;
    }

    public Polytope getShape() {
        return shape;
    }
    /**
     * Accessor method to set which species mole-fraction or molar-density is averaged
     * To set to total number density, invoke with static ALL_SPECIES field as argument
     */
    public final void setSpecies(Species s) {species = s;}
    /**
     * Accessor method to get the current value of the species index
     *
     * @see #setSpeciesIndex
     */
    public final Species getSpecies() {return species;}
    
    /**
     * @return the current value of the local density or local mole fraction
     */
    public double getDataAsScalar() {
        if (phase == null) throw new IllegalStateException("must call setPhase before using meter");
        int totalSum = 0, speciesSum = 0;
        iterator.reset();
        while(iterator.hasNext()) {
            AtomLeaf m = (AtomLeaf)iterator.nextAtom();
            if(shape.contains(m.coord.position())) {
                totalSum++;
                if(m.type.getSpecies() == species) speciesSum++;
            }
        }
        if(totalSum == 0) return Double.NaN;
        return (double)speciesSum/(double)totalSum;
    }
    
    /**
     * @return Returns the phase.
     */
    public Phase getPhase() {
        return phase;
    }
    /**
     * @param phase The phase to set.
     */
    public void setPhase(Phase phase) {
        this.phase = phase;
        iterator.setPhase(phase);
        if (shape == null) {
            setShape(phase.getBoundary().getShape());
        }
    }

    /**
     * @return Returns the iterator.
     */
    public AtomIteratorPhaseDependent getIterator() {
        return iterator;
    }
    /**
     * @param iterator The iterator to set.
     */
    public void setIterator(AtomIteratorPhaseDependent iterator) {
        this.iterator = iterator;
    }

    private Phase phase;
    /**
     * Class variable used to specify that all species are included in number-density calculation
     */
    private Species species;
    private AtomIteratorPhaseDependent iterator = new AtomIteratorLeafAtoms();
    private Polytope shape;
}

@@ -294,16 +294,45 @@
 .Phase;%0A
+import etomica.space.Vector;%0A
 import e
@@ -478,25 +478,15 @@
  */%0A
-%0A
 public 
-abstract 
 clas
@@ -555,10 +555,11 @@
 eter
+ %7B
 %0A
-%7B
 %0A   
@@ -849,28 +849,107 @@
 info;%0A    %7D%0A
+%0A
     
+/**%0A     * Sets the subvolume shape for the mole fraction calculation.%0A     */
 %0A    public 
@@ -1023,64 +1023,540 @@
     
-public Polytope getShape() %7B%0A        return shape;%0A    %7D
+/**%0A     * Returns the subvolume shape for the mole fraction calculation.%0A     */%0A    public Polytope getShape() %7B%0A        return shape;%0A    %7D%0A    %0A    /**%0A     * Sets the origin of the subvolume (Polytopes typically have their center%0A     * at 0).  The shape origin is 0 by default.%0A     */%0A    public void setShapeOrigin(Vector newShapeOrigin) %7B%0A        shapeOrigin = newShapeOrigin;%0A    %7D%0A    %0A    /**%0A     * Returns the origin of the subvolume.%0A     */%0A    public Vector getShapeOrigin() %7B%0A        return shapeOrigin;%0A    %7D%0A    
 %0A   
@@ -2341,17 +2341,17 @@
 tomLeaf 
-m
+a
  = (Atom
@@ -2392,44 +2392,94 @@
     
-if(shape.contains(m.coord.position()
+tempVec.Ev1Mv2(a.coord.position(), shapeOrigin);%0A            if(shape.contains(tempVec
 )) %7B
@@ -2526,17 +2526,17 @@
      if(
-m
+a
 .type.ge
@@ -2893,25 +2893,28 @@
 Phase(Phase 
-p
+newP
 hase) %7B%0A    
@@ -2921,26 +2921,120 @@
     
-this.phase = phase
+phase = newPhase;%0A        tempVec = phase.space().makeVector();%0A        shapeOrigin = phase.space().makeVector()
 ;%0A  
@@ -3467,24 +3467,77 @@
 tor;%0A    %7D%0A%0A
+    private static final long serialVersionUID = 1L;%0A
     private 
@@ -3799,10 +3799,70 @@
  shape;%0A
+    private Vector shapeOrigin;%0A    private Vector tempVec;%0A
 %7D%0A

make MeterMoleFraction not abstract (it has no abstract methods and no subclasses!) Add ability to specify an origin for the shape (since Polytops have their origin fixed) and misc cleanup.