Skip to content

Commit 004a6a0

Browse files
authored
Merge pull request #1861 from danforthcenter/add-cropreporter-npq-support
Add support for CropReporter NPQ protocol
2 parents 3c806bd + 81f1876 commit 004a6a0

5 files changed

Lines changed: 242 additions & 0 deletions

File tree

plantcv/plantcv/photosynthesis/read_cropreporter.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ def read_cropreporter(filename):
4545
# Light-adapted measurements
4646
_process_psl_data(ps=ps, metadata=metadata_dict)
4747

48+
# NPQ measurements
49+
_process_npq_data(ps=ps, metadata=metadata_dict)
50+
4851
# Dark-adapted PAM measurements
4952
_process_pmd_data(ps=ps, metadata=metadata_dict)
5053

@@ -158,6 +161,63 @@ def _process_psl_data(ps, metadata):
158161
col_wrap=int(np.ceil(ps.ojip_light.frame_label.size / 4)))
159162

160163

164+
def _process_npq_data(ps, metadata):
165+
"""
166+
Create an xarray DataArray for a NPQ dataset.
167+
168+
Parameters
169+
----------
170+
ps : plantcv.plantcv.classes.PSII_data
171+
PSII_data instance
172+
metadata : dict
173+
INF file metadata dictionary
174+
"""
175+
bin_filepath = _dat_filepath(dataset="NPQ", datapath=ps.datapath, filename=ps.filename)
176+
if os.path.exists(bin_filepath):
177+
img_cube, frame_labels, frame_nums = _read_dat_file(dataset="NPQ", filename=bin_filepath,
178+
height=int(metadata["ImageRows"]),
179+
width=int(metadata["ImageCols"]))
180+
# Add the OJIP dark frames
181+
frame_labels[0] = 'Fdark'
182+
frame_labels[1] = 'F0'
183+
frame_labels[2] = 'Fm'
184+
psd = xr.DataArray(
185+
data=img_cube[:, :, 0:3, None],
186+
dims=('x', 'y', 'frame_label', 'measurement'),
187+
coords={'frame_label': frame_labels[0:3],
188+
'frame_num': ('frame_label', frame_nums[0:3]),
189+
'measurement': ['t0']},
190+
name='ojip_dark'
191+
)
192+
psd.attrs["long_name"] = "OJIP dark-adapted measurements"
193+
ps.add_data(psd)
194+
195+
_debug(visual=ps.ojip_dark.squeeze('measurement', drop=True),
196+
filename=os.path.join(params.debug_outdir, f"{str(params.device)}_PSD-frames.png"),
197+
col='frame_label',
198+
col_wrap=int(np.ceil(ps.ojip_dark.frame_label.size / 4)))
199+
200+
# Add the OJIP light frames
201+
frame_labels[3] = 'Flight'
202+
frame_labels[4] = 'Fp'
203+
frame_labels[5] = 'Fmp'
204+
psd = xr.DataArray(
205+
data=img_cube[:, :, 3:6, None],
206+
dims=('x', 'y', 'frame_label', 'measurement'),
207+
coords={'frame_label': frame_labels[3:6],
208+
'frame_num': ('frame_label', frame_nums[3:6]),
209+
'measurement': ['t0']},
210+
name='ojip_light'
211+
)
212+
psd.attrs["long_name"] = "OJIP light-adapted measurements"
213+
ps.add_data(psd)
214+
215+
_debug(visual=ps.ojip_light.squeeze('measurement', drop=True),
216+
filename=os.path.join(params.debug_outdir, f"{str(params.device)}_PSL-frames.png"),
217+
col='frame_label',
218+
col_wrap=int(np.ceil(ps.ojip_light.frame_label.size / 4)))
219+
220+
161221
def _process_pmd_data(ps, metadata):
162222
"""
163223
Create an xarray DataArray for a PMD dataset.

tests/plantcv/photosynthesis/conftest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ def __init__(self):
1414
# Test data directories
1515
self.datadir_v441 = os.path.join(os.path.dirname(os.path.abspath(__file__)),
1616
"..", "..", "testdata", "cropreporter_v441")
17+
self.datadir_npq = os.path.join(os.path.dirname(os.path.abspath(__file__)),
18+
"..", "..", "testdata", "cropreporter_npq")
1719
self.datadir_v653 = os.path.join(os.path.dirname(os.path.abspath(__file__)),
1820
"..", "..", "testdata", "cropreporter_v653")
1921
# CropReporter data file
2022
self.cropreporter = os.path.join(self.datadir_v441, "PSII_HDR_020321_WT_TOP_1.INF")
2123
self.cropreporter_v653 = os.path.join(self.datadir_v653, "HDR_dark_light.INF")
24+
self.cropreporter_npq = os.path.join(self.datadir_npq, "PSII_HDR_020321_WT_TOP_1.INF")
2225
# Mask image
2326
self.ps_mask = os.path.join(self.datadir_v441, "PSII_HDR_020321_WT_TOP_1_mask.png")
2427

tests/plantcv/photosynthesis/test_read_cropreporter.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,10 @@ def test_read_cropreporter_spc_only(photosynthesis_test_data, tmpdir):
6161
ps = read_cropreporter(filename=fluor_filename)
6262
print(os.listdir(cache_dir))
6363
assert isinstance(ps, PSII_data) and ps.spectral.array_data.shape == (966, 1296, 3)
64+
65+
66+
def test_read_cropreporter_npq(photosynthesis_test_data, tmpdir):
67+
"""Test for PlantCV."""
68+
ps = read_cropreporter(filename=photosynthesis_test_data.cropreporter_npq)
69+
assert isinstance(ps, PSII_data) and ps.ojip_dark.shape == (966, 1296, 3, 1)
70+
assert isinstance(ps, PSII_data) and ps.ojip_light.shape == (966, 1296, 3, 1)
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
Manufacturer=PhenoVation B.V.
2+
Device=CropReporter
3+
Version=4.4.1
4+
SerialNo=CR-530557
5+
MeasurementInfo=n.a.
6+
ExperimentNo=1
7+
PlantNo=2
8+
ImageNo=6
9+
BarcodeNo=n.a.
10+
AutoPlantInc=0
11+
AutoImageInc=1
12+
AutoSaveOn=1
13+
SaveAllFrames=1
14+
TimeStamp=44230.35177256
15+
FilterWheelIncl=6
16+
FocusIncl=109
17+
BinningMode=0
18+
ImageCols=1296
19+
ImageRows=966
20+
FrameRate=20.0
21+
PowerCorrect=100
22+
FvfmDarkFrames=4
23+
FvfmDataFrames=20
24+
FvfmShutterFrames=200
25+
FvfmGainFrames=400
26+
FvfmTriggerDelay=0
27+
FvfmStrobeDelay=0
28+
FvfmFixedFmaxTime=250000
29+
FvfmFastModeOn=0
30+
FvfmMeasPower=80
31+
FqfmDarkFrames=4
32+
FqfmDataFrames=20
33+
FqfmShutterFrames=200
34+
FqfmGainFrames=400
35+
FqfmTriggerDelay=0
36+
FqfmStrobeDelay=0
37+
FqfmFixedFmaxTime=250000
38+
FqfmFastModeOn=0
39+
FqfmInterval=300
40+
FqfmMeasPower=80
41+
FqfmActinicPower=50
42+
NpqDarkFrames=4
43+
NpqDataFrames=20
44+
NpqShutterFrames=200
45+
NpqGainFrames=400
46+
NpqTriggerDelay=0
47+
NpqStrobeDelay=0
48+
NpqFixedFmaxTime=250000
49+
NpqFastModeOn=0
50+
NpqInterval=300
51+
NpqMeasPower=80
52+
NpqActinicPower=50
53+
RfdDarkFrames=10
54+
RfdDataFrames=25
55+
RfdShutterFrames=400
56+
RfdGainFrames=200
57+
RfdInterval=300
58+
RfdMeasPower=50
59+
SpcDarkFrames=10
60+
SpcDataFrames=10
61+
SpcDarkCompOn=0
62+
FilterPositions=10
63+
SpcFilterName0=PSII
64+
SpcShutterFrames0=2500
65+
SpcGainFrames0=0
66+
SpcFilterName1=NIR
67+
SpcShutterFrames1=24032
68+
SpcGainFrames1=300
69+
SpcFilterName2=FarRed
70+
SpcShutterFrames2=2787
71+
SpcGainFrames2=300
72+
SpcFilterName3=Anth
73+
SpcShutterFrames3=750
74+
SpcGainFrames3=300
75+
SpcFilterName4=Red
76+
SpcShutterFrames4=342
77+
SpcGainFrames4=300
78+
SpcFilterName5=Green
79+
SpcShutterFrames5=250
80+
SpcGainFrames5=300
81+
SpcFilterName6=Blue
82+
SpcShutterFrames6=1495
83+
SpcGainFrames6=300
84+
SpcFilterName7=Gfp
85+
SpcShutterFrames7=2500
86+
SpcGainFrames7=0
87+
SpcFilterName8=Rfp
88+
SpcShutterFrames8=2500
89+
SpcGainFrames8=0
90+
SpcFilterName9=Open
91+
SpcShutterFrames9=900
92+
SpcGainFrames9=0
93+
SpcMeasPower=30
94+
ClrDarkFrames=4
95+
ClrDataFrames=4
96+
ClrDarkCompOn=0
97+
ClrMeasPower=30
98+
GfpDarkFrames=4
99+
GfpDataFrames=4
100+
GfpShutterFrames=4000
101+
GfpGainFrames=400
102+
GfpMeasPower=50
103+
GfpCalFactor=130
104+
RfpDarkFrames=4
105+
RfpDataFrames=4
106+
RfpShutterFrames=4000
107+
RfpGainFrames=400
108+
RfpMeasPower=50
109+
ChlDarkFrames=4
110+
ChlDataFrames=4
111+
ChlShutterFrames=800
112+
ChlGainFrames=300
113+
ChlMeasPower=50
114+
FvFmMeasDone=1
115+
FqFmMeasDone=1
116+
NpqMeasDone=1
117+
RfdMeasDone=0
118+
ChlMeasDone=1
119+
GfpMeasDone=0
120+
RfpMeasDone=0
121+
SpcMeasDone=1
122+
ClrMeasDone=1
123+
FvFmFrameF0=0
124+
FvFmFrameFj=-1
125+
FvFmFrameFi=-1
126+
FvFmFrameFm=5
127+
FvFmFrames=20
128+
FvFmTimePoint0=100
129+
FvFmTimePoint1=50100
130+
FvFmTimePoint2=100100
131+
FvFmTimePoint3=150100
132+
FvFmTimePoint4=200100
133+
FvFmTimePoint5=250100
134+
FvFmTimePoint6=300100
135+
FvFmTimePoint7=350100
136+
FvFmTimePoint8=400100
137+
FvFmTimePoint9=450100
138+
FvFmTimePoint10=500100
139+
FvFmTimePoint11=550100
140+
FvFmTimePoint12=600100
141+
FvFmTimePoint13=650100
142+
FvFmTimePoint14=700100
143+
FvFmTimePoint15=750100
144+
FvFmTimePoint16=800100
145+
FvFmTimePoint17=850100
146+
FvFmTimePoint18=900100
147+
FvFmTimePoint19=950100
148+
FqFmFrameFsp=0
149+
FqFmFrameFmp=5
150+
FqFmFrames=20
151+
FqFmTimePoint0=100
152+
FqFmTimePoint1=50100
153+
FqFmTimePoint2=100100
154+
FqFmTimePoint3=150100
155+
FqFmTimePoint4=200100
156+
FqFmTimePoint5=250100
157+
FqFmTimePoint6=300100
158+
FqFmTimePoint7=350100
159+
FqFmTimePoint8=400100
160+
FqFmTimePoint9=450100
161+
FqFmTimePoint10=500100
162+
FqFmTimePoint11=550100
163+
FqFmTimePoint12=600100
164+
FqFmTimePoint13=650100
165+
FqFmTimePoint14=700100
166+
FqFmTimePoint15=750100
167+
FqFmTimePoint16=800100
168+
FqFmTimePoint17=850100
169+
FqFmTimePoint18=900100
170+
FqFmTimePoint19=950100
171+
NpqFrameFm=5
172+
NpqFrameFmp=5

tests/testdata/cropreporter_v441/PSII_NPQ_020321_WT_TOP_1.DAT renamed to tests/testdata/cropreporter_npq/PSII_NPQ_020321_WT_TOP_1.DAT

File renamed without changes.

0 commit comments

Comments
 (0)