*************************************************************************************************; * * CLIENT: ModernaTX, Inc. * PROTOCOL: mRNA-1273-P301 * * PURPOSE: Create analysis dataset adis * * INPUT FILES: SDTM domains * OUTPUT FILES: ADIS.sas7bdat * * USAGE NOTES: * *************************************************************************************************; * Copyright 2020 Pharmaceutical Product Development, Inc. * All Rights Reserved. *************************************************************************************************; options noquotelenmax; %include "madam.sas"; **Assign global macro variable DSETNAME to reflect the name of the final ADaM dataset**; %global DSETNAME; %let dsetname = adis; %let adslvar=tr01sdt tr01edt dose2dt dos2dtm tr01sdtm tr01edtm dose1fl dose2fl eosdt dthdt tr02sdt tr02sdtm oldos2dt oldo2dtm randfl saffl sex ELECSBL EUAVACDT AP02SDT; **Merge supplemental data onto parent domain**; %revsupp(libin=trans,libout=work,ds=is,supp=suppis,outds=is_all); proc sort tagsort data=is_all; by usubjid subjid iscat istestcd isdtc; where missing(isstat); run; **INSERT CODE TO GENERATE DATASET**; data is_adsl; merge is_all(in=a) adb.adsl(in=b keep=USUBJID subjid &adslvar.); by usubjid subjid; if a and b; array _ul $200 isuloq islod ismethod; run; data is_adsl; length PARAMCD $8 PARAM $200 _: $200 AVALC post01sdt_adt post01sdt_adt1 $100 PARCAT2 $50; set is_adsl(rename=(isuloq=_isuloq islod=_islod)); * parcat1; PARCAT1 = iscat; PARCAT2 = 'Keep Actual Values Beyond ULOQ'; if ^missing(_isuloq) then ISULOQ=input(_isuloq,best.); if ^missing(_islod) then ISLOD=input(_islod,best.); * paramcd/param; if index(lowcase(parcat1),'neutra') or istestcd='SARSCOV2' then do; PARAMCD = istestcd; PARAM = istest; end; else if index(lowcase(parcat1),'binding') then do; PARAMCD = istestcd; if ^missing(isstresu) then PARAM = strip(istest)||' ('||strip(isstresu)||')'; else PARAM = strip(istest)||' ('||strip(isorresu)||')'; end; else delete; if isnam in ('PPD Vaccine' 'VRC') and ismethod^='' and istestcd^='SARSCOV2' then param = strip(param)|| ' by '||ismethod; else if isnam='PPD Vaccine' and istestcd^='SARSCOV2' then param = strip(param)|| ' by ELISA'; else if isnam='VRC' and istestcd^='SARSCOV2' then param = strip(param)|| ' by MSD MULTIPLEX'; if istest='PsVNT50' then PARAM='Pseudovirus Neutralizing Antibody ID50 Titers'; if istest='PsVNT80' then PARAM='Pseudovirus Neutralizing Antibody ID80 Titers'; if istestcd='MN50' then PARAM='Wild Type Live Virus nAb Microneutralization 50%'; if istestcd='SARSCOV2' then PARAM='Elecsys Anti-SARS-CoV-2'; PARAMCD=upcase(PARAMCD); * results AVAL; if index(isstresc,'<') or index(upcase(isstresc),'BQL') OR .. then AVAL = ISLLOQ*0.5; end; else if index(isstresc,'>') then do; DTYPE = 'ULOQ'; AVAL = ISULOQ; end; else AVAL = ISSTRESN; AVALC = ISSTRESC; * Analysis Date/time; update_isdtc = tranwrd(isdtc,'TUN:UN',''); %ISO2SAS(isodate=update_isdtc, datec=_isdtc, daten=ADT, timec=_atmc); if index(_atmc,'--')=0 and ^missing(_atmc) then ATM = input(_atmc,time5.); if index(_atmc,'--')=0 and ^missing(_atmc) and ^missing(ADT) then ori_ADTM = input(compress(put(ADT,date9.)||':'||_atmc),datetime20.); adtm=.; %caldy(stdt=ADT,endt=TR01SDT,outdy=ADY); *** Period; if .tr01sdt>. and index(visit,'Uns') then addsortn = put(adt,yymmdd10.)||' - 999'; else if (visit=:'Ill' or visit=:'Conva' or index(visit,'OL-D')) and adt>tr01sdt>. then addsortn = put(adt,yymmdd10.); else if (visit=:'Ill' or visit=:'Conva' or index(visit,'OL-D')) and missing(isdtc) then addsortn = '0000'; if adt>tr01sdt>. then post01sdt_adt = put(0-visitnum+10000,z8.); else post01sdt_adt = isdtc; if adt>tr01sdt>. then post01sdt_adt1 = put(0-visitnum+10000,z8.); else post01sdt_adt1 = isdtc||put(visitnum,z5.2); format ADTM datetime20. ADT date9. ATM time5.; run; %macro newparamcd(cd=,ram=,l10=); data new_&cd; set is_adsl(where=(paramcd="&cd.")); PARAMTYP = 'DERIVED'; PARAMCD = "&l10.";*||"&cd."; PARAM = "&ram."; if AVAL not in (. 0) then do; AVAL = log10(AVAL); _isstresc = vvalue(aval); output; end; run; %mend newparamcd; %newparamcd(cd=MN50,ram=%nrstr(LOG10(MN50)),l10=L10MN50); %newparamcd(cd=V58IG1S,ram=%nrstr(LOG10(VAC58 Spike IgG subclass 1)),l10=LV58IG1S); %newparamcd(cd=V58IG2S,ram=%nrstr(LOG10(VAC58 Spike IgG subclass 2)),l10=LV58IG2S); %newparamcd(cd=V58IG3S,ram=%nrstr(LOG10(VAC58 Spike IgG subclass 3)),l10=LV58IG3S); %newparamcd(cd=V58IG4S,ram=%nrstr(LOG10(VAC58 Spike IgG subclass 4)),l10=LV58IG4S); %newparamcd(cd=V58IGMS,ram=%nrstr(LOG10(VAC58 Spike IgM Antibody)),l10=LV58IGMS); %newparamcd(cd=V58IGGS,ram=%nrstr(LOG10(VAC58 Spike IgG Antibody)),l10=LV58IGGS); /*IgA */ %newparamcd(cd=V65IGGS,ram=%nrstr(LOG10(VAC65 Spike IgG Antibody)),l10=LV65IGGS); %newparamcd(cd=V66IGGN,ram=%nrstr(LOG10(VAC66 Nucleocapsid IgG Antibody)),l10=LV66IGGN); %newparamcd(cd=NPIGG,ram=%nrstr(LOG10(SARSCOV2NP IgG Antibody)),l10=LNPIGG); %newparamcd(cd=RBDIGG,ram=%nrstr(LOG10(SARSCOV2RBD IgG Antibody)),l10=LRBDIGG); %newparamcd(cd=S2PIGG,ram=%nrstr(LOG10(SARSCOV2S2P IgG Antibody)),l10=LS2PIGG); %newparamcd(cd=PSVNT50,ram=%nrstr(LOG10(PsVNT50)),l10=L10PVN50); %newparamcd(cd=PSVNT80,ram=%nrstr(LOG10(PsVNT80)),l10=L10PVN80); data newparamcd; set is_adsl new_:; if AVAL>. then _isstresc = 'Results'; else if paramcd='SARSCOV2' then _isstresc = avalc; else _isstresc = ''; run; * Baseline Record Flag & Analysis Windows & CHG/PCHG; %ablfl(indst=newparamcd,outdst=base_chg, seq=isseq, basec=Y, avisit_type=2, stresc=_isstresc, tpt=post01sdt_adt1, tptnum= descending post01sdt_adt, addsortn=addsortn); proc sort tagsort data=anl01fl; by usubjid subjid paramcd descending _avaln postfl adt avisit; run; data adis_atpt; length ATPT $20; set anl01fl; by usubjid subjid paramcd descending _avaln postfl adt avisit; retain _ablfl_bql; if ablfl='Y' and (index(isstresc,'<') or index(upcase(isstresc),'BQL') OR .34 then do; ATPT = ''; AWRANGE = ''; AWTARGET = .; AWTDIFF = .; end; else if index(ori_visit,'Uns') and missing(_ill_dat) and first.avisit then do; ATPT = ''; AWRANGE = ''; AWTARGET = .; AWTDIFF = .; end; else if index(ori_visit,'Uns') and missing(_ill_dat) then do; ATPT = ''; AWRANGE = ''; AWTARGET = .; AWTDIFF = .; end; else if visit='Illness Visit Day 3 - Day 21' and missing(_ill_dat) then do; ATPT = ''; AWRANGE = ''; AWTARGET = .; AWTDIFF = .; end; end; if ^missing(ATPT) then ATPTN = input(compress(scan(ATPT,2,' ')),best.); run; * Analysis Flag 02; data adis; length CRIT1 CRIT2 CRIT3 CRIT4 CRIT5 CRIT6 $100; set adis_atpt; if PARAMTYP^='DERIVED' and ADT>. then do; * Criterion 1 Evaluation Result Flag; if (index(BASEC,'<') or index(upcase(isstresc),'BQL') or (BASE.)) and AVAL>=2*ISLLOQ and ISLLOQ>. then CRIT1FL = 'Y'; else if index(BASEC,'<')=0 and index(upcase(isstresc),'BQL')=0 and not (.=2 then CRIT1FL = 'Y'; if CRIT1FL='Y' then CRIT1 = '>=2-fold Increase from Baseline'; * Criterion 2 Evaluation Result Flag; if (index(BASEC,'<') or index(upcase(isstresc),'BQL') or (BASE.)) and AVAL>=3*ISLLOQ and ISLLOQ>. then CRIT2FL = 'Y'; else if index(BASEC,'<')=0 and index(upcase(isstresc),'BQL')=0 and not (.=3 then CRIT2FL = 'Y'; if CRIT2FL='Y' then CRIT2 = '>=3-fold Increase from Baseline'; * Criterion 3 Evaluation Result Flag; if (index(BASEC,'<') or index(upcase(isstresc),'BQL') or (BASE.)) and AVAL>=4*ISLLOQ and ISLLOQ>. then CRIT3FL = 'Y'; else if index(BASEC,'<')=0 and index(upcase(isstresc),'BQL')=0 and not (.=4 then CRIT3FL = 'Y'; if CRIT3FL='Y' then CRIT3 = '>=4-fold Increase from Baseline'; * Criterion 4 Evaluation Result Flag; if (index(BASEC,'<') or index(upcase(isstresc),'BQL') or (BASE.)) and AVAL>=ISLLOQ and ISLLOQ>. then CRIT4FL = 'Y'; else if index(BASEC,'<')=0 and index(upcase(isstresc),'BQL')=0 and not (.=4 then CRIT4FL = 'Y'; if CRIT4FL='Y' then CRIT4 = 'Seroconversion Due to Vaccination'; * Criterion 5 Evaluation Result Flag; if elecsbl='Negative' and paramcd='SARSCOV2' and postfl='Y' and upcase(ISSTRESC)='POSITIVE' then CRIT5FL = 'Y'; else if elecsbl='Positive' and paramcd='V66IGGEN' and postfl='Y' and R2BASE>=4 then CRIT5FL = 'Y'; if CRIT5FL='Y' then CRIT5 = 'Seroconversion Due to Infection'; * Criterion 6 Evaluation Result Flag; if PARAMCD='PSVNT50' then x = 3.3; else if PARAMCD='PSVNT80' then x = 2.3; else if PARAMCD='V65IGGS' then x = 4.6; else if PARAMCD='S2PIGG' then x = 1.9; else x = 4; if (index(BASEC,'<') or index(upcase(isstresc),'BQL') or (BASE.)) and AVAL>=ISLLOQ and ISLLOQ>. then CRIT6FL = 'Y'; else if index(BASEC,'<')=0 and index(upcase(isstresc),'BQL')=0 and not (BASE.) and R2BASE>=x then CRIT6FL = 'Y'; else CRIT6FL = ''; if CRIT6FL='Y' then CRIT6 = 'Seroresponse'; if PARAMCD not in ('SARSCOV2' 'V66IGGN') then call missing(CRIT5,CRIT5FL); if PARAMCD in ('SARSCOV2') then call missing(CRIT6,CRIT6FL); if PARAMCD=:'L' then call missing(CRIT1,CRIT1FL,CRIT2,CRIT2FL,CRIT3,CRIT3FL,CRIT4,CRIT4FL,CRIT6,CRIT6FL); end; if PARAMTYP='DERIVED' then call missing(ISSTRESC,ISORNRLO,ISORNRHI,ISSTRESN); if paramcd^='SARSCOV2' then AVALC = ''; else PARCAT2 = ''; array _range(1) $40 RANGE; drop SEX RANDFL SAFFL DOSE1FL DOSE2FL ELECSBL TR01SDT TR01EDT TR01EDTM DOSE2DT TR01SDTM DOS2DTM MDOSREF; run; **Generate final dataset by updating certain attributes. Optionally merge common variables & create sequence variable as needed**; %TRTA(dsname=&DSETNAME); %adam_dataset_update( ds=&DSETNAME, libin=work, libout=output, adsllib=adb, addcomvar=Y, addseq=, dropinfmt=Y, mapspecfile=&ADAM_SPEC, maploc=&ADAM_SPEC_LOC, debug=N ); **Generate Value Level Metadata values for the ad dataset**; %* dod_vlm( type=ADAM, selmems=&DSETNAME, excmems=, specloc=&ADAM_SPEC_LOC, specname=&ADAM_SPEC, debug=N ); **Generate Enhanced Controlled Terminology for the ad dataset**; %* dod_enhcd_ct( type=ADAM, selmems=&DSETNAME, excmems=, specloc=&ADAM_SPEC_LOC, specname=&ADAM_SPEC, map_ct_nm=, map_ct_loc=, debug=N ); /* %put 'put Aler'||'t_R: check below ABLFL and confirm maximum AVAL is flagged.'; data adb_is; set adb.adis; where tr01sdt=adt and adt>.; keep subjid paramcd tr01sdt isdtc aval avalc ablfl base visit avisit; run; proc sql; create table adb2_is as select *,count(*) as n,count(distinct aval) as n2 from adb_is group by subjid,paramcd having n>1 and n2>1; quit; */