Software regression ? [NodeId: Coherence] [slvProductName] is null

Hello everyone,

I used to compute the coherence on the results of Back-Geocoding of two products (that are also the results of back-geocoding with a Master). (BandSelect .*_slv1_.*)

The results were four layers (two VV and two VH), but two of them were blank (I assumed it computed the coherence between the Master and the Master).

Then I selected the two bands that were valid and everything worked like a charm.

Lately, I updated my toolbox, and now, I have a message stated that the coherence cannot be computed due to a null ProductName. (The results of the last BackGeocoding: (870.0 KB))

INFO: org.esa.snap.core.gpf.operators.tooladapter.ToolAdapterIO: Initializing external tool adapters
INFO: org.esa.snap.core.util.EngineVersionCheckActivator: Please check regularly for new updates for the best SNAP experience.
INFO: org.hsqldb.persist.Logger: dataFileCache open start
[slvProductName] is null
org.esa.snap.core.gpf.OperatorException: [slvProductName] is null
	at org.esa.snap.engine_utilities.gpf.OperatorUtils.catchOperatorException(
	at org.esa.s1tbx.insar.gpf.CoherenceOp.initialize(
	at org.esa.snap.core.gpf.internal.OperatorContext.initializeOperator(
	at org.esa.snap.core.gpf.internal.OperatorContext.getTargetProduct(
	at org.esa.snap.core.gpf.Operator.getTargetProduct(
	at org.esa.snap.core.gpf.main.CommandLineTool.runOperator(
	at org.esa.snap.core.gpf.main.CommandLineTool.runGraphOrOperator(
	at org.esa.snap.core.gpf.main.GPT.main(
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(
	at java.lang.reflect.Method.invoke(
	at org.esa.snap.runtime.Launcher.lambda$run$0(
	at org.esa.snap.runtime.Engine.runClientCode(
	at org.esa.snap.runtime.Launcher.main(
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(
	at java.lang.reflect.Method.invoke(
	at com.exe4j.runtime.LauncherEngine.launch(
	at com.install4j.runtime.launcher.UnixLauncher.start(
	at Source)
Caused by: java.lang.IllegalArgumentException: [slvProductName] is null
	at org.esa.snap.core.util.Guardian.assertNotNull(
	at org.esa.snap.engine_utilities.gpf.StackUtils.saveSlaveProductBandNames(
	at org.esa.s1tbx.insar.gpf.CoherenceOp.createTargetProduct(
	at org.esa.s1tbx.insar.gpf.CoherenceOp.initialize(
	... 24 more

Error: [slvProductName] is null
-- org.jblas INFO Deleting /tmp/jblas2750746498868856509/
-- org.jblas INFO Deleting /tmp/jblas2750746498868856509/
-- org.jblas INFO Deleting /tmp/jblas2750746498868856509/
-- org.jblas INFO Deleting /tmp/jblas2750746498868856509/
-- org.jblas INFO Deleting /tmp/jblas2750746498868856509

I don’t know if it’s a regression or more probably a wrong designed graph. Anyone has an idea ?

Thanks for you help !!

Wouldn’t it be easier to put all three input images into one BackGeocoding list?

Thanks for your answer.

Actually, I process a batch of products (e.g. a year of images, registered on the first image of the timeserie, the “master”). To save time, I do it in two steps. First, I do the backgeocoding of all images with the “master”, select the slave band and store the result. Then, I compute the backgeocoding & coherence of two consecutive images.

I did not know we can do a backgeocoding of a list. I have to think about it and do some benchmarks.

Do you think it will solve the problem (slvProductName is null) ?

Would be worth a try.

Thanks for the suggestion.
I changed my graph to have one BackGeocoding list :

Unfortunately, it only computes the coherence between Master&Slave1 and Master&Slave2.


I tried to select the slave bands only and disable “SingleMaster” option (otherwise, it does nothing), but it only outputs the VV coherence.


How can I get the coherence VV/VH between Slave1 & Slave2 ?

I don’t understand what SingleMaster is, but I have strange behavior.

Below, two coherence images (I used BandSelect=VV before computing the coherence), the upper one is with SingleMaster=True. Results is 03jan/09jan, the second one is with SingleMaster=false. Results is 09jan/03jan (the opposite). Except for the black dots, the images are exactly the same.

I’m lost…

sorry, I don’t get it.
Let’s say you have

  • img1=03Jan2019
  • img2=09Jan2019
  • img3=15Jan2019

what do you need in the end?

I need the coherence between img2&img3.
But I would like img2 and img3 coregistrated with img1.
(actually, I have many more images, and I would like all of them to be coregistrated with img1)

I’d say unabling the “single master” option should to the task, but somehow it still has issues with Sentinel-1 data. It worked for me with stripmap products.

Unfortunately, with SingleMaster=False, I only get CoherenceVV and sometimes, I have black dots on my image…
I’m trying to find a workaround (using BandSelect, two steps BackGeocoding…), but I always run into a problem…

Maybe the align to standard grid allows you to coregister the data independently while aligning it to the reference image. How can I snap outputs of terrain correction to a given grid? - #3 by valgur
I have never tried it myself though.

To compute coherence, the two products must be backgeocoded together. I don’t think it works to backgeocode them with the same reference and then compute the coherence between them.

I decided to dive into the code and I have two fixes to suggest:

  • To fix the “software regression” (commit: 7759322509 (“update StackUtils and add test”, 2021-04-08) on snap-engine), it’s a little bit ugly, but it works:
@@ -436,6 +442,10 @@ public class CoherenceOp extends Operator {
                 if (singleMaster) {
                     String slvProductName = StackUtils.findOriginalSlaveProductName(sourceProduct, container.sourceSlave.realBand);
+                    if (slvProductName == null){
+                        SystemUtils.LOG.warning("createTargetProduct: slvProductName is null");
+                        continue;
+                    }
                     StackUtils.saveSlaveProductBandNames(targetProduct, slvProductName,
                             targetBandNames.toArray(new String[0]));
  • To fix the “singleMaster=False” on a product where there is no master anymore:
    polarisations were empty:
@@ -253,7 +254,12 @@ public class CoherenceOp extends Operator {

             final String[] polarisationsInBandNames = OperatorUtils.getPolarisations(sourceProduct);
-            polarisations = InterferogramOp.getPolsSharedByMstSlv(sourceProduct, polarisationsInBandNames);
+            if (singleMaster){
+              polarisations = InterferogramOp.getPolsSharedByMstSlv(sourceProduct, polarisationsInBandNames);
+            }
+            else{
+              polarisations = polarisationsInBandNames;
+            }
             sourceImageWidth = sourceProduct.getSceneRasterWidth();
             sourceImageHeight = sourceProduct.getSceneRasterHeight();

and as private void constructTargetMetadata() { compares two consecutives keys, keys must be sorted by polarisation first:

@@ -292,13 +298,13 @@ public class CoherenceOp extends Operator {

                             final Map<String, CplxContainer> map) throws Exception {
         for (String swath : subswaths) {
-            final String subswath = swath.isEmpty() ? "" : '_' + swath.toUpperCase();
+            final String subswath = swath.isEmpty() ? "" : swath.toUpperCase()+'_';
             for (String polarisation : polarisations) {
-                final String pol = polarisation.isEmpty() ? "" : '_' + polarisation.toUpperCase();
+                final String pol = polarisation.isEmpty() ? "" : polarisation.toUpperCase()+'_';
                 // map key: ORBIT NUMBER
-                String mapKey = root.getAttributeInt(AbstractMetadata.ABS_ORBIT) + subswath + pol;
+                String mapKey = pol + subswath + root.getAttributeInt(AbstractMetadata.ABS_ORBIT);
                 // metadata: construct classes and define bands
                 final String date = OperatorUtils.getAcquisitionDate(root);

It works for me.

Should I do a pull-request ?

1 Like

maybe @jun_lu can comment here

Hello everyone,

Is there any update on this topic ?

Thanks a lot for your great job on all the other topics !


Thanks, I’ll add a test for the polarizations.

Usually the co-pol is used because the coherence is stronger. I’m curious what other information is gained from also having the cross-pol coherence?

The information-content is different so sometimes it is useful to include it in analysis.

A JIRA ticket ([SITBX-906] - JIRA) has been created to track the issue. We will look into the issue, thank you