← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 468: Added OutlierAnalysis service classes

 

------------------------------------------------------------
revno: 468
committer: Lars Helge Oeverland larshelge@xxxxxxxxx
branch nick: trunk
timestamp: Sat 2009-07-25 13:08:28 +0200
message:
  Added OutlierAnalysis service classes
added:
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/AbstractStdDevOutlierAnalysisService.java
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/MinMaxOutlierAnalysisService.java
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/StdDevOutlierAnalysisService.java
  dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis/
  dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis/MinMaxOutlierAnalysisServiceTest.java
  dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis/StdDevOutlierAnalysisServiceTest.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription.
=== added directory 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis'
=== added file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/AbstractStdDevOutlierAnalysisService.java'
--- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/AbstractStdDevOutlierAnalysisService.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/AbstractStdDevOutlierAnalysisService.java	2009-07-25 11:08:28 +0000
@@ -0,0 +1,65 @@
+package org.hisp.dhis.outlieranalysis;
+
+/*
+ * Copyright (c) 2004-${year}, University of Oslo
+ * 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.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * 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 OWNER 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Queue;
+
+import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+
+/**
+ * @author Dag Haavi Finstad
+ * @version $Id: AbstractStdDevOutlierAnalysisService.java 1020 2009-06-05 01:30:07Z daghf $
+ */
+public abstract class AbstractStdDevOutlierAnalysisService
+    implements OutlierAnalysisService
+{
+    public final Collection<OutlierValue> findOutliers( Collection<? extends OrganisationUnit> organisationUnits,
+        Collection<DataElement> dataElements, Collection<Period> periods, Double stdDevFactor )
+    {
+        final Queue<OrganisationUnit> orgUnitQueue = new LinkedList<OrganisationUnit>( organisationUnits );
+        final Collection<OutlierValue> outlierCollection = new ArrayList<OutlierValue>();
+        
+        while ( !orgUnitQueue.isEmpty() )
+        {
+            final OrganisationUnit organisationUnit = orgUnitQueue.remove();
+            orgUnitQueue.addAll( organisationUnit.getChildren() );
+            
+            for ( DataElement dataElement : dataElements )
+            {
+                outlierCollection.addAll( findOutliers( organisationUnit, dataElement, periods, stdDevFactor ) );
+            }
+        }
+
+        return outlierCollection;
+    }
+}

=== added file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/MinMaxOutlierAnalysisService.java'
--- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/MinMaxOutlierAnalysisService.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/MinMaxOutlierAnalysisService.java	2009-07-25 11:08:28 +0000
@@ -0,0 +1,106 @@
+package org.hisp.dhis.outlieranalysis;
+
+/*
+ * Copyright (c) 2004-${year}, University of Oslo
+ * 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.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * 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 OWNER 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.
+ */
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.datavalue.DataValue;
+import org.hisp.dhis.datavalue.DataValueService;
+import org.hisp.dhis.minmax.MinMaxDataElement;
+import org.hisp.dhis.minmax.MinMaxDataElementService;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+
+/**
+ * 
+ * @author Dag Haavi Finstad
+ * @version $Id: DefaultMinMaxOutlierAnalysisService.java 1047 2009-06-10 11:01:04Z daghf $
+ */
+public class MinMaxOutlierAnalysisService
+    extends AbstractStdDevOutlierAnalysisService
+{
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    private MinMaxDataElementService minMaxDataElementService;
+
+    public void setMinMaxDataElementService( MinMaxDataElementService minMaxDataElementService )
+    {
+        this.minMaxDataElementService = minMaxDataElementService;
+    }
+
+    private DataValueService dataValueService;
+
+    public void setDataValueService( DataValueService dataValueService )
+    {
+        this.dataValueService = dataValueService;
+    }
+
+    // -------------------------------------------------------------------------
+    // MinMaxOutlierAnalysisService implementation
+    // -------------------------------------------------------------------------
+
+    public Collection<OutlierValue> findOutliers( OrganisationUnit organisationUnit, DataElement dataElement,
+        Collection<Period> periods, Double stdDevFactor )
+    {
+        final Collection<OutlierValue> outlierValues = new ArrayList<OutlierValue>();
+
+        if ( !dataElement.getType().equals( DataElement.TYPE_INT ) )
+        {
+            return outlierValues;
+        }
+
+        final Collection<MinMaxDataElement> minMaxDataElements = 
+            minMaxDataElementService.getMinMaxDataElements( organisationUnit, dataElement );
+
+        for ( MinMaxDataElement minMaxDataElement : minMaxDataElements )
+        {
+            int lowerBound = minMaxDataElement.getMin();
+            int upperBound = minMaxDataElement.getMax();
+            
+            for ( Period period : periods )
+            {    
+                final DataValue dataValue = dataValueService.getDataValue( 
+                    organisationUnit, dataElement, period, minMaxDataElement.getOptionCombo() );
+    
+                final int value = Integer.parseInt( dataValue.getValue() );
+        
+                if ( value < lowerBound || value > upperBound )
+                {
+                    outlierValues.add( new OutlierValue( dataValue, lowerBound, upperBound ) );
+                }
+            }
+        }        
+
+        return outlierValues;
+    }
+}

