Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ export class OnDemandAddMenuComponent implements OnInit {
);
}

public queueAllOnDemand(products: models.CMRProduct[][], job_type: models.Hyp3JobType): void {
const jobs: models.QueuedHyp3Job[] = products.map(product => ({
granules: [...product].sort((a, b) => {
public queueAllOnDemand(productsGroups: models.CMRProduct[][], job_type: models.Hyp3JobType): void {
const jobs: models.QueuedHyp3Job[] = productsGroups.map(products => ({
granules: [...products].sort((a, b) => {
if (a.metadata.date < b.metadata.date) {
return -1;
}
Expand Down
1 change: 1 addition & 0 deletions src/app/models/hyp3/hyp3-job-type.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface Hyp3JobProductType {
productTypes: string[];
beamModes: string[];
polarizations: string[];
dateRange?: Range<Date | null>;
}

export interface Hyp3JobOption {
Expand Down
28 changes: 27 additions & 1 deletion src/app/models/hyp3/hyp3-jobs.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,37 @@ export const AutoRift: Hyp3JobType = {
options: []
};

export const OperaRtcS1JobType: Hyp3JobType = {
id: 'OPERA_RTC_S1',
name: 'OPERA RTC S1',
infoUrl: 'https://hyp3-docs.asf.alaska.edu/guides/opera_rtc_product_guide/',
description: 'OPERA_RTC_S1_DESC',
numProducts: 1,
productTypes: [{
dataset: sentinel_1_bursts,
productTypes: [
'BURST',
],
beamModes: ['IW'],
polarizations: [
'VV', 'HH', 'HV', 'VH'
],
dateRange: {
// Disallow IPF version < 002.70 according to the dates given at https://sar-mpc.eu/processor/ipf/
start: new Date('2016/04/14 00:00:00 UTC'),
// Opera RTC forward processing start date
end: new Date('2022/01/1 00:00:00 UTC')
},
}],
options: []
}

export const hyp3JobTypes = {
RTC_GAMMA: RtcGammaJobType,
INSAR_GAMMA: InsarGammaJobType,
INSAR_ISCE_BURST: InsarIsceBurstJobType,
AUTORIFT: AutoRift
AUTORIFT: AutoRift,
OPERA_RTC_S1: OperaRtcS1JobType
};

export const hyp3JobTypesList = Object.values(hyp3JobTypes);
Expand Down
71 changes: 65 additions & 6 deletions src/app/services/hyp3/hyp3-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,17 @@ export class Hyp3ApiService {

hyp3ableProducts.forEach(product => {
const prodType = product[0].metadata.productType;

if (models.OperaRtcS1JobType.id === jobType.id) {
product = product.map(p => {
if (this.isCrossPolBurst(p)) {
return this.makeCoPolBurst(p);
} else {
return p;
}
})
}

byProdType[prodType].push(product?.sort((a, b) => {
if (a.metadata.date < b.metadata.date) {
return -1;
Expand All @@ -232,9 +243,10 @@ export class Hyp3ApiService {
}));
});

const byProductType: models.Hyp3ableByProductType[] = Object.entries(byProdType).map(([productType, prods]) => ({
productType, products: <any>prods
}));
const byProductType: models.Hyp3ableByProductType[] = Object.entries(byProdType)
.map(([productType, prods]) => {
return ({ productType, products: <any>prods });
});

return {
jobType,
Expand All @@ -250,6 +262,31 @@ export class Hyp3ApiService {
return ({ byJobType, total });
}

private isCrossPolBurst(product: models.CMRProduct) {
return product.metadata.polarization === 'HV' ||
product.metadata.polarization === 'VH';
}

private makeCoPolBurst(product: models.CMRProduct) {
const crossPol = product.metadata.polarization;
const polarization = crossPol === 'VH' ? 'VV' : 'HH';

const name = product.name.replace(`_${crossPol}_`, `_${polarization}_`);
const file = product.file.replace(`_${crossPol}_`, `_${polarization}_`);
const id = product.id.replace(`_${crossPol}_`, `_${polarization}_`);
const downloadUrl = product.downloadUrl.replace(`/${crossPol}/`, `/${polarization}/`);

const coPolProduct = {
...product,
name, file, id, downloadUrl,
metadata: {
...product.metadata, polarization
},
};

return coPolProduct;
}

public getValidJobTypes(product: models.CMRProduct[]): models.Hyp3JobType[] {
return models.hyp3JobTypesList.filter(jobType => this.isHyp3able(product, jobType));
}
Expand All @@ -261,15 +298,37 @@ export class Hyp3ApiService {
const types = new Set(productType.productTypes);
const pols = new Set(productType.polarizations);
const beamModes = new Set(productType.beamModes);

return products.every(product =>
types.has(product.metadata.productType) &&
pols.has(product.metadata.polarization) &&
beamModes.has(product.metadata.beamMode)
types.has(product.metadata.productType) &&
pols.has(product.metadata.polarization) &&
beamModes.has(product.metadata.beamMode) &&
this.withinDateRange(product.metadata.date.toDate(), productType.dateRange) &&
product.dataset !== 'Sentinel-1C'
);
})
);
}

public withinDateRange(check: Date, dateRange: models.DateRange | null) {
if (!dateRange) {
return true;
}

const { start, end } = dateRange;
let isAfterStart = true;
let isBeforeEnd = true;

if (start !== null) {
isAfterStart = check.getTime() >= start.getTime();
}
if (end !== null) {
isBeforeEnd = check.getTime() <= end.getTime();
}

return isAfterStart && isBeforeEnd;
}

public getExpiredHyp3ableObject(scene: models.CMRProduct): { byJobType: models.Hyp3ableProductByJobType[]; total: number } {
const job_types = models.hyp3JobTypes;
const job_type = Object.keys(job_types).find(id => {
Expand Down
36 changes: 23 additions & 13 deletions src/app/store/queue/queue.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,24 +183,34 @@ export function queueReducer(state = initState, action: QueueActions): QueueStat

case QueueActionType.ADD_JOBS: {
const jobs = [...state.customJobs];
const new_jobs = [...action.payload];
let _duplicates = 0;
const jobsToQueue = new_jobs.filter(new_job =>
!jobs.some(old_job => {
const result = old_job.job_type === new_job.job_type &&
sameGranules(old_job.granules, new_job.granules);
if (result) {
_duplicates += 1;
}
return result;
const jobsToAdd = [...action.payload];
let duplicates = 0;

const makeJobId = (job: QueuedHyp3Job) => {
const granuleIds = job.granules.map(g => g?.id).join('-');
return `${job.job_type.id}--${granuleIds}`
}

const uniqueJobs = new Set(jobs.map(makeJobId));

const jobsToQueue = jobsToAdd.filter(jobToAdd => {
const jobId = makeJobId(jobToAdd);

const isDuplicate = uniqueJobs.has(jobId);

if (isDuplicate) {
duplicates += 1;
} else {
uniqueJobs.add(jobId);
}
)
);

return !isDuplicate;
});

return {
...state,
customJobs: [...jobs, ...jobsToQueue],
duplicates: _duplicates
duplicates: duplicates
};
}

Expand Down