Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service Provider for applying enhancements #1369

Merged
merged 15 commits into from
Jul 18, 2024
2 changes: 1 addition & 1 deletion cdm/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ apply from: "$rootDir/gradle/any/protobuf.gradle"

dependencies {
api enforcedPlatform(project(':netcdf-java-platform'))
implementation 'commons-math:commons-math'
implementation 'org.apache.commons:commons-math3'

testImplementation enforcedPlatform(project(':netcdf-java-testing-platform'))

Expand Down
39 changes: 16 additions & 23 deletions cdm/core/src/main/java/ucar/nc2/dataset/VariableDS.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
*/
public class VariableDS extends Variable implements VariableEnhanced, EnhanceScaleMissingUnsigned {



/**
* Constructor when there's no underlying variable.
* You must also set the values by doing one of:
Expand Down Expand Up @@ -269,8 +271,10 @@ Array convert(Array data, Set<NetcdfDataset.Enhance> enhancements) {
// datatype of the result depends on what enhancements were applied
DataType convertedType = data.getDataType();


// TODO: change to a provider for extensible Enhancements
List<Enhancement> toApply = new ArrayList<>();

if (enhancements.contains(Enhance.ConvertUnsigned) && unsignedConversion != null) {
toApply.add(unsignedConversion);
convertedType = unsignedConversion.getOutType();
Expand All @@ -283,15 +287,9 @@ Array convert(Array data, Set<NetcdfDataset.Enhance> enhancements) {
toApply.add(scaleOffset);
convertedType = scaleOffset.getScaledOffsetType();
}
if (enhancements.contains(Enhance.ApplyStandardizer) && standardizer != null) {
toApply.add(standardizer);
}
if (enhancements.contains(Enhance.ApplyNormalizer) && normalizer != null) {
toApply.add(normalizer);
}
if (enhancements.contains(Enhance.ApplyClassifier) && classifier != null) {
toApply.add(classifier);
}

toApply.addAll(loadedEnhancements);


double[] dataArray = (double[]) data.get1DJavaArray(DataType.DOUBLE);

Expand Down Expand Up @@ -866,9 +864,8 @@ public Array convert(Array in, boolean convertUnsigned, boolean applyScaleOffset
// TODO make immutable in version 6
private UnsignedConversion unsignedConversion;
private ScaleOffset scaleOffset;
private Standardizer standardizer;
private Normalizer normalizer;
private Classifier classifier;
private List<Enhancement> loadedEnhancements = new ArrayList<>();

private ConvertMissing convertMissing;
private Set<Enhance> enhanceMode = EnumSet.noneOf(Enhance.class); // The set of enhancements that were made.

Expand Down Expand Up @@ -935,18 +932,14 @@ private void createEnhancements() {
}
this.dataType = scaleOffset != null ? scaleOffset.getScaledOffsetType() : this.dataType;
}
Attribute standardizerAtt = findAttribute(CDM.STANDARDIZE);
if (standardizerAtt != null && this.enhanceMode.contains(Enhance.ApplyStandardizer) && dataType.isFloatingPoint()) {
this.standardizer = Standardizer.createFromVariable(this);
}
Attribute normalizerAtt = findAttribute(CDM.NORMALIZE);
if (normalizerAtt != null && this.enhanceMode.contains(Enhance.ApplyNormalizer) && dataType.isFloatingPoint()) {
this.normalizer = Normalizer.createFromVariable(this);
}
Attribute classifierAtt = findAttribute(CDM.CLASSIFY);
if (classifierAtt != null && this.enhanceMode.contains(Enhance.ApplyClassifier) && dataType.isNumeric()) {
this.classifier = Classifier.createFromVariable(this);
for (Enhance enhance : this.enhanceMode) {
for (EnhancementProvider service : ServiceLoader.load(EnhancementProvider.class)) {
if (service.appliesTo(enhance, this.attributes(), dataType)) {
loadedEnhancements.add(service.Create(this));
}
}
}

}

public Builder<?> toBuilder() {
Expand Down
32 changes: 29 additions & 3 deletions cdm/core/src/main/java/ucar/nc2/filter/Classifier.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package ucar.nc2.filter;


import ucar.ma2.Array;
import ucar.ma2.IndexIterator;
import ucar.nc2.Variable;
import ucar.nc2.constants.CDM;
import ucar.nc2.Attribute;
import ucar.nc2.dataset.NetcdfDataset.Enhance;
import ucar.nc2.dataset.VariableDS;
import ucar.nc2.util.Misc;
import java.util.ArrayList;
import java.util.List;
import ucar.ma2.*;
import ucar.nc2.*;


public class Classifier implements Enhancement {


private String[] AttCat;
private List<int[]> rules = new ArrayList<>();

private static String name = "Classifier";



public Classifier() {
this.AttCat = new String[0];
this.rules = new ArrayList<>();
Expand All @@ -27,7 +35,8 @@ public Classifier(String[] AttCat) {
}

// Factory method to create a Classifier from a Variable
public static Classifier createFromVariable(Variable var) {

public static Classifier createFromVariable(VariableDS var) {
List<Attribute> attributes = var.attributes().getAttributes();

for (Attribute attribute : attributes) {
Expand Down Expand Up @@ -116,4 +125,21 @@ public static int[] stringToIntArray(String str) {
return intArray;
}

public static class Provider implements EnhancementProvider {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you make another commit, remove these spaces just to keep things clean



@Override
public boolean appliesTo(Enhance enhance, AttributeContainer attributes, DataType dt) {
return enhance == Enhance.ApplyClassifier && attributes.findAttribute(CDM.CLASSIFY) != null && dt.isNumeric();
}

@Override
public Classifier Create(VariableDS var) {
return createFromVariable(var);
}
}

}


26 changes: 26 additions & 0 deletions cdm/core/src/main/java/ucar/nc2/filter/EnhancementProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2021 University Corporation for Atmospheric Research/Unidata
* See LICENSE for license information.
*/

package ucar.nc2.filter;

import ucar.ma2.*;
import ucar.nc2.*;
import ucar.nc2.dataset.NetcdfDataset.Enhance;
import ucar.nc2.dataset.VariableDS;


/**
* A Service Provider of {@link Enhancement}.
*/
public interface EnhancementProvider {

boolean appliesTo(Enhance enhance, AttributeContainer attributes, DataType dt);

Enhancement Create(VariableDS var);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should start with lower case for method names in java, so let's make it create

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1



}


27 changes: 25 additions & 2 deletions cdm/core/src/main/java/ucar/nc2/filter/Normalizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.math.stat.descriptive.SummaryStatistics;
import ucar.nc2.constants.CDM;
import java.util.Set;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import ucar.ma2.Array;
import ucar.ma2.DataType;
import ucar.ma2.IndexIterator;
import ucar.nc2.AttributeContainer;
import ucar.nc2.Variable;
import ucar.nc2.dataset.NetcdfDataset.Enhance;
import ucar.nc2.dataset.VariableDS;

public class Normalizer implements Enhancement {

private final ScaleOffset scaleOffset;
private final double minimum;
private final double range; // maximum - minimum
private static String name = "Normalizer";

public static Normalizer createFromVariable(VariableDS var) {
try {
Expand Down Expand Up @@ -72,4 +77,22 @@ public double getRange() {
return range;
}

public static class Provider implements EnhancementProvider {


@Override
public boolean appliesTo(Enhance enhance, AttributeContainer attributes, DataType dt) {
return enhance == Enhance.ApplyNormalizer && attributes.findAttribute(CDM.NORMALIZE) != null
&& dt.isFloatingPoint();
}

@Override
public Normalizer Create(VariableDS var) {
return Normalizer.createFromVariable(var);
}



}

}
3 changes: 3 additions & 0 deletions cdm/core/src/main/java/ucar/nc2/filter/ScaleOffset.java
Original file line number Diff line number Diff line change
Expand Up @@ -290,5 +290,8 @@ public int getId() {
public Filter create(Map<String, Object> properties) {
return new ScaleOffset(properties);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to commit changes to this file at all it seems :)


}


}
24 changes: 23 additions & 1 deletion cdm/core/src/main/java/ucar/nc2/filter/Standardizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import ucar.nc2.constants.CDM;

import org.apache.commons.math.stat.descriptive.SummaryStatistics;
import java.util.Set;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import ucar.ma2.Array;
import ucar.ma2.DataType;
import ucar.ma2.IndexIterator;
import ucar.nc2.AttributeContainer;
import ucar.nc2.dataset.NetcdfDataset.Enhance;
import ucar.nc2.dataset.VariableDS;

public class Standardizer implements Enhancement {

private final ScaleOffset scaleOffset;
private final double mean;
private final double stdDev;
private static String name = "Standardizer";

public static Standardizer createFromVariable(VariableDS var) {
try {
Expand Down Expand Up @@ -71,5 +76,22 @@ public double getMean() {
public double getStdDev() {
return stdDev;
}



public static class Provider implements EnhancementProvider {


@Override
public boolean appliesTo(Enhance enhance, AttributeContainer attributes, DataType dt) {
return enhance == Enhance.ApplyStandardizer && attributes.findAttribute(CDM.STANDARDIZE) != null
&& dt.isFloatingPoint();
}

@Override
public Standardizer Create(VariableDS var) {
return createFromVariable(var);
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ucar.nc2.filter.Classifier$Provider
ucar.nc2.filter.Standardizer$Provider
ucar.nc2.filter.Normalizer$Provider



Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
import ucar.nc2.dataset.NetcdfDatasets;
import ucar.nc2.dataset.VariableDS;
import ucar.nc2.filter.Classifier;
import ucar.unidata.util.test.TestDir;

Expand All @@ -33,7 +34,7 @@ public void testEnhanceClassifier_Ints() throws IOException {
assertThat((Object) classifySpecs).isNotNull();
assertThat(!classifySpecs.attributes().isEmpty()).isTrue();
Array Data = classifySpecs.read();
Classifier classifier = Classifier.createFromVariable(classifySpecs);
Classifier classifier = Classifier.createFromVariable((VariableDS) classifySpecs);
int[] ClassifiedArray = classifier.classifyWithAttributes(Data);
assertThat(nearlyEquals(Array.makeFromJavaArray(ClassifiedArray), DATA_mixNumbers)).isTrue();

Expand All @@ -53,7 +54,7 @@ public void testEnhanceClassifier_Floats() throws IOException {
assertThat((Object) classifySpecs).isNotNull();
assertThat(!classifySpecs.attributes().isEmpty()).isTrue();
Array Data = classifySpecs.read();
Classifier classifier = Classifier.createFromVariable(classifySpecs);
Classifier classifier = Classifier.createFromVariable((VariableDS) classifySpecs);
int[] ClassifiedArray = classifier.classifyWithAttributes(Data);
assertThat(nearlyEquals(Array.makeFromJavaArray(ClassifiedArray), DATA_mixNumbers)).isTrue();

Expand All @@ -73,7 +74,7 @@ public void testEnhanceClassifier_classification() throws IOException {
assertThat((Object) classifySpecs).isNotNull();
assertThat(!classifySpecs.attributes().isEmpty()).isTrue();
Array Data = classifySpecs.read();
Classifier classifier = Classifier.createFromVariable(classifySpecs);
Classifier classifier = Classifier.createFromVariable((VariableDS) classifySpecs);
int[] ClassifiedArray = classifier.classifyWithAttributes(Data);
assertThat(nearlyEquals(Array.makeFromJavaArray(ClassifiedArray), CLASSIFICATION_TEST)).isTrue();

Expand Down
2 changes: 1 addition & 1 deletion netcdf-java-platform/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ dependencies {
api 'com.beust:jcommander:1.78'

// cdm-core
api 'commons-math:commons-math:1.2'
api 'org.apache.commons:commons-math3:3.6.1'

// cdm-grib
api 'edu.ucar:jj2000:5.4'
Expand Down
Loading