=== added file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/StdDevOutlierAnalysisService.java'
--- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/StdDevOutlierAnalysisService.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/outlieranalysis/StdDevOutlierAnalysisService.java	2009-07-25 11:08:28 +0000
@@ -0,0 +1,110 @@
+package org.hisp.dhis.outlieranalysis;
+
+/*
+ * Copyright (c) 2004-${year}, University of Oslo
+ * 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.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * 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 OWNER 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
+import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.datavalue.DataValue;
+import org.hisp.dhis.datavalue.DataValueService;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+
+/**
+ * 
+ * @author Dag Haavi Finstad
+ * @version $Id: DefaultStdDevOutlierAnalysisService.java 1020 2009-06-05 01:30:07Z daghf $
+ */
+public class StdDevOutlierAnalysisService
+    extends AbstractStdDevOutlierAnalysisService
+{
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    private DataValueService dataValueService;
+
+    public void setDataValueService( DataValueService dataValueService )
+    {
+        this.dataValueService = dataValueService;
+    }
+
+    // -------------------------------------------------------------------------
+    // OutlierAnalysisService implementation
+    // -------------------------------------------------------------------------
+
+    public Collection<OutlierValue> findOutliers( OrganisationUnit organisationUnit, 
+        DataElement dataElement, Collection<Period> periods, Double stdDevFactor )
+    {
+        final Collection<OutlierValue> outlierValues = new ArrayList<OutlierValue>();
+
+        if ( !dataElement.getType().equals( DataElement.TYPE_INT ) )
+        {
+            return outlierValues;
+        }
+
+        final Collection<DataValue> dataValues = dataValueService.getDataValues( organisationUnit, dataElement );
+        final DescriptiveStatistics statistics = new DescriptiveStatistics();
+        
+        final Map<Period, DataValue> dataValueMap = new HashMap<Period, DataValue>();        
+        
+        for ( DataValue dataValue : dataValues )
+        {
+            statistics.addValue( Double.parseDouble( dataValue.getValue() ) );
+            dataValueMap.put( dataValue.getPeriod(), dataValue );
+        }
+
+        double mean = statistics.getMean();
+        double standardDeviation = statistics.getStandardDeviation();
+        double lowerBound = mean - stdDevFactor * standardDeviation;
+        double upperBound = mean + stdDevFactor * standardDeviation;
+
+        for ( Period period : periods )
+        {
+            final DataValue dataValue = dataValueMap.get( period );
+
+            if ( dataValue == null )
+            {
+                continue;
+            }
+
+            final double value = Double.parseDouble( dataValue.getValue() );
+
+            if ( value < lowerBound || value > upperBound )
+            {
+                outlierValues.add( new OutlierValue( dataValue, lowerBound, upperBound ) );
+            }
+        }
+
+        return outlierValues;
+    }
+}

