2

We have several seismic attribute generators which require data from seismic volumes which are not among the input volumes.

In Petrel 2010 this worked fine as long as the generator ran in the UI thread.

Petrel 2011 goes to great lengths to prohibit this: First of all, generators no longer run on the main thread at all. Secondly, an IAsyncSubCube fetched in the UI thread throws an InvalidOperationException if accessed from an attribute worker thread. Here's the exception message:

[ArrayBufferAccessorLink] Error accessing array data: [RequestBroker] The current thread, an internal worker thread, does not have permission to initiate new data access. (This situation may be originating from an external computation e.g. an async. seismic attribute computation.) Exception type: class Slb::Salmon::Adt::Exceptions::InsufficientPermissionsException

Is there any way I can make such an access work? (Providing these volumes as regular attribute inputs is not an option.)

Robert Schmidt
  • 699
  • 4
  • 14
  • I've realized that the UI thread is very likely to be blocked, so dynamic invokes to it from attribute generator worker threads is not an option, even if access to arbitrary IAsyncSubCubes from the worker threads had been permitted. – Robert Schmidt Aug 05 '11 at 13:59

3 Answers3

1

I think more information is needed to answer your question.

Is your attribute trace-based or brick-based?

What does your attribute return in CanGenerateAsync?

What kind of APIs do you use to access seismic volumes? (a code sample would be great)

And finally, why would you need to access cubes which are not input for your attribute, from the attribute generator code? Could you tell more about your use-case?

Evgeny
  • 665
  • 4
  • 14
  • Thanks, Evgeny. Trace or brick based doesn't matter. I used CanGenerateAsync in Petrel 2010 in order to be able to access domain objects (arbitrary volumes) other than the input ISubCubes, as the generator was then running in the UI thread. I simply use SeismicCube to access ISubCubes matching the ISubCube of the output volume. This is all a workaround in order to be able to generate an attribute from an *arbitrary* number of inputs, since the amount of volumes provided by the user is unknown at build time. Thus, I can't use InputCount, as the amount is neither known or constant. – Robert Schmidt Aug 05 '11 at 12:59
  • Sorry, I meant CanGenerateAsync==false above. My issue highlights a weakness in the attributes API - it now appears that our only option (in Petrel 2011) for deriving a volume from a *dynamic* number of inputs, is to perform the entire calculation up front. I can find no way to perform the calculation on demand. This places a potentially huge investment of time (and disk space) on the user before (s)he can even assess the correctness of the calculation parameters. – Robert Schmidt Aug 05 '11 at 13:07
  • I thought I'd elaborate on a use case: seismic stochastic inversion produces a user-configurable number of impedance realizations, typically also in pairs (IP/IS or AI/GI). Typical post processing of these realizations include calculating statistics across all or some of them. If seismic attributes supported a dynamic InputCount, they'd be the perfect vehicle for such post processing. – Robert Schmidt Aug 05 '11 at 13:22
1

This might work:

Delegate dataGetCallback = new Func<Index3, Index3, float[,,]>(GetData);

void IGenerator.Calculate(ISubCube[] inputs, ISubCube[] outputs, Index3 min, Index3 max) {
    float[,,] data = (float[,,])CoreSystem.SynchronizedInvoke.Invoke(getDataCallback, new[] { min, max });

    MyAlgorithm(outputs, data, min, max);
}

float[,,] GetData(Index3 min, Index3 max) {
    return inputDataNotPassedAsArgument.GetSubCube(min, max).ToArray();
}

Consider to do CoreSystem.SynchronizedInvoke.BeginInvoke instead of Invoke which runs synchronously. BeginInvoke will let you do some work on "your" thread while you wait for data to be available.

Warning: I have not tried this.

Hallgrim
  • 15,143
  • 10
  • 46
  • 54
  • Thanks, Hallgrim - I've investigated a similar solution using the Dispatcher for the main thread (I suspect that's equivalent to your suggestion). The problem is that the UI thread may be blocked by Petrel (e.g. waiting for the worker thread to finish), which would result in a deadlock. – Robert Schmidt Aug 08 '11 at 08:29
  • If you use BeginInvoke instead of Invoke you should be able to prevent deadlock, because you will not be waiting for the UI thread. – Hallgrim Aug 09 '11 at 19:55
  • I can't see this working. Assume the UI thread is blocked on a trivial SeismicCube.GetTrace() call (a fairly typical, though suboptimal usage), which propagates to my IGenerator.Calculate() executing in a worker thread. I can't return from Calculate() before the Invoke() or BeginInvoke()/EndInvoke() finishes, and the main thread is blocked from running the main loop where the delegate is enqueued. Thus a deadlock. Or am I missing something? – Robert Schmidt Aug 10 '11 at 08:02
  • It seems like you are assuming that the initial request will happen on the UI thread. It will not. Or am I missing something? – Hallgrim Aug 30 '11 at 18:28
  • Well, any plugin can call GetTrace() in the UI thread, using a blocking call, right? Even though it is bad form, I have to take this into account. Anyway - thanks for your input! – Robert Schmidt Jan 12 '12 at 08:09
1

Please use the following approach, but be sure that CanGenerateAsync always returns false:

    // GetAsyncSubCube in the calculation thread and use it in calculation thread
    public override void Calculate(Slb.Ocean.Petrel.DomainObject.Seismic.ISubCube[] input, Slb.Ocean.Petrel.DomainObject.Seismic.ISubCube output)
    {
        IAsyncSubCube cube = Parameters.Cube.GetAsyncSubCube(input[0].MinIJK, input[0].MaxIJK);

        foreach (Index3 index in output )
        {
            output[index] = cube[index];
        }
    }
Evgeny
  • 665
  • 4
  • 14
  • Thanks, Evgeny! Works great. It should be noted that this is an exception to the 2011 documentation which states that GetAsyncSubCube can only be called from the main thread. The single worker thread used when CanGenerateAsync==false seems to be a special case. – Robert Schmidt Aug 10 '11 at 12:17