Skip to content

Commit

Permalink
Support feature-specific offsets to allow for manual datum adjustment…
Browse files Browse the repository at this point in the history
…s or similar constant adjustments, #36.
  • Loading branch information
james-d-brown committed Aug 16, 2024
1 parent b1a52a7 commit 335b811
Show file tree
Hide file tree
Showing 34 changed files with 741 additions and 154 deletions.
283 changes: 231 additions & 52 deletions src/wres/pipeline/pooling/PoolFactory.java

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion test/wres/pipeline/EvaluationUtilitiesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import wres.config.yaml.components.EvaluationDeclaration;
import wres.config.yaml.components.EvaluationDeclarationBuilder;
import wres.config.yaml.components.FeatureGroups;
import wres.config.yaml.components.FeatureGroupsBuilder;
import wres.config.yaml.components.LeadTimeInterval;
import wres.config.yaml.components.ThresholdBuilder;
import wres.config.yaml.components.ThresholdType;
Expand Down Expand Up @@ -261,7 +262,9 @@ void testGetSummaryStatisticsCalculatorsWithTwoTimeWindowsAcrossFeatureGroups()

Set<GeometryGroup> geometryGroups = Set.of( firstGroup, secondGroup );

FeatureGroups featureGroups = new FeatureGroups( geometryGroups );
FeatureGroups featureGroups = FeatureGroupsBuilder.builder()
.geometryGroups( geometryGroups )
.build();

EvaluationDeclaration evaluation = EvaluationDeclarationBuilder.builder()
.leadTimes( leadTimeInterval )
Expand Down
16 changes: 9 additions & 7 deletions wres-config/nonsrc/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -566,9 +566,9 @@ definitions:
cross-pairing chosen."
anyOf:
- "$ref": "#/definitions/CrossPairEnum"
- "$ref": "#/definitions/CrossPairFull"
- "$ref": "#/definitions/CrossPairWithParameters"

CrossPairFull:
CrossPairWithParameters:
type: object
additionalProperties: false
properties:
Expand Down Expand Up @@ -665,25 +665,25 @@ definitions:
properties:
observed:
anyOf:
- "$ref": "#/definitions/FeatureTupleFull"
- "$ref": "#/definitions/FeatureWithParameters"
- type: string
minLength: 1
maxLength: 32
predicted:
anyOf:
- "$ref": "#/definitions/FeatureTupleFull"
- "$ref": "#/definitions/FeatureWithParameters"
- type: string
minLength: 1
maxLength: 32
baseline:
anyOf:
- "$ref": "#/definitions/FeatureTupleFull"
- "$ref": "#/definitions/FeatureWithParameters"
- type: string
minLength: 1
maxLength: 32

FeatureTupleFull:
title: A feature tuple with additional properties
FeatureWithParameters:
title: A feature with additional properties
type: object
additionalProperties: false
properties:
Expand All @@ -695,6 +695,8 @@ definitions:
type: string
minLength: 1
maxLength: 2083
offset:
type: number
required:
- name

Expand Down
4 changes: 2 additions & 2 deletions wres-config/src/wres/config/yaml/DeclarationFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,11 @@ public class DeclarationFactory
.enable( DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY )
.enable( DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY )
.enable( JsonParser.Feature.STRICT_DUPLICATE_DETECTION )
.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES )
.build()
.registerModule( new ProtobufModule() )
.registerModule( new JavaTimeModule() )
.configure( DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES,
true );
.enable( DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES );

/** Mapper for serialization. */
private static final ObjectMapper SERIALIZER =
Expand Down
8 changes: 6 additions & 2 deletions wres-config/src/wres/config/yaml/DeclarationInterpolator.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import wres.config.yaml.components.EvaluationDeclarationBuilder;
import wres.config.yaml.components.FeatureAuthority;
import wres.config.yaml.components.FeatureGroups;
import wres.config.yaml.components.FeatureGroupsBuilder;
import wres.config.yaml.components.Features;
import wres.config.yaml.components.FeaturesBuilder;
import wres.config.yaml.components.Formats;
Expand Down Expand Up @@ -486,7 +487,8 @@ private static void interpolateSparseFeatures( EvaluationDeclarationBuilder buil
.geometries();
Set<GeometryTuple> denseFeatures = DeclarationInterpolator.interpolateSparseFeatures( features,
hasBaseline );
Features adjustedFeatures = new Features( denseFeatures );
Features adjustedFeatures = new Features( denseFeatures, builder.features()
.offsets() );
builder.features( adjustedFeatures );
}