=== added directory 'dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis'
=== added file 'dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis/MinMaxOutlierAnalysisServiceTest.java'
--- dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis/MinMaxOutlierAnalysisServiceTest.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis/MinMaxOutlierAnalysisServiceTest.java	2009-07-25 11:08:28 +0000
@@ -0,0 +1,211 @@
+package org.hisp.dhis.outlieranalysis;
+
+/*
+ * Copyright (c) 2004-2007, University of Oslo
+ * 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.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * 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 OWNER 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.
+ */
+
+import static junit.framework.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.hisp.dhis.DhisSpringTest;
+import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryComboService;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.dataset.DataSetService;
+import org.hisp.dhis.datavalue.DataValue;
+import org.hisp.dhis.datavalue.DataValueService;
+import org.hisp.dhis.minmax.MinMaxDataElement;
+import org.hisp.dhis.minmax.MinMaxDataElementService;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
+import org.hisp.dhis.period.MonthlyPeriodType;
+import org.hisp.dhis.period.Period;
+import org.hisp.dhis.period.PeriodService;
+import org.junit.Test;
+
+/**
+ * @author eirikmi
+ * @version $Id: MinMaxOutlierAnalysisServiceTest.java 883 2009-05-15 00:42:45Z daghf $
+ */
+public class MinMaxOutlierAnalysisServiceTest
+    extends DhisSpringTest
+{
+    private OutlierAnalysisService minMaxOutlierAnalysisService;
+
+    private MinMaxDataElementService minMaxDataElementService;
+
+    private DataElement dataElementA;
+    private DataElement dataElementB;
+    private DataElement dataElementC;
+    private DataElement dataElementD;
+
+    private DataValue dataValueA;
+    private DataValue dataValueB;
+
+    private Set<DataElement> dataElementsA = new HashSet<DataElement>();
+    private Set<DataElement> dataElementsB = new HashSet<DataElement>();
+    private Set<DataElement> dataElementsC = new HashSet<DataElement>();
+
+    private DataElementCategoryCombo categoryCombo;
+
+    private DataElementCategoryOptionCombo categoryOptionCombo;
+
+    private Period periodA;
+    private Period periodB;
+    private Period periodC;
+    private Period periodD;
+    private Period periodE;
+    private Period periodF;
+    private Period periodG;
+    private Period periodH;
+    private Period periodI;
+    private Period periodJ;
+
+    private OrganisationUnit organisationUnitA;
+
+    private OrganisationUnit organisationUnitB;
+
+    private Set<OrganisationUnit> organisationUnitsA = new HashSet<OrganisationUnit>();
+
+    private MinMaxDataElement minMaxDataElement;
+
+    // ----------------------------------------------------------------------
+    // Fixture
+    // ----------------------------------------------------------------------
+
+    @Override
+    public void setUpTest()
+        throws Exception
+    {
+        minMaxOutlierAnalysisService = (MinMaxOutlierAnalysisService) getBean( "org.hisp.dhis.outlieranalysis.MinMaxOutlierAnalysisService" );
+
+        dataElementService = (DataElementService) getBean( DataElementService.ID );
+
+        minMaxDataElementService = (MinMaxDataElementService) getBean( MinMaxDataElementService.ID );
+
+        categoryComboService = (DataElementCategoryComboService) getBean( DataElementCategoryComboService.ID );
+
+        dataSetService = (DataSetService) getBean( DataSetService.ID );
+
+        organisationUnitService = (OrganisationUnitService) getBean( OrganisationUnitService.ID );
+
+        dataValueService = (DataValueService) getBean( DataValueService.ID );
+
+        periodService = (PeriodService) getBean( PeriodService.ID );
+
+        dataElementA = createDataElement( 'A' );
+        dataElementB = createDataElement( 'B' );
+        dataElementC = createDataElement( 'C' );
+        dataElementD = createDataElement( 'D' );
+
+        dataElementService.addDataElement( dataElementA );
+        dataElementService.addDataElement( dataElementB );
+        dataElementService.addDataElement( dataElementC );
+        dataElementService.addDataElement( dataElementD );
+
+        dataElementsA.add( dataElementA );
+        dataElementsA.add( dataElementB );
+        dataElementsB.add( dataElementC );
+        dataElementsB.add( dataElementD );
+        dataElementsC.add( dataElementB );
+
+        categoryCombo = categoryComboService.getDataElementCategoryComboByName( DataElementCategoryCombo.DEFAULT_CATEGORY_COMBO_NAME );
+
+        categoryOptionCombo = categoryCombo.getOptionCombos().iterator().next();
+
+        periodA = createPeriod( new MonthlyPeriodType(), getDate( 2000, 3, 1 ), getDate( 2000, 3, 31 ) );
+        periodB = createPeriod( new MonthlyPeriodType(), getDate( 2000, 4, 1 ), getDate( 2000, 4, 30 ) );
+        periodC = createPeriod( new MonthlyPeriodType(), getDate( 2000, 5, 1 ), getDate( 2000, 5, 30 ) );
+        periodD = createPeriod( new MonthlyPeriodType(), getDate( 2000, 6, 1 ), getDate( 2000, 6, 30 ) );
+        periodE = createPeriod( new MonthlyPeriodType(), getDate( 2000, 7, 1 ), getDate( 2000, 7, 30 ) );
+        periodF = createPeriod( new MonthlyPeriodType(), getDate( 2000, 8, 1 ), getDate( 2000, 8, 30 ) );
+        periodG = createPeriod( new MonthlyPeriodType(), getDate( 2000, 9, 1 ), getDate( 2000, 9, 30 ) );
+        periodH = createPeriod( new MonthlyPeriodType(), getDate( 2000, 10, 1 ), getDate( 2000, 10, 30 ) );
+        periodI = createPeriod( new MonthlyPeriodType(), getDate( 2000, 11, 1 ), getDate( 2000, 11, 30 ) );
+        periodJ = createPeriod( new MonthlyPeriodType(), getDate( 2000, 12, 1 ), getDate( 2000, 12, 30 ) );
+
+        organisationUnitA = createOrganisationUnit( 'A' );
+        organisationUnitB = createOrganisationUnit( 'B' );
+
+        organisationUnitService.addOrganisationUnit( organisationUnitA );
+        organisationUnitService.addOrganisationUnit( organisationUnitB );
+
+        organisationUnitsA.add( organisationUnitA );
+        organisationUnitsA.add( organisationUnitB );
+    }
+
+    // ----------------------------------------------------------------------
+    // Business logic tests
+    // ----------------------------------------------------------------------
+
+    @Test
+    public void testGetFindOutliers()
+    {
+        // testvalues = [5, 5, -5, -5, 10, -10, 13, -13, 41, -41]
+        // mean(testvalues) = 0.0
+        // std(testvalues) = 20.0
+        
+        dataValueA = createDataValue( dataElementA, periodI, organisationUnitA, "41", categoryOptionCombo );
+        dataValueB = createDataValue( dataElementA, periodJ, organisationUnitA, "-41", categoryOptionCombo );
+
+        dataValueService.addDataValue( createDataValue( dataElementA, periodA, organisationUnitA, "5", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodB, organisationUnitA, "-5", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodC, organisationUnitA, "5", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodD, organisationUnitA, "-5", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodE, organisationUnitA, "10", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodF, organisationUnitA, "-10", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodG, organisationUnitA, "13", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodH, organisationUnitA, "-13", categoryOptionCombo ) );
+        
+        dataValueService.addDataValue( dataValueA );
+        dataValueService.addDataValue( dataValueB );
+        
+        minMaxDataElement = new MinMaxDataElement( organisationUnitA, dataElementA, categoryOptionCombo, -40, 40, false );
+        minMaxDataElementService.addMinMaxDataElement( minMaxDataElement );
+
+        Collection<Period> periods = new ArrayList<Period>();
+        periods.add( periodI );
+        periods.add( periodJ );
+        periods.add( periodA );
+        periods.add( periodE );
+
+        Collection<OutlierValue> result = minMaxOutlierAnalysisService.findOutliers( 
+            organisationUnitsA, dataElementsA, periods, null );
+
+        Collection<OutlierValue> ref = new ArrayList<OutlierValue>();
+        ref.add( new OutlierValue( dataValueA, minMaxDataElement.getMin(), minMaxDataElement.getMax() ) );
+        ref.add( new OutlierValue( dataValueB, minMaxDataElement.getMin(), minMaxDataElement.getMax() ) );
+
+        assertEquals( result.size(), 2 );
+        assertEquals( result, ref );
+    }
+}

