statgen / METAL

Meta-analysis of genomewide association scans
Other
39 stars 12 forks source link

Fatal error:p-value [0] outside range in ninv() #32

Open AmandaHWChong opened 1 year ago

AmandaHWChong commented 1 year ago

Hi,

Could you please explain the following error:

p-value [0] outside range in ninv()

and how I would go about troubleshoot it?

Thank you for your help!

welchr commented 1 year ago

Seems like it is trying to compute a z-statistic using ninv() from a p-value of 0, which isn't possible, so it throws an error.

https://github.com/statgen/METAL/blob/ab5d19155aa72cef5ca5d2876aea0dd6b9fcba0d/libsrc/MathStats.cpp#L234

Is there an entry in your p-value column exactly equal to 0?

AmandaHWChong commented 1 year ago

No I did not find any p-values equal to 0 in my GWAS summary data.

welchr commented 1 year ago

Could be the %.2g can't handle a very small value beyond double precision, so it writes out 0. What's the smallest p-value seen in any of your studies? Are any of them smaller than 1e-1000L?

AmandaHWChong commented 10 months ago

Yes the smallest is 1.8E-3796. Is there a way to troubleshoot this issue?

welchr commented 9 months ago

METAL looks to be compiled with a constant value of 1E-1000 as the minimum p-value accepted when using long double precision:

https://github.com/statgen/METAL/blob/ab5d19155aa72cef5ca5d2876aea0dd6b9fcba0d/libsrc/MathStats.cpp#L229-L234

However on most modern systems, a long double can probably go down much further. On my system:

#include <iostream>
#include <limits>

int main() {
  std::cout << std::numeric_limits<long double>::min() << std::endl;
}

Prints 3.3621e-4932.

What I don't know is whether that 1E-1000 limit is a hard coded value that used to be the long double precision minimum on the system METAL was developed on 15+ years ago, or whether that is the limit beyond which the ninv() function does not work properly. I would guess ninv() should work fine even at such small values but I don't know that for sure.

If you were to change the limit to std::numeric_limits<long double>::min() and recompile METAL, you would likely want to come up with a test dataset to verify that METAL gives the correct output in that range.

And even if that worked, while it would handle your one p-value of 1.8E-3796, if you try to meta-analyze with a p-value from another study that is as small or smaller, you may still end up underflowing.

Another option could be that, if you don't truly need that high of precision, you could increase your p-value up to something larger (which would allow METAL to run), and then annotate in your tables that the p-value is "<1E-800" or whatever value you choose. Not ideal of course. And you probably would not want to use that p-value for downstream analysis.

KAILi-Hsu commented 1 month ago

Hi I've encountered a similar error:

FATAL ERROR - p-value [7e-310] outside range in ninv()

Following the suggestion above, I edited the content in METAL/libsrc/MathStats.cpp as follows:

ifdef NINV_LONG_DOUBLE

if ( r < 1e-1000L )

else

if ( r < 1e-600 )

endif

  error("p-value [%.2g] outside range in ninv()", p ); 

However, after deleting the original 'build' and recompiling, running METAL again still produces exactly the same error. Do you have any other suggestions to help me resolve this issue? Thank you!

(By the way, the smallest p-value I have is around e-310.)

welchr commented 1 month ago

Are you using the newly produced executable from the recompiled build? Maybe your script is still using metal on your $PATH. You could modify the error message to double check you're using the latest code, something like error("kaili-hsu build -- p-value [%.2g] outside range in ninv()", p );.

I would recommend setting the limits to what are available on your system as well:

#ifdef NINV_LONG_DOUBLE
if ( r < (std::numeric_limits<long double>::min() * (1 + std::numeric_limits<long double>::epsilon())) )
#else
if ( r < (std::numeric_limits<double>::min() * (1 + std::numeric_limits<double>::epsilon())) )
#endif
error("p-value [%.2g] outside range in ninv()", p );