Expand All @@ -512,7 +514,9 @@ private static void interpolateSparseFeatures( EvaluationDeclarationBuilder buil
.build();
adjustedGeoGroups.add( nextAdjustedGroup );
}
FeatureGroups adjustedFeatureGroups = new FeatureGroups( adjustedGeoGroups );
FeatureGroups adjustedFeatureGroups = FeatureGroupsBuilder.builder()
.geometryGroups( adjustedGeoGroups )
.build();
builder.featureGroups( adjustedFeatureGroups );
}
}
Expand Down
10 changes: 8 additions & 2 deletions wres-config/src/wres/config/yaml/DeclarationMigrator.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@
import wres.config.yaml.components.EvaluationDeclarationBuilder;
import wres.config.yaml.components.FeatureAuthority;
import wres.config.yaml.components.FeatureGroups;
import wres.config.yaml.components.FeatureGroupsBuilder;
import wres.config.yaml.components.FeatureService;
import wres.config.yaml.components.FeatureServiceBuilder;
import wres.config.yaml.components.FeatureServiceGroup;
import wres.config.yaml.components.Features;
import wres.config.yaml.components.FeaturesBuilder;
import wres.config.yaml.components.Format;
import wres.config.yaml.components.Formats;
import wres.config.yaml.components.GeneratedBaseline;
Expand Down Expand Up @@ -293,7 +295,9 @@ private static void migrateFeatures( List<NamedFeature> features, EvaluationDecl
if ( !features.isEmpty() )
{
Set<GeometryTuple> geometries = DeclarationMigrator.migrateFeatures( features );
Features wrappedFeatures = new Features( geometries );
Features wrappedFeatures = FeaturesBuilder.builder()
.geometries( geometries )
.build();
builder.features( wrappedFeatures );
}
}
Expand All @@ -312,7 +316,9 @@ private static void migrateFeatureGroups( List<FeaturePool> featureGroups, Evalu
featureGroups.stream()
.map( DeclarationMigrator::migrateFeatureGroup )
.collect( Collectors.toSet() );
FeatureGroups wrappedGroups = new FeatureGroups( geometryGroups );
FeatureGroups wrappedGroups = FeatureGroupsBuilder.builder()
.geometryGroups( geometryGroups )
.build();
builder.featureGroups( wrappedGroups );
}
}
Expand Down
8 changes: 6 additions & 2 deletions wres-config/src/wres/config/yaml/DeclarationUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import wres.config.yaml.components.EvaluationDeclarationBuilder;
import wres.config.yaml.components.FeatureAuthority;
import wres.config.yaml.components.FeatureGroups;
import wres.config.yaml.components.FeatureGroupsBuilder;
import wres.config.yaml.components.FeatureServiceGroup;
import wres.config.yaml.components.Features;
import wres.config.yaml.components.LeadTimeInterval;
Expand Down Expand Up @@ -2243,7 +2244,8 @@ private static EvaluationDeclaration removeFeaturesWithoutThresholds( Evaluation
.collect( Collectors.toSet() );

// Set the new features
Features filteredFeatures = new Features( filtered );
Features filteredFeatures = new Features( filtered, declaration.features()
.offsets() );
builder.features( filteredFeatures );

if ( LOGGER.isWarnEnabled()
Expand Down Expand Up @@ -2305,7 +2307,9 @@ private static EvaluationDeclaration removeFeaturesWithoutThresholds( Evaluation
.toList() );
}

FeatureGroups finalFeatureGroups = new FeatureGroups( adjustedGroups );
FeatureGroups finalFeatureGroups = FeatureGroupsBuilder.builder()
.geometryGroups( adjustedGroups )
.build();
builder.featureGroups( finalFeatureGroups );
}