=== added file 'dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis/StdDevOutlierAnalysisServiceTest.java'
--- dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis/StdDevOutlierAnalysisServiceTest.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/outlieranalysis/StdDevOutlierAnalysisServiceTest.java	2009-07-25 11:08:28 +0000
@@ -0,0 +1,198 @@
+package org.hisp.dhis.outlieranalysis;
+
+/*
+ * Copyright (c) 2004-2007, University of Oslo
+ * 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.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * 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 OWNER 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.
+ */
+
+import static junit.framework.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.hisp.dhis.DhisSpringTest;
+import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryComboService;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.dataset.DataSetService;
+import org.hisp.dhis.datavalue.DataValue;
+import org.hisp.dhis.datavalue.DataValueService;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
+import org.hisp.dhis.period.MonthlyPeriodType;
+import org.hisp.dhis.period.Period;
+import org.hisp.dhis.period.PeriodService;
+import org.junit.Test;
+
+/**
+ * @author eirikmi
+ * @version $Id: StdDevOutlierAnalysisServiceTest.java 883 2009-05-15 00:42:45Z daghf $
+ */
+public class StdDevOutlierAnalysisServiceTest
+    extends DhisSpringTest
+{
+    private OutlierAnalysisService stdDevOutlierAnalysisService;
+
+    private DataElement dataElementA;
+    private DataElement dataElementB;
+    private DataElement dataElementC;
+    private DataElement dataElementD;
+
+    private DataValue dataValueA;
+    private DataValue dataValueB;
+
+    private Set<DataElement> dataElementsA = new HashSet<DataElement>();
+    private Set<DataElement> dataElementsB = new HashSet<DataElement>();
+    private Set<DataElement> dataElementsC = new HashSet<DataElement>();
+
+    private DataElementCategoryCombo categoryCombo;
+
+    private DataElementCategoryOptionCombo categoryOptionCombo;
+
+    private Period periodA;
+    private Period periodB;
+    private Period periodC;    
+    private Period periodD;    
+    private Period periodE;    
+    private Period periodF;    
+    private Period periodG;
+    private Period periodH;
+    private Period periodI;
+    private Period periodJ;
+
+    private OrganisationUnit organisationUnitA;
+    private OrganisationUnit organisationUnitB;
+
+    private Set<OrganisationUnit> organisationUnitsA = new HashSet<OrganisationUnit>();
+
+    // ----------------------------------------------------------------------
+    // Fixture
+    // ----------------------------------------------------------------------
+
+    @Override
+    public void setUpTest()
+    {
+        stdDevOutlierAnalysisService = (OutlierAnalysisService) getBean( "org.hisp.dhis.outlieranalysis.StdDevOutlierAnalysisService" );
+
+        dataElementService = (DataElementService) getBean( DataElementService.ID );
+
+        categoryComboService = (DataElementCategoryComboService) getBean( DataElementCategoryComboService.ID );
+
+        dataSetService = (DataSetService) getBean( DataSetService.ID );
+
+        organisationUnitService = (OrganisationUnitService) getBean( OrganisationUnitService.ID );
+        
+        dataValueService = (DataValueService) getBean( DataValueService.ID );
+
+        periodService = (PeriodService) getBean( PeriodService.ID );
+
+        dataElementA = createDataElement( 'A' );
+        dataElementB = createDataElement( 'B' );
+        dataElementC = createDataElement( 'C' );
+        dataElementD = createDataElement( 'D' );
+
+        dataElementService.addDataElement( dataElementA );
+        dataElementService.addDataElement( dataElementB );
+        dataElementService.addDataElement( dataElementC );
+        dataElementService.addDataElement( dataElementD );
+
+        dataElementsA.add( dataElementA );
+        dataElementsA.add( dataElementB );
+        dataElementsB.add( dataElementC );
+        dataElementsB.add( dataElementD );
+        dataElementsC.add( dataElementB );
+
+        categoryCombo = categoryComboService
+            .getDataElementCategoryComboByName( DataElementCategoryCombo.DEFAULT_CATEGORY_COMBO_NAME );
+
+        categoryOptionCombo = categoryCombo.getOptionCombos().iterator().next();
+
+        periodA = createPeriod( new MonthlyPeriodType(), getDate( 2000, 3, 1 ), getDate( 2000, 3, 31 ) );
+        periodB = createPeriod( new MonthlyPeriodType(), getDate( 2000, 4, 1 ), getDate( 2000, 4, 30 ) );
+        periodC = createPeriod( new MonthlyPeriodType(), getDate( 2000, 5, 1 ), getDate( 2000, 5, 30 ) );
+        periodD = createPeriod( new MonthlyPeriodType(), getDate( 2000, 6, 1 ), getDate( 2000, 6, 30 ) );
+        periodE = createPeriod( new MonthlyPeriodType(), getDate( 2000, 7, 1 ), getDate( 2000, 7, 30 ) );
+        periodF = createPeriod( new MonthlyPeriodType(), getDate( 2000, 8, 1 ), getDate( 2000, 8, 30 ) );
+        periodG = createPeriod( new MonthlyPeriodType(), getDate( 2000, 9, 1 ), getDate( 2000, 9, 30 ) );
+        periodH = createPeriod( new MonthlyPeriodType(), getDate( 2000, 10, 1 ), getDate( 2000, 10, 30 ) );
+        periodI = createPeriod( new MonthlyPeriodType(), getDate( 2000, 11, 1 ), getDate( 2000, 11, 30 ) );
+        periodJ = createPeriod( new MonthlyPeriodType(), getDate( 2000, 12, 1 ), getDate( 2000, 12, 30 ) );
+
+        organisationUnitA = createOrganisationUnit( 'A' );
+        organisationUnitB = createOrganisationUnit( 'B' );
+
+        organisationUnitService.addOrganisationUnit( organisationUnitA );
+        organisationUnitService.addOrganisationUnit( organisationUnitB );
+
+        organisationUnitsA.add( organisationUnitA );
+        organisationUnitsA.add( organisationUnitB );
+    }
+
+    // ----------------------------------------------------------------------
+    // Business logic tests
+    // ----------------------------------------------------------------------
+
+    @Test
+    public void testGetFindOutliers()
+    {
+        // testvalues = [5, 5, -5, -5, 10, -10, 13, -13, 71, -71]
+        // mean(testvalues) = 0.0
+        // std(testvalues) = 34.51
+        
+        dataValueA = createDataValue( dataElementA, periodI, organisationUnitA, "71", categoryOptionCombo );
+        dataValueB = createDataValue( dataElementA, periodJ, organisationUnitA, "-71", categoryOptionCombo );
+
+        dataValueService.addDataValue( createDataValue( dataElementA, periodA, organisationUnitA, "5", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodB, organisationUnitA, "-5", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodC, organisationUnitA, "5", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodD, organisationUnitA, "-5", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodE, organisationUnitA, "10", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodF, organisationUnitA, "-10", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodG, organisationUnitA, "13", categoryOptionCombo ) );
+        dataValueService.addDataValue( createDataValue( dataElementA, periodH, organisationUnitA, "-13", categoryOptionCombo ) );
+        dataValueService.addDataValue( dataValueA );
+        dataValueService.addDataValue( dataValueB );
+
+        double stdDevFactor = 2.0;
+        Collection<Period> periods = new ArrayList<Period>();
+        periods.add( periodI );
+        periods.add( periodJ );
+        periods.add( periodA );
+        periods.add( periodE );
+
+        Collection<OutlierValue> result = stdDevOutlierAnalysisService.findOutliers( 
+            organisationUnitsA, dataElementsA, periods, stdDevFactor );
+
+        Collection<OutlierValue> ref = new ArrayList<OutlierValue>();
+        ref.add( new OutlierValue( dataValueA, -34.51 * stdDevFactor, 34.51 * stdDevFactor ) );
+        ref.add( new OutlierValue( dataValueB, -34.51 * stdDevFactor, 34.51 * stdDevFactor ) );
+        assertEquals( result.size(), 2 );
+        assertEquals( result, ref );
+    }
+}