/* * Copyright (C) 2015 by Array Systems Computing Inc. http://www.array.ca * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.s1tbx.insar.gpf; import com.bc.ceres.core.ProgressMonitor; import org.esa.snap.core.datamodel.MetadataElement; import org.esa.snap.core.datamodel.Product; import org.esa.snap.core.util.Debug; import org.esa.snap.engine_utilities.datamodel.AbstractMetadata; import org.jlinda.core.Baseline; import org.jlinda.core.Orbit; import org.jlinda.core.Point; import org.jlinda.core.SLCImage; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * User: pmar@ppolabs.com * Date: 1/20/12 * Time: 3:39 PM */ public class InSARStackOverview { private final static int BTEMP_CRITICAL = 3 * 365; private final static int BPERP_CRITICAL = 1200; private final static int DFDC_CRITICAL = 1380; private SLCImage[] slcImages; private Orbit[] orbits; private int numOfImages; private long orbitNumber; private float modeledCoherence; // TODO: function to sort input array according to modeled coherence // TODO: critical values for other sensors then C.band ESA public InSARStackOverview() { } public void setInput(SLCImage[] slcImages, Orbit[] orbits) { this.slcImages = slcImages; this.orbits = orbits; this.numOfImages = slcImages.length; if (this.numOfImages != orbits.length) { throw new IllegalArgumentException("Number of elements in input arrays has to be the same!"); } } // returns orbit number of an "optimal master" public long getOrbitNumber() { return orbitNumber; } public float getModeledCoherence() { return modeledCoherence; } // methods private static float modelCoherence(float bPerp, float bTemp, float fDc, float bPerpCritical, float bTempCritical, float fDcCritical) { return coherenceFnc(bPerp, bPerpCritical) * coherenceFnc(bTemp, bTempCritical) * coherenceFnc(fDc, fDcCritical); } private static float modelCoherence(float bPerp, float bTemp, float fDc) { return coherenceFnc(bPerp, BPERP_CRITICAL) * coherenceFnc(bTemp, BTEMP_CRITICAL) * coherenceFnc(fDc, DFDC_CRITICAL); } private static float coherenceFnc(float value, float value_CRITICAL) { if (Math.abs(value) > value_CRITICAL) { return (float) 0.01; } else { return (1 - Math.abs(value) / value_CRITICAL); } } // setup cplxcontainer private CplxContainer[] setupCplxContainers() { CplxContainer[] cplxContainers = new CplxContainer[numOfImages]; for (int i = 0; i < numOfImages; i++) { SLCImage slcImage = slcImages[i]; Orbit orbit = orbits[i]; cplxContainers[i] = new CplxContainer(slcImage.getOrbitNumber(), slcImage.getMjd(), slcImage, orbit); } return cplxContainers; } private IfgStack[] setupIfgStack(CplxContainer[] cplxContainers, ProgressMonitor pm) { // construct pairs from data in containers IfgStack[] ifgStack = new IfgStack[numOfImages]; IfgPair[][] ifgPair = new IfgPair[numOfImages][numOfImages]; pm.beginTask("Computing...", numOfImages); for (int i = 0; i < numOfImages; i++) { CplxContainer master = cplxContainers[i]; for (int j = 0; j < numOfImages; j++) { CplxContainer slave = cplxContainers[j]; ifgPair[i][j] = new IfgPair(master, slave); } ifgStack[i] = new IfgStack(master, ifgPair[i]); ifgStack[i].meanCoherence(); pm.worked(1); } pm.done(); return ifgStack; } public int findOptimalMaster(IfgStack[] ifgStack) { orbitNumber = ifgStack[0].master.orbitNumber; modeledCoherence = ifgStack[0].meanCoherence; int index = 0; int i = 0; for (IfgStack anIfgStack : ifgStack) { long orbit = anIfgStack.master.orbitNumber; float coherence = anIfgStack.meanCoherence; if (coherence > modeledCoherence) { modeledCoherence = coherence; orbitNumber = orbit; index = i; } ++i; } return index; } public IfgStack[] getCoherenceScores(final ProgressMonitor pm) { CplxContainer[] cplxContainers = setupCplxContainers(); return setupIfgStack(cplxContainers, pm); } public int estimateOptimalMaster(final ProgressMonitor pm) { return findOptimalMaster(getCoherenceScores(pm)); } /** * Finds the optimal master product from a list of products * * @param srcProducts input products * @return the optimal master product */ public static Product findOptimalMasterProduct(final Product[] srcProducts) throws Exception { final int size = srcProducts.length; final List<SLCImage> imgList = new ArrayList<>(size); final List<Orbit> orbList = new ArrayList<>(size); for (Product product : srcProducts) { final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); imgList.add(new SLCImage(absRoot, product)); orbList.add(new Orbit(absRoot, 3)); } try { final InSARStackOverview dataStack = new InSARStackOverview(); dataStack.setInput(imgList.toArray(new SLCImage[size]), orbList.toArray(new Orbit[size])); int index = dataStack.estimateOptimalMaster(ProgressMonitor.NULL); return srcProducts[index]; } catch (Throwable t) { Debug.trace(t); } return srcProducts[0]; } public static InSARStackOverview.IfgStack[] calculateInSAROverview(final Product coregProduct) throws Exception { MetadataElement slaveElem = coregProduct.getMetadataRoot().getElement(AbstractMetadata.SLAVE_METADATA_ROOT); if (slaveElem == null) { slaveElem = coregProduct.getMetadataRoot().getElement("Slave Metadata"); } final List<MetadataElement> absMetaList = new ArrayList<>(); absMetaList.add(AbstractMetadata.getAbstractedMetadata(coregProduct)); absMetaList.addAll(Arrays.asList(slaveElem.getElements())); return InSARStackOverview.calculateInSAROverview(absMetaList.toArray(new MetadataElement[absMetaList.size()])); } public static InSARStackOverview.IfgStack[] calculateInSAROverview(final MetadataElement[] absRoots) throws Exception { final List<SLCImage> imgList = new ArrayList<>(absRoots.length); final List<Orbit> orbList = new ArrayList<>(absRoots.length); for (MetadataElement absRoot : absRoots) { imgList.add(new SLCImage(absRoot, null)); orbList.add(new Orbit(absRoot, 3)); } final InSARStackOverview dataStack = new InSARStackOverview(); dataStack.setInput(imgList.toArray(new SLCImage[imgList.size()]), orbList.toArray(new Orbit[orbList.size()])); return dataStack.getCoherenceScores(ProgressMonitor.NULL); } public static InSARStackOverview.IfgStack[] calculateInSAROverview(final Product[] products) throws Exception { final List<SLCImage> imgList = new ArrayList<>(products.length); final List<Orbit> orbList = new ArrayList<>(products.length); for (Product product : products) { final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); imgList.add(new SLCImage(absRoot, product)); orbList.add(new Orbit(absRoot, 3)); } final InSARStackOverview dataStack = new InSARStackOverview(); dataStack.setInput(imgList.toArray(new SLCImage[imgList.size()]), orbList.toArray(new Orbit[orbList.size()])); return dataStack.getCoherenceScores(ProgressMonitor.NULL); } // inner classes private static class CplxContainer { public final long orbitNumber; public final double dateMjd; public final SLCImage metaData; public final Orbit orbit; public CplxContainer(long orbitNumber, double dateMjd, SLCImage metaData, Orbit orbit) { this.orbitNumber = orbitNumber; this.dateMjd = dateMjd; this.metaData = metaData; this.orbit = orbit; } } public static class IfgStack { private final CplxContainer master; private final IfgPair[] master_slave; private float meanCoherence; public IfgStack(CplxContainer master, IfgPair... master_slave) { this.master = master; this.master_slave = master_slave; } public void meanCoherence() { for (IfgPair aMaster_slave : master_slave) { meanCoherence += aMaster_slave.coherence; } meanCoherence /= master_slave.length; } public IfgPair[] getMasterSlave() { return master_slave; } } public static class IfgPair { private final int refLine, refPixel; private final double refHeight; private final CplxContainer master, slave; private Baseline baseline = null; private float bPerp; // perpendicular baseline private final float bTemp; // temporal baseline private final float deltaDoppler; // doppler centroid frequency difference private final float coherence; // modeled coherence private float heightAmb; // modeled coherence public IfgPair(CplxContainer master, CplxContainer slave) { this.master = master; this.slave = slave; final Point refPoint = master.metaData.getApproxRadarCentreOriginal(); this.refPixel = (int) refPoint.x; this.refLine = (int) refPoint.y; this.refHeight = 0; try { baseline = new Baseline(); baseline.model(master.metaData, slave.metaData, master.orbit, slave.orbit); bPerp = (float) baseline.getBperp(refLine, refPixel); heightAmb = (float) baseline.getHamb(refLine, refPixel, refHeight); } catch (Exception e) { e.printStackTrace(); } bTemp = (float) (master.dateMjd - slave.dateMjd); deltaDoppler = (float) (master.metaData.doppler.getF_DC_a0() - slave.metaData.doppler.getF_DC_a0()); coherence = modelCoherence(bPerp, bTemp, deltaDoppler); } public float getPerpendicularBaseline(final double line, final double pixel, final double height) throws Exception { return (float) baseline.getBperp(line, pixel, height); } public float getParallelBaseline(final double line, final double pixel, final double height) throws Exception { return (float) baseline.getBpar(line, pixel, height); } public float getAlpha(final double line, final double pixel, final double height) throws Exception { return (float) baseline.getAlpha(line, pixel, height); } public float getVerticalBaseline(final double line, final double pixel, final double height) throws Exception { return (float) baseline.getBvert(line, pixel, height); } public float getHorizontalBaseline(final double line, final double pixel, final double height) throws Exception { return (float) baseline.getBhor(line, pixel, height); } public float getPerpendicularBaseline() { return bPerp; } public float getTemporalBaseline() { return bTemp; } public float getDopplerDifference() { return deltaDoppler; } public float getCoherence() { return coherence; } public float getHeightAmb() { return heightAmb; } public SLCImage getMasterMetadata() { return master.metaData; } public SLCImage getSlaveMetadata() { return slave.metaData; } } }