Expand Down
1 change: 0 additions & 1 deletion wres-config/src/wres/config/yaml/DeclarationValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,6 @@ private static List<EvaluationStatusEvent> validateDatasets( EvaluationDeclarati
// Data types are valid
List<EvaluationStatusEvent> typesValid = DeclarationValidator.typesAreValid( declaration );
events.addAll( typesValid );

// Ensembles cannot be present on both left and right sides
List<EvaluationStatusEvent> ensembles = DeclarationValidator.ensembleOnOneSideOnly( declaration );
events.addAll( ensembles );
Expand Down
19 changes: 17 additions & 2 deletions wres-config/src/wres/config/yaml/components/FeatureGroups.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package wres.config.yaml.components;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
Expand All @@ -14,15 +16,18 @@
import wres.config.yaml.deserializers.FeatureGroupsDeserializer;
import wres.config.yaml.serializers.FeatureGroupsSerializer;
import wres.statistics.generated.GeometryGroup;
import wres.statistics.generated.GeometryTuple;

/**
* Geographic feature groups.
* Geographic feature groups and associated offset values (e.g., datum offsets). Absence of an offset for a given
* feature with a group implies no/zero offset.
* @param geometryGroups the feature groups
* @param offsets the offset values associated with features in the group, such as a datum offset, if any
*/
@RecordBuilder
@JsonSerialize( using = FeatureGroupsSerializer.class )
@JsonDeserialize( using = FeatureGroupsDeserializer.class )
public record FeatureGroups( Set<GeometryGroup> geometryGroups )
public record FeatureGroups( Set<GeometryGroup> geometryGroups, Map<GeometryTuple, Offset> offsets )
{
/**
* Sets the default values.
Expand All @@ -40,6 +45,16 @@ public record FeatureGroups( Set<GeometryGroup> geometryGroups )
// Immutable copy, preserving insertion order
geometryGroups = Collections.unmodifiableSet( new LinkedHashSet<>( geometryGroups ) );
}

if ( Objects.isNull( offsets ) )
{
offsets = Collections.emptyMap();
}
else
{
// Immutable copy, preserving insertion order
offsets = Collections.unmodifiableMap( new LinkedHashMap<>( offsets ) );
}
}

@Override
Expand Down
18 changes: 16 additions & 2 deletions wres-config/src/wres/config/yaml/components/Features.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package wres.config.yaml.components;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
Expand All @@ -16,13 +18,15 @@
import wres.statistics.generated.GeometryTuple;

/**
* Geographic features.
* Geographic features and associated offset values (e.g., datum offsets). Absence of an offset for a given feature
* implies no/zero offset.
* @param geometries the features
* @param offsets the offset values, such as a datum offset, if any
*/
@RecordBuilder
@JsonSerialize( using = FeaturesSerializer.class )
@JsonDeserialize( using = FeaturesDeserializer.class )
public record Features( Set<GeometryTuple> geometries )
public record Features( Set<GeometryTuple> geometries, Map<GeometryTuple,Offset> offsets )
{
/**
* Sets the default values.
Expand All @@ -39,6 +43,16 @@ public record Features( Set<GeometryTuple> geometries )
// Immutable copy, preserving insertion order
geometries = Collections.unmodifiableSet( new LinkedHashSet<>( geometries ) );
}

if ( Objects.isNull( offsets ) )
{
offsets = Collections.emptyMap();
}
else
{
// Immutable copy, preserving insertion order
offsets = Collections.unmodifiableMap( new LinkedHashMap<>( offsets ) );
}
}

@Override
Expand Down
11 changes: 11 additions & 0 deletions wres-config/src/wres/config/yaml/components/Offset.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package wres.config.yaml.components;

/**
* The offset value to apply to each dataset orientation. For example, a datum offset.
* @param left the left-oriented offset
* @param right the right-oriented offset
* @param baseline the baseline-oriented offset
*/
public record Offset( double left, double right, double baseline )
{
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package wres.config.yaml.deserializers;

import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

Expand All @@ -16,7 +17,9 @@
import org.slf4j.LoggerFactory;

import wres.config.yaml.components.FeatureGroups;
import wres.config.yaml.components.FeatureGroupsBuilder;
import wres.config.yaml.components.Features;
import wres.config.yaml.components.Offset;
import wres.statistics.generated.GeometryGroup;
import wres.statistics.generated.GeometryTuple;

Expand Down Expand Up @@ -71,14 +74,15 @@ private FeatureGroups getFeatureGroupsFromArray( ObjectReader reader,
{
// Preserve insertion order
Set<GeometryGroup> featureGroups = new LinkedHashSet<>();
Map<GeometryTuple, Offset> featureOffsets = new LinkedHashMap<>();

int nodeCount = featureGroupsNode.size();

for ( int i = 0; i < nodeCount; i++ )
{
JsonNode nextNode = featureGroupsNode.get( i );
String groupName = "";
Set<GeometryTuple> geometries = null;

// Group name
if ( nextNode.has( "name" ) )
{
Expand All @@ -95,8 +99,9 @@ private FeatureGroups getFeatureGroupsFromArray( ObjectReader reader,
parser.setCodec( reader );
Features features = FEATURES_DESERIALIZER.deserialize( parser, context );
geometries = features.geometries();
featureOffsets.putAll( features.offsets() );
LOGGER.debug( "Discovered the following collection of geometries associated with a feature group "
+ "named '{}': {}.", groupName, new Features( geometries ) );
+ "named '{}': {}.", groupName, features );
}

// Create the group
Expand All @@ -110,6 +115,9 @@ private FeatureGroups getFeatureGroupsFromArray( ObjectReader reader,
}
}

return new FeatureGroups( Collections.unmodifiableSet( featureGroups ) );
return FeatureGroupsBuilder.builder()
.geometryGroups( featureGroups )
.offsets( featureOffsets )
.build();
}
}
Loading

0 comments on commit 335b811

Please sign in to comment.