Correlation coefficient in Nataf transform

Dear developer,

hello. I have a question to ask.
I have a correlation between two arbitrary distributions ρ_x. How can I get the correlation between standard normal distributions ρ_z through Nataf transformation in OpenTURNS?
Thanks

Hi,

There is no service allowing to convert a linear correlation coefficient between two arbitrary distributions and the correlation of the supposed normal copula between these distributions (which is what is done when using the Nataf transformation). The reason for that is that either you built your joint distribution based on the marginal distributions and a normal copula, and the linear correlation is a consequence of this construction, or you try to mix two univariate distributions and a normal copula in order to get a target linear correlation, and this problem is ill posed as in general, there is no joint distribution (using a normal copula or any other copula) having the target linear correlation and the target marginal distributions.

The following example illustrates this problem (and gives you a way to compute the Nataf correlation when it exists):

import openturns as ot

ot.ResourceMap.SetAsBool("JointDistribution-UseGenericCovarianceAlgorithm", True)
ot.ResourceMap.SetAsBool("Distribution-UseCovarianceAdaptiveAlgorithm", False)
ot.ResourceMap.SetAsUnsignedInteger("Distribution-DefaultIntegrationNodesNumber", 2**16)

epsilon = 1e-2

rho_target = 0.5 # fails with any value < -0.5
marginal1 = ot.LogNormal(0.0, 1.0)
marginal2 = ot.Exponential(1.0)

distribution = ot.JointDistribution([marginal1, marginal2], ot.NormalCopula(2))

def computeRho(r):
    copula = ot.NormalCopula(ot.CorrelationMatrix(2, [1.0, r[0], r[0], 1.0]))
    distribution.setCopula(copula)
    return [distribution.getCorrelation()[0, 1]]

fRho = ot.PythonFunction(1, 1, computeRho)
fRho.setInputDescription(["Nataf correlation"])
fRho.setOutputDescription(["Linear correlation"])
ot.Show(fRho.draw(-1.0+epsilon, 1.0-epsilon))

r = ot.Brent().solve(fRho, rho_target, -1.0+epsilon, 1.0-epsilon)

print(f"for {rho_target=}, {r=}")

print("distribution=", distribution)

Several points are to be noted:

  • The computation of the linear correlation is computationally challenging for extreme correlations. You can play with the different options (use the generic algorithm or not, in its adaptive version or not, using a given number of integration nodes) to see how the computation fails for rho close to -1 and 1, as the NormalCopula tends to the MinCopula (which is singular)
  • In this example only a strict subset of [-1, 1] can be obtained using a NormalCopula for the given marginal distributions, eg it is impossible to obtain a linear correlation of -0.6, see the following graph

Figure_1

Cheers

Régis