diff --git a/wres-config/src/wres/config/yaml/DeclarationValidator.java b/wres-config/src/wres/config/yaml/DeclarationValidator.java index 585f90352f..82222256f2 100644 --- a/wres-config/src/wres/config/yaml/DeclarationValidator.java +++ b/wres-config/src/wres/config/yaml/DeclarationValidator.java @@ -2919,9 +2919,12 @@ private static List validateNetcdfOutput( EvaluationDecla events.add( event ); } - // Check for some score metrics when netcdf is declared + // Check for some score metrics when netcdf is declared, unless the declaration contains no/default metrics, + // meaning that metrics will be interpolated, of which some will always be scores if ( ( outputs.hasNetcdf() || outputs.hasNetcdf2() ) + && !declaration.metrics() // Scores will always be interpolated in this case + .isEmpty() && declaration.metrics() .stream() .noneMatch( DeclarationValidator::isScore ) ) diff --git a/wres-config/test/wres/config/yaml/DeclarationValidatorTest.java b/wres-config/test/wres/config/yaml/DeclarationValidatorTest.java index 0f538d92f3..c69887e583 100644 --- a/wres-config/test/wres/config/yaml/DeclarationValidatorTest.java +++ b/wres-config/test/wres/config/yaml/DeclarationValidatorTest.java @@ -1296,6 +1296,7 @@ void testInvalidNetcdfDeclarationResultsInErrorsAndWarnings() .left( this.defaultDataset ) .right( this.defaultDataset ) .formats( new Formats( formats ) ) + .featureGroups( featureGroups ) .build(); @@ -1314,14 +1315,55 @@ void testInvalidNetcdfDeclarationResultsInErrorsAndWarnings() "The 'output_formats' includes " + "'netcdf2', which supports 'feature_groups', " + "but", - StatusLevel.WARN ) ), - () -> assertTrue( DeclarationValidatorTest.contains( events, - "these formats only support the writing " - + "of verification scores", - StatusLevel.ERROR ) ) + StatusLevel.WARN ) ) ); } + @Test + void testNetcdfDeclarationWithExplicitMetricsAndNoScoresProducesError() + { + Outputs formats = Outputs.newBuilder() + .setNetcdf2( Outputs.Netcdf2Format.getDefaultInstance() ) + .build(); + + Metric metric = new Metric( MetricConstants.RANK_HISTOGRAM, null ); + Set metrics = Collections.singleton( metric ); + + EvaluationDeclaration declaration = EvaluationDeclarationBuilder.builder() + .left( this.defaultDataset ) + .right( this.defaultDataset ) + .formats( new Formats( formats ) ) + .metrics( metrics ) + .build(); + + List events = DeclarationValidator.validate( declaration ); + + assertTrue( DeclarationValidatorTest.contains( events, + "the evaluation must include at least one score metric", + StatusLevel.ERROR ) ); + } + + @Test + void testNetcdfDeclarationAndNoMetricsProducesNoErrors() + { + // Github #305 + Outputs formats = Outputs.newBuilder() + .setNetcdf2( Outputs.Netcdf2Format.getDefaultInstance() ) + .build(); + + EvaluationDeclaration declaration = EvaluationDeclarationBuilder.builder() + .left( this.defaultDataset ) + .right( this.defaultDataset ) + .formats( new Formats( formats ) ) + .build(); + + List events = DeclarationValidator.validate( declaration ); + + assertFalse( DeclarationValidatorTest.contains( events, + "the evaluation must include at least one score metric", + StatusLevel.ERROR ) ); + } + @Test void testInvalidThresholdServiceDeclarationResultsInErrors() { diff --git a/wres-io/src/wres/io/ingesting/SourceLoader.java b/wres-io/src/wres/io/ingesting/SourceLoader.java index f5ac49c321..4f4bfad36e 100644 --- a/wres-io/src/wres/io/ingesting/SourceLoader.java +++ b/wres-io/src/wres/io/ingesting/SourceLoader.java @@ -295,7 +295,7 @@ private List>> loadFileSource( DataSource s // Ingest gridded metadata/features when required. For an in-memory evaluation, it is required by the gridded // reader. For a database evaluation, it is required by the DatabaseProject. This is a special snowflake until // #51232 is resolved - if ( source.getDisposition() == DataDisposition.NETCDF_GRIDDED ) + if ( source.isGridded() ) { // It has now been established that a gridded evaluation is required. Gridded evaluations require a spatial // mask to determine the features to evaluate. Check that now. diff --git a/wres-tasker/src/wres/tasker/WresJob.java b/wres-tasker/src/wres/tasker/WresJob.java index 1f9bbf88da..bb9d8a1d3e 100644 --- a/wres-tasker/src/wres/tasker/WresJob.java +++ b/wres-tasker/src/wres/tasker/WresJob.java @@ -132,13 +132,13 @@ public class WresJob static { - //Initialize storage of the admin token for some functions. - //This method should not except out. If problems occur storing it, - //then the tasker runs without using an admin token. + // Initialize storage of the admin token for some functions. + // This method should not except out. If problems occur storing it, + // then the tasker runs without using an admin token. intializeWresAdminToken(); - //If the broker connection factory fails to initialize, log an error and - //pass up the exception so that this static block fails out. + // If the broker connection factory fails to initialize, log an error and + // pass up the exception so that this static block fails out. try { initializeBrokerConnectionFactory(); @@ -993,7 +993,7 @@ private static void intializeWresAdminToken() */ private static void initializeBrokerConnectionFactory() throws IllegalStateException { - //Check for the client P12 path name. That P12 is handed off to the broker to authenticate the Tasker user. + // Check for the client P12 path name. That P12 is handed off to the broker to authenticate the Tasker user. String p12Path = System.getProperty( Tasker.PATH_TO_CLIENT_P12_PNAME ); if ( p12Path == null || p12Path.isEmpty() ) {