Skip to content

Commit

Permalink
Allow for empty time-series when assessing sampling uncertainty, #39.
Browse files Browse the repository at this point in the history
  • Loading branch information
james-d-brown committed Jul 17, 2024
1 parent 498ae2a commit 3619817
Showing 1 changed file with 84 additions and 36 deletions.
120 changes: 84 additions & 36 deletions wres-datamodel/src/wres/datamodel/bootstrap/BootstrapPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,58 +128,99 @@ Set<Duration> getValidTimeOffsets()
{
if ( next.size() > 1 )
{
// Offsets between consecutive series
for ( int i = 1; i < next.size(); i++ )
{
Instant first;
List<Event<T>> firstSeries = next.get( i - 1 );

if ( this.hasForecasts() )
{
first = firstSeries.get( 0 )
.getTime();
}
else
{
first = firstSeries.get( firstSeries.size() - 1 )
.getTime();
}

Instant last = next.get( i )
.get( 0 )
.getTime();
Duration offset = Duration.between( first, last )
.abs();
offsets.add( offset );
}
Set<Duration> nextOffsets = this.getOffsetsBetweenConsecutiveSeries( next );
offsets.addAll( nextOffsets );
}
}

return Collections.unmodifiableSet( offsets );
}

/**
* Adds the time offset between adjacent time-series in the inputs.
* @param series the series
*/
private Set<Duration> getOffsetsBetweenConsecutiveSeries( List<List<Event<T>>> series )
{
Set<Duration> offsets = new HashSet<>();

// Offset between the first and last series, which is required because the resampling is circular
Instant first = next.get( 0 )
.get( 0 )
.getTime();
List<Event<T>> lastSeries = next.get( next.size() - 1 );
Instant last;
// Offsets between consecutive series
for ( int i = 1; i < series.size(); i++ )
{
Instant first;
List<Event<T>> firstSeries = series.get( i - 1 );

if ( !firstSeries.isEmpty() )
{
if ( this.hasForecasts() )
{
last = lastSeries.get( 0 )
.getTime();
first = firstSeries.get( 0 )
.getTime();
}
else
{
last = lastSeries.get( lastSeries.size() - 1 )
.getTime();
first = firstSeries.get( firstSeries.size() - 1 )
.getTime();
}

Instant last = series.get( i )
.get( 0 )
.getTime();
Duration offset = Duration.between( first, last )
.abs();
offsets.add( offset );
}
}

// Offset between the first and last series, which is required because the resampling is circular
Duration offset = this.getOffsetBetweenFirstAndLastSeries( series );
if ( Objects.nonNull( offset ) )
{
offsets.add( offset );
}

return Collections.unmodifiableSet( offsets );
}

/**
* Gets the time offset between the first and last series.
* @param series the series
*/
private Duration getOffsetBetweenFirstAndLastSeries( List<List<Event<T>>> series )
{
// Offset between the first and last series, which is required because the resampling is circular
List<Event<T>> firstSeries = series.get( 0 );
List<Event<T>> lastSeries = series.get( series.size() - 1 );

Duration offset = null;

if ( !firstSeries.isEmpty()
&& !lastSeries.isEmpty() )
{
Instant first = firstSeries
.get( 0 )
.getTime();

Instant last;

if ( this.hasForecasts() )
{
last = lastSeries.get( 0 )
.getTime();
}
else
{
last = lastSeries.get( lastSeries.size() - 1 )
.getTime();
}

offset = Duration.between( first, last )
.abs();
}

return offset;
}

/**
* @return the original pool
*/
Expand Down Expand Up @@ -218,8 +259,12 @@ private BootstrapPool( Pool<TimeSeries<T>> pool )
List<List<TimeSeries<T>>> groupedBySize = new ArrayList<>();
for ( Map.Entry<Integer, List<TimeSeries<T>>> nextEntry : bySize.entrySet() )
{
int count = nextEntry.getKey();
List<TimeSeries<T>> nextList = nextEntry.getValue();
nextList.sort( sorter );
if ( count > 0 )
{
nextList.sort( sorter );
}
groupedBySize.add( nextList );
}

Expand All @@ -237,7 +282,10 @@ private BootstrapPool( Pool<TimeSeries<T>> pool )
List<TimeSeries<T>> nextInner = nextInnerEntry.getValue();

// Sort by the first valid time in each series
nextInner.sort( sorter );
if ( nextCount > 0 )
{
nextInner.sort( sorter );
}

List<List<Event<T>>> unwrapped = nextInner.stream()
.map( n -> List.copyOf( n.getEvents() ) )
Expand Down

0 comments on commit 3619817

Please sign in to comment.