mdaeron / D47crunch

Python library for processing and standardizing carbonate clumped-isotope analyses, from low-level data out of a dual-inlet mass spectrometer to final, “absolute” Δ47, Δ48, and Δ49 values with fully propagated analytical error estimates.
MIT License
8 stars 3 forks source link

Implementation of Δ48 standardization #4

Closed mdaeron closed 3 years ago

mdaeron commented 3 years ago

Clearly, D47crunch needs to implement Δ48 standardization methods, the sooner the best. Two obvious approaches are:

  1. just copy-paste the relevant methods and replace 47 by 48 in the new functions, as you did. With a bit of house-cleaning (docs, etc.), this will work in the short term;
  2. alternatively, rewrite everything so that a single D47data.standardize() method does Δ47, Δ48, or both.

Option (2) is harder to implement and I am not sure what we would gain from doing things in a very general way (it's not like there are many other standardizations that we will be doing in the near future beyond perhaps one day Δ49). What's more, it is entirely possible that many labs would use slightly different methods for D47 and D48 standardization (e.g. process Δ47 in the I-CDES RF but process Δ48 using H/E gas standards), so it is perhaps more natural to implement separate functions, potentially used with different arguments.

There are additional, minor issues to deal with, like how should the code take into account that some samples will be anchors for Δ48 but not for Δ47 or vice versa.

mdaeron commented 3 years ago

NB: for now, the following ugly hack does the job.

from D47crunch import *

rawdata = D47data()
rawdata.Nominal_D48 = {
    'ETH-1': 0.138,
    'ETH-2': 0.138,
    'ETH-3': 0.270,
    'ETH-4': 0.223,
    }

rawdata.read('D48hack.csv')
rawdata.wg()
rawdata.crunch()

# temporarily replace all 47 values with 48 values
rawdata._Nominal_D47 = rawdata.Nominal_D47.copy()
rawdata.Nominal_D47 = rawdata.Nominal_D48.copy()

for r in rawdata:
    r['_D47raw'] = r['D47raw']
    r['_d47'] = r['d47']
    r['D47raw'] = r['D48raw']
    r['d47'] = r['d48']

rawdata.refresh()
rawdata.standardize()

D48_results = {}
D48_results['r_D48'] = rawdata.repeatability['r_D47']
D48_results['r_D48a'] = rawdata.repeatability['r_D47a']
D48_results['r_D48u'] = rawdata.repeatability['r_D47u']
for u in rawdata.unknowns:
    D48_results[u] = {
        'D48': rawdata.unknowns[u]['D47'],
        'SE_D48': rawdata.unknowns[u]['SE_D47'],
        }

print()
for k in D48_results:
    print(f'{k:>8}: {D48_results[k]}')

This should generate the following output:

   r_D48: 0.1237838550727198
  r_D48a: 0.13195328760301325
  r_D48u: 0.10585573189123085
   DVH-2: {'D48': 0.2575489652935696, 'SE_D48': 0.03312408958860156}
   LGB-2: {'D48': 0.30499761247804147, 'SE_D48': 0.03712619158271187}

D48hack.csv

mdaeron commented 3 years ago

Just pushed a new branch, D48, which defines a D48data class analogous to D47data. This is yet another approach, based on the idea that in practice, Δ47 and Δ48 standardizations are mathematically independent (granted, scrambling corrections are likely to be the same, but let's ignore that for now).

The new branch seems to work as intended when doing this:

from D47crunch import *

rawdata = D47data()
rawdata.read('D48test.csv')
rawdata.wg()
rawdata.crunch()
rawdata.standardize()
rawdata.summary()
rawdata.table_of_sessions()
rawdata.table_of_samples()
rawdata.table_of_analyses()
rawdata.plot_sessions()

rawdata = D48data(rawdata)
rawdata.standardize()
rawdata.summary()
rawdata.table_of_sessions()
rawdata.table_of_samples()
rawdata.table_of_analyses()
rawdata.plot_sessions()

Please feel free to experiment and report any issues.

MattiaTag commented 3 years ago

Hi!

I have been using the new version of the code and everything seems to run smoothly. However, today I run into a problem switching to the ""indep_sessions" method. Here the traceback:

"Traceback (most recent call last): File "/Users/mattiatag/Documents/Python Works/Standards Monitoring/Reference Frame.py", line 236, in corrected = correction(path) File "/Users/mattiatag/Documents/Python Works/Standards Monitoring/Reference Frame.py", line 31, in correction clumpy.standardize(method = "indep_sessions") File "/Users/mattiatag/.conda/envs/Science/lib/python3.9/site-packages/D4xCrunch/init.py", line 439, in newfun out = oldfun(*args, *kwargs) File "/Users/mattiatag/.conda/envs/Science/lib/python3.9/site-packages/D4xCrunch/init.py", line 1161, in standardize r[f'wD{self._4x}'] /= (a + a2 r['t']) KeyError: 'wD47'

Process finished with exit code 1

mdaeron commented 3 years ago

@MattiaTag can you try again with the current version (d4288ca) of the dev branch? I believe this bug was recently corrected.

MattiaTag commented 3 years ago

Yes, it works fine in the new version!

mdaeron commented 3 years ago

Closed following v2.0 release.