The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics

preprint OA: closed
Full text JSON View at publisher
Full text 176,703 characters · extracted from preprint-html · click to expand
The EpiFusion Analysis Framework for joint... | F1000Research "use strict";function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}!function(){var t=function(){var t,e,o=[],n=window,r=n;for(;r;){try{if(r.frames.__tcfapiLocator){t=r;break}}catch(t){}if(r===n.top)break;r=r.parent}t||(!function t(){var e=n.document,o=!!n.frames.__tcfapiLocator;if(!o)if(e.body){var r=e.createElement("iframe");r.style.cssText="display:none",r.name="__tcfapiLocator",e.body.appendChild(r)}else setTimeout(t,5);return!o}(),n.__tcfapi=function(){for(var t=arguments.length,n=new Array(t),r=0;r 3&&2===parseInt(n[1],10)&&"boolean"==typeof n[3]&&(e=n[3],"function"==typeof n[2]&&n[2]("set",!0)):"ping"===n[0]?"function"==typeof n[2]&&n[2]({gdprApplies:e,cmpLoaded:!1,cmpStatus:"stub"}):o.push(n)},n.addEventListener("message",(function(t){var e="string"==typeof t.data,o={};if(e)try{o=JSON.parse(t.data)}catch(t){}else o=t.data;var n="object"===_typeof(o)&&null!==o?o.__tcfapiCall:null;n&&window.__tcfapi(n.command,n.version,(function(o,r){var a={__tcfapiReturn:{returnValue:o,success:r,callId:n.callId}};t&&t.source&&t.source.postMessage&&t.source.postMessage(e?JSON.stringify(a):a,"*")}),n.parameter)}),!1))};"undefined"!=typeof module?module.exports=t:t()}(); dataLayer = dataLayer || []; // Standard GTM initialization - Google Consent Mode handles consent automatically (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl+ '>m_auth=hzk0Vc3qFsQYhCrIoHz68A>m_preview=env-1>m_cookies_win=x';f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-MWFK8L5J'); ;window.NREUM||(NREUM={});NREUM.init={distributed_tracing:{enabled:true},privacy:{cookies_enabled:true},ajax:{deny_list:["bam.nr-data.net"]}}; ;NREUM.loader_config={accountID:"438030",trustKey:"438030",agentID:"772317073",licenseKey:"97f8f67f26",applicationID:"772317073"} ;NREUM.info={beacon:"bam.nr-data.net",errorBeacon:"bam.nr-data.net",licenseKey:"97f8f67f26",applicationID:"772317073",sa:1} ;/*! For license information please see nr-loader-spa-1.236.0.min.js.LICENSE.txt */ (()=>{"use strict";var e,t,r={5763:(e,t,r)=>{r.d(t,{P_:()=>l,Mt:()=>g,C5:()=>s,DL:()=>v,OP:()=>T,lF:()=>D,Yu:()=>y,Dg:()=>h,CX:()=>c,GE:()=>b,sU:()=>_});var n=r(8632),i=r(9567);const o={beacon:n.ce.beacon,errorBeacon:n.ce.errorBeacon,licenseKey:void 0,applicationID:void 0,sa:void 0,queueTime:void 0,applicationTime:void 0,ttGuid:void 0,user:void 0,account:void 0,product:void 0,extra:void 0,jsAttributes:{},userAttributes:void 0,atts:void 0,transactionName:void 0,tNamePlain:void 0},a={};function s(e){if(!e)throw new Error("All info objects require an agent identifier!");if(!a[e])throw new Error("Info for ".concat(e," was never set"));return a[e]}function c(e,t){if(!e)throw new Error("All info objects require an agent identifier!");a[e]=(0,i.D)(t,o),(0,n.Qy)(e,a[e],"info")}var u=r(7056);const d=()=>{const e={blockSelector:"[data-nr-block]",maskInputOptions:{password:!0}};return{allow_bfcache:!0,privacy:{cookies_enabled:!0},ajax:{deny_list:void 0,enabled:!0,harvestTimeSeconds:10},distributed_tracing:{enabled:void 0,exclude_newrelic_header:void 0,cors_use_newrelic_header:void 0,cors_use_tracecontext_headers:void 0,allowed_origins:void 0},session:{domain:void 0,expiresMs:u.oD,inactiveMs:u.Hb},ssl:void 0,obfuscate:void 0,jserrors:{enabled:!0,harvestTimeSeconds:10},metrics:{enabled:!0},page_action:{enabled:!0,harvestTimeSeconds:30},page_view_event:{enabled:!0},page_view_timing:{enabled:!0,harvestTimeSeconds:30,long_task:!1},session_trace:{enabled:!0,harvestTimeSeconds:10},harvest:{tooManyRequestsDelay:60},session_replay:{enabled:!1,harvestTimeSeconds:60,sampleRate:.1,errorSampleRate:.1,maskTextSelector:"*",maskAllInputs:!0,get blockClass(){return"nr-block"},get ignoreClass(){return"nr-ignore"},get maskTextClass(){return"nr-mask"},get blockSelector(){return e.blockSelector},set blockSelector(t){e.blockSelector+=",".concat(t)},get maskInputOptions(){return e.maskInputOptions},set maskInputOptions(t){e.maskInputOptions={...t,password:!0}}},spa:{enabled:!0,harvestTimeSeconds:10}}},f={};function l(e){if(!e)throw new Error("All configuration objects require an agent identifier!");if(!f[e])throw new Error("Configuration for ".concat(e," was never set"));return f[e]}function h(e,t){if(!e)throw new Error("All configuration objects require an agent identifier!");f[e]=(0,i.D)(t,d()),(0,n.Qy)(e,f[e],"config")}function g(e,t){if(!e)throw new Error("All configuration objects require an agent identifier!");var r=l(e);if(r){for(var n=t.split("."),i=0;i {r.d(t,{D:()=>i});var n=r(50);function i(e,t){try{if(!e||"object"!=typeof e)return(0,n.Z)("Setting a Configurable requires an object as input");if(!t||"object"!=typeof t)return(0,n.Z)("Setting a Configurable requires a model to set its initial properties");const r=Object.create(Object.getPrototypeOf(t),Object.getOwnPropertyDescriptors(t)),o=0===Object.keys(r).length?e:r;for(let a in o)if(void 0!==e[a])try{"object"==typeof e[a]&&"object"==typeof t[a]?r[a]=i(e[a],t[a]):r[a]=e[a]}catch(e){(0,n.Z)("An error occurred while setting a property of a Configurable",e)}return r}catch(e){(0,n.Z)("An error occured while setting a Configurable",e)}}},6818:(e,t,r)=>{r.d(t,{Re:()=>i,gF:()=>o,q4:()=>n});const n="1.236.0",i="PROD",o="CDN"},385:(e,t,r)=>{r.d(t,{FN:()=>a,IF:()=>u,Nk:()=>f,Tt:()=>s,_A:()=>o,il:()=>n,pL:()=>c,v6:()=>i,w1:()=>d});const n="undefined"!=typeof window&&!!window.document,i="undefined"!=typeof WorkerGlobalScope&&("undefined"!=typeof self&&self instanceof WorkerGlobalScope&&self.navigator instanceof WorkerNavigator||"undefined"!=typeof globalThis&&globalThis instanceof WorkerGlobalScope&&globalThis.navigator instanceof WorkerNavigator),o=n?window:"undefined"!=typeof WorkerGlobalScope&&("undefined"!=typeof self&&self instanceof WorkerGlobalScope&&self||"undefined"!=typeof globalThis&&globalThis instanceof WorkerGlobalScope&&globalThis),a=""+o?.location,s=/iPad|iPhone|iPod/.test(navigator.userAgent),c=s&&"undefined"==typeof SharedWorker,u=(()=>{const e=navigator.userAgent.match(/Firefox[/\s](\d+\.\d+)/);return Array.isArray(e)&&e.length>=2?+e[1]:0})(),d=Boolean(n&&window.document.documentMode),f=!!navigator.sendBeacon},1117:(e,t,r)=>{r.d(t,{w:()=>o});var n=r(50);const i={agentIdentifier:"",ee:void 0};class o{constructor(e){try{if("object"!=typeof e)return(0,n.Z)("shared context requires an object as input");this.sharedContext={},Object.assign(this.sharedContext,i),Object.entries(e).forEach((e=>{let[t,r]=e;Object.keys(i).includes(t)&&(this.sharedContext[t]=r)}))}catch(e){(0,n.Z)("An error occured while setting SharedContext",e)}}}},8e3:(e,t,r)=>{r.d(t,{L:()=>d,R:()=>c});var n=r(2177),i=r(1284),o=r(4322),a=r(3325);const s={};function c(e,t){const r={staged:!1,priority:a.p[t]||0};u(e),s[e].get(t)||s[e].set(t,r)}function u(e){e&&(s[e]||(s[e]=new Map))}function d(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"feature";if(u(e),!e||!s[e].get(t))return a(t);s[e].get(t).staged=!0;const r=[...s[e]];function a(t){const r=e?n.ee.get(e):n.ee,a=o.X.handlers;if(r.backlog&&a){var s=r.backlog[t],c=a[t];if(c){for(var u=0;s&&u {let[t,r]=e;return r.staged}))&&(r.sort(((e,t)=>e[1].priority-t[1].priority)),r.forEach((e=>{let[t]=e;a(t)})))}function f(e,t){var r=e[1];(0,i.D)(t[r],(function(t,r){var n=e[0];if(r[0]===n){var i=r[1],o=e[3],a=e[2];i.apply(o,a)}}))}},2177:(e,t,r)=>{r.d(t,{c:()=>f,ee:()=>u});var n=r(8632),i=r(2210),o=r(1284),a=r(5763),s="nr@context";let c=(0,n.fP)();var u;function d(){}function f(e){return(0,i.X)(e,s,l)}function l(){return new d}function h(){u.aborted=!0,u.backlog={}}c.ee?u=c.ee:(u=function e(t,r){var n={},c={},f={},g=!1;try{g=16===r.length&&(0,a.OP)(r).isolatedBacklog}catch(e){}var p={on:b,addEventListener:b,removeEventListener:y,emit:v,get:x,listeners:w,context:m,buffer:A,abort:h,aborted:!1,isBuffering:E,debugId:r,backlog:g?{}:t&&"object"==typeof t.backlog?t.backlog:{}};return p;function m(e){return e&&e instanceof d?e:e?(0,i.X)(e,s,l):l()}function v(e,r,n,i,o){if(!1!==o&&(o=!0),!u.aborted||i){t&&o&&t.emit(e,r,n);for(var a=m(n),s=w(e),d=s.length,f=0;fn,p:()=>i});var n=r(2177).ee.get("handle");function i(e,t,r,i,o){o?(o.buffer([e],i),o.emit(e,t,r)):(n.buffer([e],i),n.emit(e,t,r))}},4322:(e,t,r)=>{r.d(t,{X:()=>o});var n=r(5546);o.on=a;var i=o.handlers={};function o(e,t,r,o){a(o||n.E,i,e,t,r)}function a(e,t,r,i,o){o||(o="feature"),e||(e=n.E);var a=t[o]=t[o]||{};(a[r]=a[r]||[]).push([e,i])}},3239:(e,t,r)=>{r.d(t,{bP:()=>s,iz:()=>c,m$:()=>a});var n=r(385);let i=!1,o=!1;try{const e={get passive(){return i=!0,!1},get signal(){return o=!0,!1}};n._A.addEventListener("test",null,e),n._A.removeEventListener("test",null,e)}catch(e){}function a(e,t){return i||o?{capture:!!e,passive:i,signal:t}:!!e}function s(e,t){let r=arguments.length>2&&void 0!==arguments[2]&&arguments[2],n=arguments.length>3?arguments[3]:void 0;window.addEventListener(e,t,a(r,n))}function c(e,t){let r=arguments.length>2&&void 0!==arguments[2]&&arguments[2],n=arguments.length>3?arguments[3]:void 0;document.addEventListener(e,t,a(r,n))}},4402:(e,t,r)=>{r.d(t,{Ht:()=>u,M:()=>c,Rl:()=>a,ky:()=>s});var n=r(385);const i="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";function o(e,t){return e?15&e[t]:16*Math.random()|0}function a(){const e=n._A?.crypto||n._A?.msCrypto;let t,r=0;return e&&e.getRandomValues&&(t=e.getRandomValues(new Uint8Array(31))),i.split("").map((e=>"x"===e?o(t,++r).toString(16):"y"===e?(3&o()|8).toString(16):e)).join("")}function s(e){const t=n._A?.crypto||n._A?.msCrypto;let r,i=0;t&&t.getRandomValues&&(r=t.getRandomValues(new Uint8Array(31)));const a=[];for(var s=0;s {r.d(t,{Bq:()=>n,Hb:()=>o,oD:()=>i});const n="NRBA",i=144e5,o=18e5},7894:(e,t,r)=>{function n(){return Math.round(performance.now())}r.d(t,{z:()=>n})},7243:(e,t,r)=>{r.d(t,{e:()=>o});var n=r(385),i={};function o(e){if(e in i)return i[e];if(0===(e||"").indexOf("data:"))return{protocol:"data"};let t;var r=n._A?.location,o={};if(n.il)t=document.createElement("a"),t.href=e;else try{t=new URL(e,r.href)}catch(e){return o}o.port=t.port;var a=t.href.split("://");!o.port&&a[1]&&(o.port=a[1].split("/")[0].split("@").pop().split(":")[1]),o.port&&"0"!==o.port||(o.port="https"===a[0]?"443":"80"),o.hostname=t.hostname||r.hostname,o.pathname=t.pathname,o.protocol=a[0],"/"!==o.pathname.charAt(0)&&(o.pathname="/"+o.pathname);var s=!t.protocol||":"===t.protocol||t.protocol===r.protocol,c=t.hostname===r.hostname&&t.port===r.port;return o.sameOrigin=s&&(!t.hostname||c),"/"===o.pathname&&(i[e]=o),o}},50:(e,t,r)=>{function n(e,t){"function"==typeof console.warn&&(console.warn("New Relic: ".concat(e)),t&&console.warn(t))}r.d(t,{Z:()=>n})},2587:(e,t,r)=>{r.d(t,{N:()=>c,T:()=>u});var n=r(2177),i=r(5546),o=r(8e3),a=r(3325);const s={stn:[a.D.sessionTrace],err:[a.D.jserrors,a.D.metrics],ins:[a.D.pageAction],spa:[a.D.spa],sr:[a.D.sessionReplay,a.D.sessionTrace]};function c(e,t){const r=n.ee.get(t);e&&"object"==typeof e&&(Object.entries(e).forEach((e=>{let[t,n]=e;void 0===u[t]&&(s[t]?s[t].forEach((e=>{n?(0,i.p)("feat-"+t,[],void 0,e,r):(0,i.p)("block-"+t,[],void 0,e,r),(0,i.p)("rumresp-"+t,[Boolean(n)],void 0,e,r)})):n&&(0,i.p)("feat-"+t,[],void 0,void 0,r),u[t]=Boolean(n))})),Object.keys(s).forEach((e=>{void 0===u[e]&&(s[e]?.forEach((t=>(0,i.p)("rumresp-"+e,[!1],void 0,t,r))),u[e]=!1)})),(0,o.L)(t,a.D.pageViewEvent))}const u={}},2210:(e,t,r)=>{r.d(t,{X:()=>i});var n=Object.prototype.hasOwnProperty;function i(e,t,r){if(n.call(e,t))return e[t];var i=r();if(Object.defineProperty&&Object.keys)try{return Object.defineProperty(e,t,{value:i,writable:!0,enumerable:!1}),i}catch(e){}return e[t]=i,i}},1284:(e,t,r)=>{r.d(t,{D:()=>n});const n=(e,t)=>Object.entries(e||{}).map((e=>{let[r,n]=e;return t(r,n)}))},4351:(e,t,r)=>{r.d(t,{P:()=>o});var n=r(2177);const i=()=>{const e=new WeakSet;return(t,r)=>{if("object"==typeof r&&null!==r){if(e.has(r))return;e.add(r)}return r}};function o(e){try{return JSON.stringify(e,i())}catch(e){try{n.ee.emit("internal-error",[e])}catch(e){}}}},3960:(e,t,r)=>{r.d(t,{K:()=>a,b:()=>o});var n=r(3239);function i(){return"undefined"==typeof document||"complete"===document.readyState}function o(e,t){if(i())return e();(0,n.bP)("load",e,t)}function a(e){if(i())return e();(0,n.iz)("DOMContentLoaded",e)}},8632:(e,t,r)=>{r.d(t,{EZ:()=>u,Qy:()=>c,ce:()=>o,fP:()=>a,gG:()=>d,mF:()=>s});var n=r(7894),i=r(385);const o={beacon:"bam.nr-data.net",errorBeacon:"bam.nr-data.net"};function a(){return i._A.NREUM||(i._A.NREUM={}),void 0===i._A.newrelic&&(i._A.newrelic=i._A.NREUM),i._A.NREUM}function s(){let e=a();return e.o||(e.o={ST:i._A.setTimeout,SI:i._A.setImmediate,CT:i._A.clearTimeout,XHR:i._A.XMLHttpRequest,REQ:i._A.Request,EV:i._A.Event,PR:i._A.Promise,MO:i._A.MutationObserver,FETCH:i._A.fetch}),e}function c(e,t,r){let i=a();const o=i.initializedAgents||{},s=o[e]||{};return Object.keys(s).length||(s.initializedAt={ms:(0,n.z)(),date:new Date}),i.initializedAgents={...o,[e]:{...s,[r]:t}},i}function u(e,t){a()[e]=t}function d(){return function(){let e=a();const t=e.info||{};e.info={beacon:o.beacon,errorBeacon:o.errorBeacon,...t}}(),function(){let e=a();const t=e.init||{};e.init={...t}}(),s(),function(){let e=a();const t=e.loader_config||{};e.loader_config={...t}}(),a()}},7956:(e,t,r)=>{r.d(t,{N:()=>i});var n=r(3239);function i(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],r=arguments.length>2?arguments[2]:void 0,i=arguments.length>3?arguments[3]:void 0;return void(0,n.iz)("visibilitychange",(function(){if(t)return void("hidden"==document.visibilityState&&e());e(document.visibilityState)}),r,i)}},1214:(e,t,r)=>{r.d(t,{em:()=>v,u5:()=>N,QU:()=>S,_L:()=>I,Gm:()=>L,Lg:()=>M,gy:()=>U,BV:()=>Q,Kf:()=>ee});var n=r(2177);const i="nr@original";var o=Object.prototype.hasOwnProperty,a=!1;function s(e,t){return e||(e=n.ee),r.inPlace=function(e,t,n,i,o){n||(n="");var a,s,c,u="-"===n.charAt(0);for(c=0;c 2?n-2:0),o=2;o {r(A[T],e,w),r(E[T],e,w)})),r(l._A,"fetch",y),t.on(y+"end",(function(e,r){var n=this;if(r){var i=r.headers.get("content-length");null!==i&&(n.rxSize=i),t.emit(y+"done",[null,r],n)}else t.emit(y+"done",[e],n)})),t}const O={},j=["pushState","replaceState"];function S(e){const t=function(e){return(e||n.ee).get("history")}(e);return!l.il||O[t.debugId]++||(O[t.debugId]=1,s(t).inPlace(window.history,j,"-")),t}var P=r(3239);const C={},R=["appendChild","insertBefore","replaceChild"];function I(e){const t=function(e){return(e||n.ee).get("jsonp")}(e);if(!l.il||C[t.debugId])return t;C[t.debugId]=!0;var r=s(t),i=/[?&](?:callback|cb)=([^&#]+)/,o=/(.*)\.([^.]+)/,a=/^(\w+)(\.|$)(.*)$/;function c(e,t){var r=e.match(a),n=r[1],i=r[3];return i?c(i,t[n]):t[n]}return r.inPlace(Node.prototype,R,"dom-"),t.on("dom-start",(function(e){!function(e){if(!e||"string"!=typeof e.nodeName||"script"!==e.nodeName.toLowerCase())return;if("function"!=typeof e.addEventListener)return;var n=(a=e.src,s=a.match(i),s?s[1]:null);var a,s;if(!n)return;var u=function(e){var t=e.match(o);if(t&&t.length>=3)return{key:t[2],parent:c(t[1],window)};return{key:e,parent:window}}(n);if("function"!=typeof u.parent[u.key])return;var d={};function f(){t.emit("jsonp-end",[],d),e.removeEventListener("load",f,(0,P.m$)(!1)),e.removeEventListener("error",l,(0,P.m$)(!1))}function l(){t.emit("jsonp-error",[],d),t.emit("jsonp-end",[],d),e.removeEventListener("load",f,(0,P.m$)(!1)),e.removeEventListener("error",l,(0,P.m$)(!1))}r.inPlace(u.parent,[u.key],"cb-",d),e.addEventListener("load",f,(0,P.m$)(!1)),e.addEventListener("error",l,(0,P.m$)(!1)),t.emit("new-jsonp",[e.src],d)}(e[0])})),t}var k=r(5763);const H={};function L(e){const t=function(e){return(e||n.ee).get("mutation")}(e);if(!l.il||H[t.debugId])return t;H[t.debugId]=!0;var r=s(t),i=k.Yu.MO;return i&&(window.MutationObserver=function(e){return this instanceof i?new i(r(e,"fn-")):i.apply(this,arguments)},MutationObserver.prototype=i.prototype),t}const z={};function M(e){const t=function(e){return(e||n.ee).get("promise")}(e);if(z[t.debugId])return t;z[t.debugId]=!0;var r=n.c,o=s(t),a=k.Yu.PR;return a&&function(){function e(r){var n=t.context(),i=o(r,"executor-",n,null,!1);const s=Reflect.construct(a,[i],e);return t.context(s).getCtx=function(){return n},s}l._A.Promise=e,Object.defineProperty(e,"name",{value:"Promise"}),e.toString=function(){return a.toString()},Object.setPrototypeOf(e,a),["all","race"].forEach((function(r){const n=a[r];e[r]=function(e){let i=!1;[...e||[]].forEach((e=>{this.resolve(e).then(a("all"===r),a(!1))}));const o=n.apply(this,arguments);return o;function a(e){return function(){t.emit("propagate",[null,!i],o,!1,!1),i=i||!e}}}})),["resolve","reject"].forEach((function(r){const n=a[r];e[r]=function(e){const r=n.apply(this,arguments);return e!==r&&t.emit("propagate",[e,!0],r,!1,!1),r}})),e.prototype=a.prototype;const n=a.prototype.then;a.prototype.then=function(){var e=this,i=r(e);i.promise=e;for(var a=arguments.length,s=new Array(a),c=0;c e())),t};function m(e,t){i.inPlace(t,["onreadystatechange"],"fn-",E)}function b(){var e=this,t=r.context(e);e.readyState>3&&!t.resolved&&(t.resolved=!0,r.emit("xhr-resolved",[],e)),i.inPlace(e,f,"fn-",E)}if(function(e,t){for(var r in e)t[r]=e[r]}(o,p),p.prototype=o.prototype,i.inPlace(p.prototype,J,"-xhr-",E),r.on("send-xhr-start",(function(e,t){m(e,t),function(e){h.push(e),a&&(y?y.then(A):u?u(A):(w=-w,x.data=w))}(t)})),r.on("open-xhr-start",m),a){var y=c&&c.resolve();if(!u&&!c){var w=1,x=document.createTextNode(w);new a(A).observe(x,{characterData:!0})}}else t.on("fn-end",(function(e){e[0]&&e[0].type===d||A()}));function A(){for(var e=0;e {r.d(t,{t:()=>n});const n=r(3325).D.ajax},6660:(e,t,r)=>{r.d(t,{A:()=>i,t:()=>n});const n=r(3325).D.jserrors,i="nr@seenError"},3081:(e,t,r)=>{r.d(t,{gF:()=>o,mY:()=>i,t9:()=>n,vz:()=>s,xS:()=>a});const n=r(3325).D.metrics,i="sm",o="cm",a="storeSupportabilityMetrics",s="storeEventMetrics"},4649:(e,t,r)=>{r.d(t,{t:()=>n});const n=r(3325).D.pageAction},7633:(e,t,r)=>{r.d(t,{Dz:()=>i,OJ:()=>a,qw:()=>o,t9:()=>n});const n=r(3325).D.pageViewEvent,i="firstbyte",o="domcontent",a="windowload"},9251:(e,t,r)=>{r.d(t,{t:()=>n});const n=r(3325).D.pageViewTiming},3614:(e,t,r)=>{r.d(t,{BST_RESOURCE:()=>i,END:()=>s,FEATURE_NAME:()=>n,FN_END:()=>u,FN_START:()=>c,PUSH_STATE:()=>d,RESOURCE:()=>o,START:()=>a});const n=r(3325).D.sessionTrace,i="bstResource",o="resource",a="-start",s="-end",c="fn"+a,u="fn"+s,d="pushState"},7836:(e,t,r)=>{r.d(t,{BODY:()=>A,CB_END:()=>E,CB_START:()=>u,END:()=>x,FEATURE_NAME:()=>i,FETCH:()=>_,FETCH_BODY:()=>v,FETCH_DONE:()=>m,FETCH_START:()=>p,FN_END:()=>c,FN_START:()=>s,INTERACTION:()=>l,INTERACTION_API:()=>d,INTERACTION_EVENTS:()=>o,JSONP_END:()=>b,JSONP_NODE:()=>g,JS_TIME:()=>T,MAX_TIMER_BUDGET:()=>a,REMAINING:()=>f,SPA_NODE:()=>h,START:()=>w,originalSetTimeout:()=>y});var n=r(5763);const i=r(3325).D.spa,o=["click","submit","keypress","keydown","keyup","change"],a=999,s="fn-start",c="fn-end",u="cb-start",d="api-ixn-",f="remaining",l="interaction",h="spaNode",g="jsonpNode",p="fetch-start",m="fetch-done",v="fetch-body-",b="jsonp-end",y=n.Yu.ST,w="-start",x="-end",A="-body",E="cb"+x,T="jsTime",_="fetch"},5938:(e,t,r)=>{r.d(t,{W:()=>o});var n=r(5763),i=r(2177);class o{constructor(e,t,r){this.agentIdentifier=e,this.aggregator=t,this.ee=i.ee.get(e,(0,n.OP)(this.agentIdentifier).isolatedBacklog),this.featureName=r,this.blocked=!1}}},9144:(e,t,r)=>{r.d(t,{j:()=>m});var n=r(3325),i=r(5763),o=r(5546),a=r(2177),s=r(7894),c=r(8e3),u=r(3960),d=r(385),f=r(50),l=r(3081),h=r(8632);function g(){const e=(0,h.gG)();["setErrorHandler","finished","addToTrace","inlineHit","addRelease","addPageAction","setCurrentRouteName","setPageViewName","setCustomAttribute","interaction","noticeError","setUserId"].forEach((t=>{e[t]=function(){for(var r=arguments.length,n=new Array(r),i=0;i 1?r-1:0),i=1;i {e.exposed&&e.api[t]&&o.push(e.api[t](...n))})),o.length>1?o:o[0]}(t,...n)}}))}var p=r(2587);function m(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},m=arguments.length>2?arguments[2]:void 0,v=arguments.length>3?arguments[3]:void 0,{init:b,info:y,loader_config:w,runtime:x={loaderType:m},exposed:A=!0}=t;const E=(0,h.gG)();y||(b=E.init,y=E.info,w=E.loader_config),(0,i.Dg)(e,b||{}),(0,i.GE)(e,w||{}),(0,i.sU)(e,x),y.jsAttributes??={},d.v6&&(y.jsAttributes.isWorker=!0),(0,i.CX)(e,y),g();const T=function(e,t){t||(0,c.R)(e,"api");const h={};var g=a.ee.get(e),p=g.get("tracer"),m="api-",v=m+"ixn-";function b(t,r,n,o){const a=(0,i.C5)(e);return null===r?delete a.jsAttributes[t]:(0,i.CX)(e,{...a,jsAttributes:{...a.jsAttributes,[t]:r}}),x(m,n,!0,o||null===r?"session":void 0)(t,r)}function y(){}["setErrorHandler","finished","addToTrace","inlineHit","addRelease"].forEach((e=>h[e]=x(m,e,!0,"api"))),h.addPageAction=x(m,"addPageAction",!0,n.D.pageAction),h.setCurrentRouteName=x(m,"routeName",!0,n.D.spa),h.setPageViewName=function(t,r){if("string"==typeof t)return"/"!==t.charAt(0)&&(t="/"+t),(0,i.OP)(e).customTransaction=(r||"http://custom.transaction")+t,x(m,"setPageViewName",!0)()},h.setCustomAttribute=function(e,t){let r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if("string"==typeof e){if(["string","number"].includes(typeof t)||null===t)return b(e,t,"setCustomAttribute",r);(0,f.Z)("Failed to execute setCustomAttribute.\nNon-null value must be a string or number type, but a type of was provided."))}else(0,f.Z)("Failed to execute setCustomAttribute.\nName must be a string type, but a type of was provided."))},h.setUserId=function(e){if("string"==typeof e||null===e)return b("enduser.id",e,"setUserId",!0);(0,f.Z)("Failed to execute setUserId.\nNon-null value must be a string type, but a type of was provided."))},h.interaction=function(){return(new y).get()};var w=y.prototype={createTracer:function(e,t){var r={},i=this,a="function"==typeof t;return(0,o.p)(v+"tracer",[(0,s.z)(),e,r],i,n.D.spa,g),function(){if(p.emit((a?"":"no-")+"fn-start",[(0,s.z)(),i,a],r),a)try{return t.apply(this,arguments)}catch(e){throw p.emit("fn-err",[arguments,this,"string"==typeof e?new Error(e):e],r),e}finally{p.emit("fn-end",[(0,s.z)()],r)}}}};function x(e,t,r,i){return function(){return(0,o.p)(l.xS,["API/"+t+"/called"],void 0,n.D.metrics,g),i&&(0,o.p)(e+t,[(0,s.z)(),...arguments],r?null:this,i,g),r?void 0:this}}function A(){r.e(439).then(r.bind(r,7438)).then((t=>{let{setAPI:r}=t;r(e),(0,c.L)(e,"api")})).catch((()=>(0,f.Z)("Downloading runtime APIs failed...")))}return["actionText","setName","setAttribute","save","ignore","onEnd","getContext","end","get"].forEach((e=>{w[e]=x(v,e,void 0,n.D.spa)})),h.noticeError=function(e,t){"string"==typeof e&&(e=new Error(e)),(0,o.p)(l.xS,["API/noticeError/called"],void 0,n.D.metrics,g),(0,o.p)("err",[e,(0,s.z)(),!1,t],void 0,n.D.jserrors,g)},d.il?(0,u.b)((()=>A()),!0):A(),h}(e,v);return(0,h.Qy)(e,T,"api"),(0,h.Qy)(e,A,"exposed"),(0,h.EZ)("activatedFeatures",p.T),T}},3325:(e,t,r)=>{r.d(t,{D:()=>n,p:()=>i});const n={ajax:"ajax",jserrors:"jserrors",metrics:"metrics",pageAction:"page_action",pageViewEvent:"page_view_event",pageViewTiming:"page_view_timing",sessionReplay:"session_replay",sessionTrace:"session_trace",spa:"spa"},i={[n.pageViewEvent]:1,[n.pageViewTiming]:2,[n.metrics]:3,[n.jserrors]:4,[n.ajax]:5,[n.sessionTrace]:6,[n.pageAction]:7,[n.spa]:8,[n.sessionReplay]:9}}},n={};function i(e){var t=n[e];if(void 0!==t)return t.exports;var o=n[e]={exports:{}};return r[e](o,o.exports,i),o.exports}i.m=r,i.d=(e,t)=>{for(var r in t)i.o(t,r)&&!i.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},i.f={},i.e=e=>Promise.all(Object.keys(i.f).reduce(((t,r)=>(i.f[r](e,t),t)),[])),i.u=e=>(({78:"page_action-aggregate",147:"metrics-aggregate",242:"session-manager",317:"jserrors-aggregate",348:"page_view_timing-aggregate",412:"lazy-feature-loader",439:"async-api",538:"recorder",590:"session_replay-aggregate",675:"compressor",733:"session_trace-aggregate",786:"page_view_event-aggregate",873:"spa-aggregate",898:"ajax-aggregate"}[e]||e)+"."+{78:"ac76d497",147:"3dc53903",148:"1a20d5fe",242:"2a64278a",317:"49e41428",348:"bd6de33a",412:"2f55ce66",439:"30bd804e",538:"1b18459f",590:"cf0efb30",675:"ae9f91a8",733:"83105561",786:"06482edd",860:"03a8b7a5",873:"e6b09d52",898:"998ef92b"}[e]+"-1.236.0.min.js"),i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e={},t="NRBA:",i.l=(r,n,o,a)=>{if(e[r])e[r].push(n);else{var s,c;if(void 0!==o)for(var u=document.getElementsByTagName("script"),d=0;d {s.onerror=s.onload=null,clearTimeout(h);var i=e[r];if(delete e[r],s.parentNode&&s.parentNode.removeChild(s),i&&i.forEach((e=>e(n))),t)return t(n)},h=setTimeout(l.bind(null,void 0,{type:"timeout",target:s}),12e4);s.onerror=l.bind(null,s.onerror),s.onload=l.bind(null,s.onload),c&&document.head.appendChild(s)}},i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.j=364,i.p="https://js-agent.newrelic.com/",(()=>{var e={364:0,953:0};i.f.j=(t,r)=>{var n=i.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var o=new Promise(((r,i)=>n=e[t]=[r,i]));r.push(n[2]=o);var a=i.p+i.u(t),s=new Error;i.l(a,(r=>{if(i.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var o=r&&("load"===r.type?"missing":r.type),a=r&&r.target&&r.target.src;s.message="Loading chunk "+t+" failed.\n("+o+": "+a+")",s.name="ChunkLoadError",s.type=o,s.request=a,n[1](s)}}),"chunk-"+t,t)}};var t=(t,r)=>{var n,o,[a,s,c]=r,u=0;if(a.some((t=>0!==e[t]))){for(n in s)i.o(s,n)&&(i.m[n]=s[n]);if(c)c(i)}for(t&&t(r);u {i.r(o);var e=i(3325),t=i(5763);const r=Object.values(e.D);function n(e){const n={};return r.forEach((r=>{n[r]=function(e,r){return!1!==(0,t.Mt)(r,"".concat(e,".enabled"))}(r,e)})),n}var a=i(9144);var s=i(5546),c=i(385),u=i(8e3),d=i(5938),f=i(3960),l=i(50);class h extends d.W{constructor(e,t,r){let n=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];super(e,t,r),this.auto=n,this.abortHandler,this.featAggregate,this.onAggregateImported,n&&(0,u.R)(e,r)}importAggregator(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(this.featAggregate||!this.auto)return;const r=c.il&&!0===(0,t.Mt)(this.agentIdentifier,"privacy.cookies_enabled");let n;this.onAggregateImported=new Promise((e=>{n=e}));const o=async()=>{let t;try{if(r){const{setupAgentSession:e}=await Promise.all([i.e(860),i.e(242)]).then(i.bind(i,3228));t=e(this.agentIdentifier)}}catch(e){(0,l.Z)("A problem occurred when starting up session manager. This page will not start or extend any session.",e)}try{if(!this.shouldImportAgg(this.featureName,t))return void(0,u.L)(this.agentIdentifier,this.featureName);const{lazyFeatureLoader:r}=await i.e(412).then(i.bind(i,8582)),{Aggregate:o}=await r(this.featureName,"aggregate");this.featAggregate=new o(this.agentIdentifier,this.aggregator,e),n(!0)}catch(e){(0,l.Z)("Downloading and initializing ".concat(this.featureName," failed..."),e),this.abortHandler?.(),n(!1)}};c.il?(0,f.b)((()=>o()),!0):o()}shouldImportAgg(r,n){return r!==e.D.sessionReplay||!1!==(0,t.Mt)(this.agentIdentifier,"session_trace.enabled")&&(!!n?.isNew||!!n?.state.sessionReplay)}}var g=i(7633),p=i(7894);class m extends h{static featureName=g.t9;constructor(r,n){let i=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if(super(r,n,g.t9,i),("undefined"==typeof PerformanceNavigationTiming||c.Tt)&&"undefined"!=typeof PerformanceTiming){const n=(0,t.OP)(r);n[g.Dz]=Math.max(Date.now()-n.offset,0),(0,f.K)((()=>n[g.qw]=Math.max((0,p.z)()-n[g.Dz],0))),(0,f.b)((()=>{const t=(0,p.z)();n[g.OJ]=Math.max(t-n[g.Dz],0),(0,s.p)("timing",["load",t],void 0,e.D.pageViewTiming,this.ee)}))}this.importAggregator()}}var v=i(1117),b=i(1284);class y extends v.w{constructor(e){super(e),this.aggregatedData={}}store(e,t,r,n,i){var o=this.getBucket(e,t,r,i);return o.metrics=function(e,t){t||(t={count:0});return t.count+=1,(0,b.D)(e,(function(e,r){t[e]=w(r,t[e])})),t}(n,o.metrics),o}merge(e,t,r,n,i){var o=this.getBucket(e,t,n,i);if(o.metrics){var a=o.metrics;a.count+=r.count,(0,b.D)(r,(function(e,t){if("count"!==e){var n=a[e],i=r[e];i&&!i.c?a[e]=w(i.t,n):a[e]=function(e,t){if(!t)return e;t.c||(t=x(t.t));return t.min=Math.min(e.min,t.min),t.max=Math.max(e.max,t.max),t.t+=e.t,t.sos+=e.sos,t.c+=e.c,t}(i,a[e])}}))}else o.metrics=r}storeMetric(e,t,r,n){var i=this.getBucket(e,t,r);return i.stats=w(n,i.stats),i}getBucket(e,t,r,n){this.aggregatedData[e]||(this.aggregatedData[e]={});var i=this.aggregatedData[e][t];return i||(i=this.aggregatedData[e][t]={params:r||{}},n&&(i.custom=n)),i}get(e,t){return t?this.aggregatedData[e]&&this.aggregatedData[e][t]:this.aggregatedData[e]}take(e){for(var t={},r="",n=!1,i=0;i t.max&&(t.max=e),e 2&&void 0!==arguments[2])||arguments[2];super(e,r,j.t,n),c.il&&((0,t.OP)(e).initHidden=Boolean("hidden"===document.visibilityState),(0,N.N)((()=>(0,s.p)("docHidden",[(0,p.z)()],void 0,j.t,this.ee)),!0),(0,O.bP)("pagehide",(()=>(0,s.p)("winPagehide",[(0,p.z)()],void 0,j.t,this.ee))),this.importAggregator())}}var P=i(3081);class C extends h{static featureName=P.t9;constructor(e,t){let r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];super(e,t,P.t9,r),this.importAggregator()}}var R,I=i(2210),k=i(1214),H=i(2177),L={};try{R=localStorage.getItem("__nr_flags").split(","),console&&"function"==typeof console.log&&(L.console=!0,-1!==R.indexOf("dev")&&(L.dev=!0),-1!==R.indexOf("nr_dev")&&(L.nrDev=!0))}catch(e){}function z(e){try{L.console&&z(e)}catch(e){}}L.nrDev&&H.ee.on("internal-error",(function(e){z(e.stack)})),L.dev&&H.ee.on("fn-err",(function(e,t,r){z(r.stack)})),L.dev&&(z("NR AGENT IN DEVELOPMENT MODE"),z("flags: "+(0,b.D)(L,(function(e,t){return e})).join(", ")));var M=i(6660);class B extends h{static featureName=M.t;constructor(r,n){let i=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];super(r,n,M.t,i),this.skipNext=0;try{this.removeOnAbort=new AbortController}catch(e){}const o=this;o.ee.on("fn-start",(function(e,t,r){o.abortHandler&&(o.skipNext+=1)})),o.ee.on("fn-err",(function(t,r,n){o.abortHandler&&!n[M.A]&&((0,I.X)(n,M.A,(function(){return!0})),this.thrown=!0,(0,s.p)("err",[n,(0,p.z)()],void 0,e.D.jserrors,o.ee))})),o.ee.on("fn-end",(function(){o.abortHandler&&!this.thrown&&o.skipNext>0&&(o.skipNext-=1)})),o.ee.on("internal-error",(function(t){(0,s.p)("ierr",[t,(0,p.z)(),!0],void 0,e.D.jserrors,o.ee)})),this.origOnerror=c._A.onerror,c._A.onerror=this.onerrorHandler.bind(this),c._A.addEventListener("unhandledrejection",(t=>{const r=function(e){let t="Unhandled Promise Rejection: ";if(e instanceof Error)try{return e.message=t+e.message,e}catch(t){return e}if(void 0===e)return new Error(t);try{return new Error(t+(0,D.P)(e))}catch(e){return new Error(t)}}(t.reason);(0,s.p)("err",[r,(0,p.z)(),!1,{unhandledPromiseRejection:1}],void 0,e.D.jserrors,this.ee)}),(0,O.m$)(!1,this.removeOnAbort?.signal)),(0,k.gy)(this.ee),(0,k.BV)(this.ee),(0,k.em)(this.ee),(0,t.OP)(r).xhrWrappable&&(0,k.Kf)(this.ee),this.abortHandler=this.#e,this.importAggregator()}#e(){this.removeOnAbort?.abort(),this.abortHandler=void 0}onerrorHandler(t,r,n,i,o){"function"==typeof this.origOnerror&&this.origOnerror(...arguments);try{this.skipNext?this.skipNext-=1:(0,s.p)("err",[o||new F(t,r,n),(0,p.z)()],void 0,e.D.jserrors,this.ee)}catch(t){try{(0,s.p)("ierr",[t,(0,p.z)(),!0],void 0,e.D.jserrors,this.ee)}catch(e){}}return!1}}function F(e,t,r){this.message=e||"Uncaught error with no additional information",this.sourceURL=t,this.line=r}let U=1;const q="nr@id";function G(e){const t=typeof e;return!e||"object"!==t&&"function"!==t?-1:e===c._A?0:(0,I.X)(e,q,(function(){return U++}))}function V(e){if("string"==typeof e&&e.length)return e.length;if("object"==typeof e){if("undefined"!=typeof ArrayBuffer&&e instanceof ArrayBuffer&&e.byteLength)return e.byteLength;if("undefined"!=typeof Blob&&e instanceof Blob&&e.size)return e.size;if(!("undefined"!=typeof FormData&&e instanceof FormData))try{return(0,D.P)(e).length}catch(e){return}}}var X=i(7243);class W{constructor(e){this.agentIdentifier=e,this.generateTracePayload=this.generateTracePayload.bind(this),this.shouldGenerateTrace=this.shouldGenerateTrace.bind(this)}generateTracePayload(e){if(!this.shouldGenerateTrace(e))return null;var r=(0,t.DL)(this.agentIdentifier);if(!r)return null;var n=(r.accountID||"").toString()||null,i=(r.agentID||"").toString()||null,o=(r.trustKey||"").toString()||null;if(!n||!i)return null;var a=(0,_.M)(),s=(0,_.Ht)(),c=Date.now(),u={spanId:a,traceId:s,timestamp:c};return(e.sameOrigin||this.isAllowedOrigin(e)&&this.useTraceContextHeadersForCors())&&(u.traceContextParentHeader=this.generateTraceContextParentHeader(a,s),u.traceContextStateHeader=this.generateTraceContextStateHeader(a,c,n,i,o)),(e.sameOrigin&&!this.excludeNewrelicHeader()||!e.sameOrigin&&this.isAllowedOrigin(e)&&this.useNewrelicHeaderForCors())&&(u.newrelicHeader=this.generateTraceHeader(a,s,c,n,i,o)),u}generateTraceContextParentHeader(e,t){return"00-"+t+"-"+e+"-01"}generateTraceContextStateHeader(e,t,r,n,i){return i+"@nr=0-1-"+r+"-"+n+"-"+e+"----"+t}generateTraceHeader(e,t,r,n,i,o){if(!("function"==typeof c._A?.btoa))return null;var a={v:[0,1],d:{ty:"Browser",ac:n,ap:i,id:e,tr:t,ti:r}};return o&&n!==o&&(a.d.tk=o),btoa((0,D.P)(a))}shouldGenerateTrace(e){return this.isDtEnabled()&&this.isAllowedOrigin(e)}isAllowedOrigin(e){var r=!1,n={};if((0,t.Mt)(this.agentIdentifier,"distributed_tracing")&&(n=(0,t.P_)(this.agentIdentifier).distributed_tracing),e.sameOrigin)r=!0;else if(n.allowed_origins instanceof Array)for(var i=0;i 2&&void 0!==arguments[2])||arguments[2];super(r,n,Z.t,i),(0,t.OP)(r).xhrWrappable&&(this.dt=new W(r),this.handler=(e,t,r,n)=>(0,s.p)(e,t,r,n,this.ee),(0,k.u5)(this.ee),(0,k.Kf)(this.ee),function(r,n,i,o){function a(e){var t=this;t.totalCbs=0,t.called=0,t.cbTime=0,t.end=E,t.ended=!1,t.xhrGuids={},t.lastSize=null,t.loadCaptureCalled=!1,t.params=this.params||{},t.metrics=this.metrics||{},e.addEventListener("load",(function(r){_(t,e)}),(0,O.m$)(!1)),c.IF||e.addEventListener("progress",(function(e){t.lastSize=e.loaded}),(0,O.m$)(!1))}function s(e){this.params={method:e[0]},T(this,e[1]),this.metrics={}}function u(e,n){var i=(0,t.DL)(r);i.xpid&&this.sameOrigin&&n.setRequestHeader("X-NewRelic-ID",i.xpid);var a=o.generateTracePayload(this.parsedOrigin);if(a){var s=!1;a.newrelicHeader&&(n.setRequestHeader("newrelic",a.newrelicHeader),s=!0),a.traceContextParentHeader&&(n.setRequestHeader("traceparent",a.traceContextParentHeader),a.traceContextStateHeader&&n.setRequestHeader("tracestate",a.traceContextStateHeader),s=!0),s&&(this.dt=a)}}function d(e,t){var r=this.metrics,i=e[0],o=this;if(r&&i){var a=V(i);a&&(r.txSize=a)}this.startTime=(0,p.z)(),this.listener=function(e){try{"abort"!==e.type||o.loadCaptureCalled||(o.params.aborted=!0),("load"!==e.type||o.called===o.totalCbs&&(o.onloadCalled||"function"!=typeof t.onload)&&"function"==typeof o.end)&&o.end(t)}catch(e){try{n.emit("internal-error",[e])}catch(e){}}};for(var s=0;s 1?e[1]=i:e.push(i)}else e[0]&&e[0].headers&&s(e[0].headers,n)&&(this.dt=n);function s(e,t){var r=!1;return t.newrelicHeader&&(e.set("newrelic",t.newrelicHeader),r=!0),t.traceContextParentHeader&&(e.set("traceparent",t.traceContextParentHeader),t.traceContextStateHeader&&e.set("tracestate",t.traceContextStateHeader),r=!0),r}}function x(e,t){this.params={},this.metrics={},this.startTime=(0,p.z)(),this.dt=t,e.length>=1&&(this.target=e[0]),e.length>=2&&(this.opts=e[1]);var r,n=this.opts||{},i=this.target;"string"==typeof i?r=i:"object"==typeof i&&i instanceof Y?r=i.url:c._A?.URL&&"object"==typeof i&&i instanceof URL&&(r=i.href),T(this,r);var o=(""+(i&&i instanceof Y&&i.method||n.method||"GET")).toUpperCase();this.params.method=o,this.txSize=V(n.body)||0}function A(t,r){var n;this.endTime=(0,p.z)(),this.params||(this.params={}),this.params.status=r?r.status:0,"string"==typeof this.rxSize&&this.rxSize.length>0&&(n=+this.rxSize);var o={txSize:this.txSize,rxSize:n,duration:(0,p.z)()-this.startTime};i("xhr",[this.params,o,this.startTime,this.endTime,"fetch"],this,e.D.ajax)}function E(t){var r=this.params,n=this.metrics;if(!this.ended){this.ended=!0;for(var o=0;o 2&&void 0!==arguments[2])||arguments[2];super(e,t,we.t,r),this.importAggregator()}}new class{constructor(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:(0,_.ky)(16);c._A?(this.agentIdentifier=t,this.sharedAggregator=new y({agentIdentifier:this.agentIdentifier}),this.features={},this.desiredFeatures=new Set(e.features||[]),this.desiredFeatures.add(m),Object.assign(this,(0,a.j)(this.agentIdentifier,e,e.loaderType||"agent")),this.start()):(0,l.Z)("Failed to initial the agent. Could not determine the runtime environment.")}get config(){return{info:(0,t.C5)(this.agentIdentifier),init:(0,t.P_)(this.agentIdentifier),loader_config:(0,t.DL)(this.agentIdentifier),runtime:(0,t.OP)(this.agentIdentifier)}}start(){const t="features";try{const r=n(this.agentIdentifier),i=[...this.desiredFeatures];i.sort(((t,r)=>e.p[t.featureName]-e.p[r.featureName])),i.forEach((t=>{if(r[t.featureName]||t.featureName===e.D.pageViewEvent){const n=function(t){switch(t){case e.D.ajax:return[e.D.jserrors];case e.D.sessionTrace:return[e.D.ajax,e.D.pageViewEvent];case e.D.sessionReplay:return[e.D.sessionTrace];case e.D.pageViewTiming:return[e.D.pageViewEvent];default:return[]}}(t.featureName);n.every((e=>r[e]))||(0,l.Z)("".concat(t.featureName," is enabled but one or more dependent features has been disabled (").concat((0,D.P)(n),"). This may cause unintended consequences or missing data...")),this.features[t.featureName]=new t(this.agentIdentifier,this.sharedAggregator)}})),(0,T.Qy)(this.agentIdentifier,this.features,t)}catch(e){(0,l.Z)("Failed to initialize all enabled instrument classes (agent aborted) -",e);for(const e in this.features)this.features[e].abortHandler?.();const r=(0,T.fP)();return delete r.initializedAgents[this.agentIdentifier]?.api,delete r.initializedAgents[this.agentIdentifier]?.[t],delete this.sharedAggregator,r.ee?.abort(),delete r.ee?.get(this.agentIdentifier),!1}}}({features:[J,m,S,class extends h{static featureName=oe;constructor(t,r){if(super(t,r,oe,!(arguments.length>2&&void 0!==arguments[2])||arguments[2]),!c.il)return;const n=this.ee;let i;(0,k.QU)(n),this.eventsEE=(0,k.em)(n),this.eventsEE.on(se,(function(e,t){this.bstStart=(0,p.z)()})),this.eventsEE.on(ae,(function(t,r){(0,s.p)("bst",[t[0],r,this.bstStart,(0,p.z)()],void 0,e.D.sessionTrace,n)})),n.on(ce+ne,(function(e){this.time=(0,p.z)(),this.startPath=location.pathname+location.hash})),n.on(ce+ie,(function(t){(0,s.p)("bstHist",[location.pathname+location.hash,this.startPath,this.time],void 0,e.D.sessionTrace,n)}));try{i=new PerformanceObserver((t=>{const r=t.getEntries();(0,s.p)(te,[r],void 0,e.D.sessionTrace,n)})),i.observe({type:re,buffered:!0})}catch(e){}this.importAggregator({resourceObserver:i})}},C,xe,B,class extends h{static featureName=de;constructor(e,r){if(super(e,r,de,!(arguments.length>2&&void 0!==arguments[2])||arguments[2]),!c.il)return;if(!(0,t.OP)(e).xhrWrappable)return;try{this.removeOnAbort=new AbortController}catch(e){}let n,i=0;const o=this.ee.get("tracer"),a=(0,k._L)(this.ee),s=(0,k.Lg)(this.ee),u=(0,k.BV)(this.ee),d=(0,k.Kf)(this.ee),f=this.ee.get("events"),l=(0,k.u5)(this.ee),h=(0,k.QU)(this.ee),g=(0,k.Gm)(this.ee);function m(e,t){h.emit("newURL",[""+window.location,t])}function v(){i++,n=window.location.hash,this[ve]=(0,p.z)()}function b(){i--,window.location.hash!==n&&m(0,!0);var e=(0,p.z)();this[pe]=~~this[pe]+e-this[ve],this[ye]=e}function y(e,t){e.on(t,(function(){this[t]=(0,p.z)()}))}this.ee.on(ve,v),s.on(be,v),a.on(be,v),this.ee.on(ye,b),s.on(ge,b),a.on(ge,b),this.ee.buffer([ve,ye,"xhr-resolved"],this.featureName),f.buffer([ve],this.featureName),u.buffer(["setTimeout"+le,"clearTimeout"+fe,ve],this.featureName),d.buffer([ve,"new-xhr","send-xhr"+fe],this.featureName),l.buffer([me+fe,me+"-done",me+he+fe,me+he+le],this.featureName),h.buffer(["newURL"],this.featureName),g.buffer([ve],this.featureName),s.buffer(["propagate",be,ge,"executor-err","resolve"+fe],this.featureName),o.buffer([ve,"no-"+ve],this.featureName),a.buffer(["new-jsonp","cb-start","jsonp-error","jsonp-end"],this.featureName),y(l,me+fe),y(l,me+"-done"),y(a,"new-jsonp"),y(a,"jsonp-end"),y(a,"cb-start"),h.on("pushState-end",m),h.on("replaceState-end",m),window.addEventListener("hashchange",m,(0,O.m$)(!0,this.removeOnAbort?.signal)),window.addEventListener("load",m,(0,O.m$)(!0,this.removeOnAbort?.signal)),window.addEventListener("popstate",(function(){m(0,i>1)}),(0,O.m$)(!0,this.removeOnAbort?.signal)),this.abortHandler=this.#e,this.importAggregator()}#e(){this.removeOnAbort?.abort(),this.abortHandler=void 0}}],loaderType:"spa"})})(),window.NRBA=o})(); window.jQuery || document.write(' ') CKEDITOR_BASEPATH='https://f1000research.com/js/vendor/ckeditor/' window.reactTheme = 'research'; window.MathJax = { CommonHTML: { linebreaks: { automatic: true } }, 'HTML-CSS': { linebreaks: { automatic: true } }, SVG: { linebreaks: { automatic: true } }, AuthorInit: function() { MathJax.Hub.Register.MessageHook('End Process', function () { let timeout = false; // holder for timeout id const delay = 250; // delay after event is "complete" to run callback const reflowMath = function() { const dispFormulas = document.querySelectorAll('.disp-formula.panel'); if (!dispFormulas) { return; } for (const dispFormula of dispFormulas) { const child = dispFormula.querySelector('.MathJax_Preview').nextSibling.firstChild; const isMultiline = MathJax.Hub.getAllJax(dispFormula)[0].root.isMultiline; if (dispFormula.offsetWidth < child.offsetWidth || isMultiline) { MathJax.Hub.Queue(['Rerender', MathJax.Hub, dispFormula]); } } }; window.addEventListener('resize', function() { clearTimeout(timeout); // clear the timeout timeout = setTimeout(reflowMath, delay); // start timing for event "completion" }); }); }, }; if (window.location.hash == '#_=_'){ window.location = window.location.href.split('#')[0] } !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function() {n.callMethod? n.callMethod.apply(n,arguments):n.queue.push(arguments)} ;if(!f._fbq)f._fbq=n; n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0; t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window, document,'script','https://connect.facebook.net/en_US/fbevents.js'); fbq('init', '1641728616063202'); fbq('track', "PixelInitialized", {}); (function(h,o,t,j,a,r){ h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)}; h._hjSettings={hjid:2318163,hjsv:6}; a=o.getElementsByTagName('head')[0]; r=o.createElement('script');r.async=1; r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv; a.appendChild(r); })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv='); search file_upload Submit your research search menu close search Browse Gateways & Collections How to Publish Submit your Research My Submissions Article Guidelines Article Guidelines (New Versions) Open Data, Software and Code Guidelines Open Data and Accessible Source Materials Guidelines (HSS) Open Data, Software and Code Guidelines (PSE) Prepublication Checks Production Process Posters and Slides Guidelines Document Guidelines Article Processing Charges Peer Review Finding Article Reviewers About How it Works For Reviewers Our Advisors Policies Glossary FAQs For Developers Newsroom Contact My Research Submissions Content and Tracking Alerts My Details Sign In file_upload Submit your research { "@context": "https://schema.org", "@type": "ScholarlyArticle", "mainEntityOfPage": { "@type": "WebPage", "@id": "https://f1000research.com/articles/14-345" }, "headline": "The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak...", "datePublished": "2025-03-28T15:24:31", "dateModified": "2025-03-28T15:24:31", "author": [ { "@type": "Person", "name": "Ciara Judge" }, { "@type": "Person", "name": "Oliver Brady" }, { "@type": "Person", "name": "Sarah Hill" } ], "publisher": { "@type": "Organization", "name": "F1000Research", "logo": { "@type": "ImageObject", "url": "https://f1000research.com/img/AMP/F1000Research_image.png", "height": 480, "width": 60 } }, "image": { "@type": "ImageObject", "url": "https://f1000research.com/img/AMP/F1000Research_image.png", "height": 1200, "width": 150 }, "description": "The fields of epidemiology and viral phylodynamics share the ultimate goal of disease control, but concepts, methodologies and data employed by each differ in ways that confer complementary strengths and different areas of weakness. We recently introduced EpiFusion, a model for joint inference of outbreak characteristics using phylogenetic and case incidence data via particle filtering and demonstrated its usage to infer the effective reproduction number of simulated and real outbreaks. Here we provide a series of vignettes demonstrating data analysis using the EpiFusion Analysis Framework, consisting of the R package EpiFusionUtilities and the Java program in which the model is implemented, including an example using a new feature incorporated since EpiFusion’s last description: the option to provide a phylogenetic tree posterior as the phylogenetic data input to the program. By outlining these examples, we aim to improve the usability of our model, and promote workflow reproducibility and open research." } { "@context": "http://schema.org", "@type": "BreadcrumbList", "itemListElement": [ { "@type": "ListItem", "position": "1", "item": { "@id": "https://f1000research.com/", "name": "Home" } }, { "@type": "ListItem", "position": "2", "item": { "@id": "https://f1000research.com/browse/articles", "name": "Browse" } }, { "@type": "ListItem", "position": "3", "item": { "@id": "https://f1000research.com/articles/14-345", "name": "The EpiFusion Analysis Framework for joint phylodynamic and epidemiological..." } } ] } Home Browse The EpiFusion Analysis Framework for joint phylodynamic and epidemiological... ALL Metrics - Views Downloads Get PDF Get XML Cite How to cite this article Judge C, Brady O and Hill S. The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.12688/f1000research.162719.1 ) NOTE: If applicable, it is important to ensure the information in square brackets after the title is included in all citations of this article. Close Copy Citation Details Export Export Citation Sciwheel EndNote Ref. Manager Bibtex ProCite Sente EXPORT Select a format first Track Share ▬ ✚ Software Tool Article The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] Ciara Judge https://orcid.org/0000-0001-7923-9898 1-3 , Oliver Brady 1,2 , Sarah Hill 3 Ciara Judge https://orcid.org/0000-0001-7923-9898 1-3 , Oliver Brady 1,2 , Sarah Hill 3 PUBLISHED 28 Mar 2025 Author details Author details 1 Department of Infectious Disease Epidemiology and Dynamics, London School of Hygiene and Tropical Medicine Faculty of Epidemiology and Population Health, London, England, UK 2 Centre for Mathematical Modelling of Infectious Diseases, London School of Hygiene and Tropical Medicine, London, UK 3 Department of Pathobiology and Population Sciences, The Royal Veterinary College, Hatfield, England, UK Ciara Judge Roles: Conceptualization, Data Curation, Formal Analysis, Investigation, Methodology, Project Administration, Resources, Software, Validation, Visualization, Writing – Original Draft Preparation, Writing – Review & Editing Oliver Brady Roles: Conceptualization, Methodology, Project Administration, Supervision, Writing – Review & Editing Sarah Hill Roles: Conceptualization, Methodology, Project Administration, Supervision, Writing – Review & Editing OPEN PEER REVIEW DETAILS REVIEWER STATUS This article is included in the Bioinformatics gateway. Abstract The fields of epidemiology and viral phylodynamics share the ultimate goal of disease control, but concepts, methodologies and data employed by each differ in ways that confer complementary strengths and different areas of weakness. We recently introduced EpiFusion, a model for joint inference of outbreak characteristics using phylogenetic and case incidence data via particle filtering and demonstrated its usage to infer the effective reproduction number of simulated and real outbreaks. Here we provide a series of vignettes demonstrating data analysis using the EpiFusion Analysis Framework, consisting of the R package EpiFusionUtilities and the Java program in which the model is implemented, including an example using a new feature incorporated since EpiFusion’s last description: the option to provide a phylogenetic tree posterior as the phylogenetic data input to the program. By outlining these examples, we aim to improve the usability of our model, and promote workflow reproducibility and open research. READ ALL READ LESS Keywords research software, phylodynamics, epidemiology, joint inference, effective reproduction number, infectious disease, modelling, R, java, particle filtering Corresponding Author(s) Ciara Judge ( [email protected] ) Close Corresponding author: Ciara Judge Competing interests: No competing interests were disclosed. Grant information: CJ was supported by a Bloomsbury Colleges PhD Studentship and a National University of Ireland Denis Phelan Scholarship. OJB was supported by a UK Medical Research Council Career Development Award (MR/V031112/1). SCH was supported by a Sir Henry Wellcome Postdoctoral Fellowship from the Wellcome Trust (220414/Z/20/Z) [https://welcome.org/]. For the purpose of open access, the authors have applied a CC BY public copyright licence to any Author Accepted Manuscript version arising from this submission. The funders had no role in study design, data collection and analysis, decision to publish, or preparation of the manuscript. The funders had no role in study design, data collection and analysis, decision to publish, or preparation of the manuscript. Copyright: © 2025 Judge C et al . This is an open access article distributed under the terms of the Creative Commons Attribution License , which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. How to cite: Judge C, Brady O and Hill S. The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.12688/f1000research.162719.1 ) First published: 28 Mar 2025, 14 :345 ( https://doi.org/10.12688/f1000research.162719.1 ) Latest published: 28 Mar 2025, 14 :345 ( https://doi.org/10.12688/f1000research.162719.1 ) Introduction Implementing mathematical models of infectious disease outbreak characteristics using computational tools is an important aspect of public health research. 1 , 2 Tools are often distributed as packages or libraries in popular programming languages such as R, Python or Julia, or as standalone executable software. 3 – 6 Distributing and documenting workflows is important for the purposes of reproducible research, and to enable appropriate implementation of epidemiological models. 7 – 9 Previously we outlined EpiFusion, a novel method for modelling infectious disease outbreak characteristics conditioned on case incidence and phylogenetic trees using particle filtering, and validated its usage to infer infection trajectories and the effective reproduction number R t . 10 Here, we present the EpiFusion Analysis Framework, consisting of this EpiFusion model implemented as a Java command line tool, and the EpiFusionUtilities R package for data and output processing. EpiFusion consists of a ‘single process model, dual observation model’ particle filtering structure, where particles simulate outbreak trajectories and characteristics through time (process model) and are evaluated against phylodynamic and epidemiological data at resampling steps (observation models). EpiFusion uses case incidence and phylogenetic tree(s) as its data input but can also be run with either data type alone. The force of infection over time β is fit within the particle filter, and the recovery rate, case sampling rate, and genomic sequence sampling rate ( γ , ϕ and ψ respectively) are fit via Markov Chain Monte Carlo (MCMC). Further information including model theory and validation are provided in Ref. 10 . The EpiFusion model is packaged as a Java 11 command line tool and takes eXtensible Markup Language (XML) files 12 as input. In this article we provide instruction on implementing the recommended workflow (‘The EpiFusion Analysis Framework’) using an EpiFusion model. This includes data pre-processing, parameterisation, and eventual output parsing from within an R session, using the R package EpiFusionUtilities ( https://github.com/ciarajudge/EpiFusionUtilities ). We also demonstrate start-to-finish use cases for complete analysis of two outbreak datasets using EpiFusion and EpiFusionUtilities. Methods Operation EpiFusion is implemented as an open-source Java software (version 8 or later) and can be used as a command line tool or from within the EpiFusionUtilities R package ( https://ciarajudge.github.io/EpiFusionUtilities/ ). The latest stable version of the program is available for download under Releases on the project Github repository ( https://github.com/ciarajudge/EpiFusion/releases ). The source code for the latest development version is also available at this repository for users who wish to clone the repository and compile the program from source. EpiFusion can be called using its full file path, or from any working directory on your system by creating a symbolic link (Appendix 1). EpiFusionUtilities is implemented as an open source R 13 (version 3.5.0 or later) package and is available to install from Github using the R package devtools 14 : # install from Github devtools :: install_github ( "https://github.com/ciarajudge/EpiFusionUtilities" ) The key steps of the EpiFusion Framework workflow are outlined below in brief in the ‘Implementation’ section. Implementation The EpiFusion Analysis Framework consists of three main steps: (i) Data Processing and Parameterisation (ii) Running EpiFusion and (iii) Parsing and Interpreting the output ( Figure 1 ). All three steps can be carried out using EpiFusionUtilities , but it is also possible to manually assemble an XML input file and run EpiFusion from the command line using an executable jar file. Figure 1. Recommended EpiFusion Framework workflow, using EpiFusionUtilities functions (green) to prepare data and parse results. Data processing and parameterisation EpiFusion XML EpiFusion uses input files written in eXtensible Markup Language (XML) to provide all data and parameterisation to the program. These files contain Loggers , Data , Analysis , Model , Parameters and Priors sections where various aspects of the model and analysis may be specified ( Table 1 ). A full breakdown of the options available within each section is included in the Supplementary Information (Appendix 2). Table 1. Main sections of EpiFusion XML parameter file structure. XML section Description Loggers Provides detail on the program output, including specifying the file path of the output folder that should be created, and the frequency at which the program both logs the state of the MCMC to the output files and prints to the console. Data Provides the case incidence data and/or a phylogenetic tree or trees. These can be supplied either directly within the XML document or by providing full file paths to files containing the data) Analysis Parameterises the method for fitting the infectivity parameter beta - this is the daily probability per infectious individual of infecting another individual. Model Allows further customisation of the EpiFusion model structure. Currently, this only includes specification of the epidemiological observation model. Parameters Specifies many assorted parameters for the model, for example number of MCMC steps per chain, number of MCMC chains, and number of particles in the particle filter. Priors Prior distribution specification for parameters to be fit via particle MCMC. A range of distribution options are available, including: Normal, Truncated Normal, Poisson, Uniform, Uniform Discrete, Beta and Fixed (if a parameter should be fixed to a specific value and not inferred via MCMC). Assembling parameter XML files EpiFusion XML files may either be populated manually using templates available at the EpiFusion Github repository under examples, or created using a number of functions in the EpiFusionUtilities package. The first step of processing case incidence or tree data for EpiFusion input is to select an ‘index date’. This date should equate approximately to the ‘date of origin’ of the outbreak under consideration, i.e. the suspected date of the first infection/importation to the geographical or demographic system under study (day ‘0’). The index date should fall before any birth events (internal nodes / branching events) in the tree or observed epidemiological cases. This date is provided to the processing functions to enable the case and incidence data to be rooted in numerical time units. All trajectory samples will assume that the outbreak originated with one individual becoming infected on the index date. All times in the EpiFusion input and output will be in relation to this date and measured in days. index_date <- as.Date ( "2024-01-01" ) If there is uncertainty in the date of origin of the outbreak we recommend setting the index date to earlier than the estimated date. The resulting trajectories will likely demonstrate high uncertainty during the earliest days of the outbreak, until the point of the time series at which some data becomes available. To prepare a tree or posterior set of trees for EpiFusion, pass an S3 phylo or multiPhylo object in R to the prepare_epifusion_tree () function (we recommend any standard phylogenetics R package to manipulate these objects 15 , 16 ). This function processes a phylogenetic tree (or trees) and writes to a file, which you can specify in the arguments of the function (the default is ‘./processedtree.tree’). It is also necessary to pass the date of the last sample in the tree(s). This function adds node and leaf labels to the tree string that correspond to their time in days after the index date. prepare_epifusion_tree (tree, index_date, last_sequence_date, "Data/Processed/processed_fixed_tree.tree" ) To generate an EpiFusion XML file from within an R session, the generate_epifusion_XML () function may be used. This function populates a template XML file (included with the EpiFusionUtilities package) with the phylogenetic and/or case incidence data, and has default settings for parameters and priors which can also be changed by providing new values in the arguments of the function. For example below, we pass a case incidence data frame (consisting of two columns: a Date column named Date , with a numeric column Cases consisting of the number of cases reported on the corresponding date) and tree to the function. We also specify that we will sample from the MCMC chain every 100 steps, set our output folder path to output_files , and adjust the number of particles in the particle filter to 300. This creates a file in our working directory, epifusion_input.xml , which is ready to pass to EpiFusion. logger_information <- list ( fileBase = "output_files" , logEvery = 100 ) parameters_to_adjust <- list ( numParticles = 300 ) generate_epifusion_XML ( tree = "Data/Processed/processed_fixed_tree.tree" , case_incidence = case_incidence, index_date = index_date, loggers = logger_information, parameters = parameters_to_adjust, xml_filepath = "epifusion_input.xml" ) We include guidance on parameterisation and setting reasonable parameters and priors in the Supplementary Information alongside our more detailed description of EpiFusion XML (Appendix 2). Running EpiFusion EpiFusion can be run directly from the command line by calling an executable Java Archive (JAR) file using the following syntax. Here EpiFusion.jar is the file path to the executable file (i.e. in this example, the file is present in the working directory) and epifusion_input.xml is the file path to the parameter XML file (also present in the working directory for this example): java -jar EpiFusion.jar epifusion_input.xml Alternatively, it is possible to run EpiFusion from inside an R session with the EpiFusionUtilities function run_epifusion() . An installation of Java is still required. run_epifusion ( "epifusion_input.xml" ) Interpreting output EpiFusion creates a directory within the working directory that corresponds to the file path of the fileBase parameter in your EpiFusion xml file. For each MCMC chain, EpiFusion will create the following output files: • betas : .csv file where each row is a daily trajectory of infectivity β sampled from the MCMC • trajectories: .csv file where each row is a daily trajectory sampled from the MCMC of the number of individuals infected over time • params: .txt file where each column is an MCMC parameter, and each row is an MCMC sample • likelihoods: .txt file of the posterior likelihoods calculated at each MCMC step • acceptance: .txt file where each line logs the acceptance rate of steps between MCMC samples • completed: .txt file where each line logs if the particle filter step was completed or quit due to particle depletion • cuminfections: .txt file where each row is a trajectory of cumulative infections per day sampled from the MCMC • positivetests (only for combined or epi-only analyses): .csv file where each row is simulated case incidence by the model which was compared to the observed case incidence. This is provided at the same resolution as the observed case incidence, i.e. there will be one column per case incidence data point. EpiFusion will also save a copy of the parameter file used to the output folder, to record which parameters were used, and a file called ‘timings.txt’ with the runtime in nanoseconds. It is possible to process this raw output manually, but EpiFusionUtilities provides a number of functions to do this from within R. The following functions load the raw output into an R object, plot the likelihood trace for each MCMC chain to enable inspection to decide what proportion of samples from each chain to discard as burn-in, and finally extract the posterior samples from each chain with a given proportion discarded and combine them into a single posterior while assessing convergence. To select an appropriate burn-in proportion, we recommend inspecting the likelihood and parameter trace plots to assess the point at which samples along the x-axis form a stationary distribution randomly sampled from the same region of the y-axis. 17 It is also possible to test multiple extractions extract_posterior_epifusion() with different burn-in proportions, and inspect the gelman-rubin statistics of the parameters, which indicate convergence if below 1.015. 18 raw_output <- load_raw_epifusion ( "output_files/" ) plot_likelihood_trace (raw_output) full_posterior <- extract_posterior_epifusion (raw_output, 0.1 ) Below we demonstrate the implementation of this workflow using the EpiFusion executable and EpiFusionUtilities to analyse data from a small simulated outbreak. Use cases Description of the simulated datasets We demonstrate three analyses on two simulated outbreak datasets ( Figures 2 , 3 ). First we address a simple outbreak that lasts approximately three months with constant sampling effort that captures a single epidemic peak (‘baseline’). In the subsection ‘Full Framework Workflow’ we will model this outbreak using case incidence data in conjunction with a fixed time-scaled phylogenetic tree. Next, in ‘Phylogenetic Uncertainty’ we will model the same outbreak whilst examining the effect of phylogenetic uncertainty by using a tree posterior generated using a BEAST analysis of genomic samples simulated from the outbreak. Finally, in ‘Introducing Rate Changes’, we examine an outbreak with similar transmission dynamics but where initial minimal sampling of cases and sequences is followed by a sharp increase in the sampling rate on February 5 th 2024, and demonstrate how to parameterise this in an EpiFusion model. This example attempts to capture the challenges that often accompany modelling real-world outbreaks, where circumstances may evolve as an outbreak progresses (e.g. changes in case definitions affecting sampling rates, or upscaling of PCR diagnostics in response to an emerging infectious disease). Figure 2. Data from the baseline outbreak simulated using ReMaster and BEAST 2.7.3. The dataset contains both a summary phylogenetic tree (top) and tree posterior samples (middle), and weekly case incidence (orange). Figure 3. Data from outbreak with a step-change increase in sampling simulated using ReMaster. To generate the data, outbreak trajectories, and resulting weekly case incidence and a transmission tree of cases were simulated using ReMaster. 19 To give a simulated phylogenetic tree of ‘sequenced samples’ from the outbreak the transmission trees were downsampled, as typically only a small proportion of cases are sequenced in even heavily sampled outbreak settings. 20 , 21 For the baseline outbreak genomic sequences were simulated in R from this phylogenetic tree using the function simSeq() from the R package phangorn. 16 These sequences were used to generate a tree posterior using BEAST 2.7.3 22 with a Birth Death Skyline model, 23 under a strict clock and JC69 substitution model. The date of origin of each outbreak was arbitrarily chosen as January 1st 2024 and the case data and tree leaves were labelled accordingly. The final resulting data inputs for analysis in EpiFusion consisted of a file with a fixed time-scaled phylogenetic tree, a tree posterior file generated from sequences simulated from the outbreak, and a csv file with dated counts of weekly incidence. These raw data files are provided alongside the code below in the article repository ( https://github.com/ciarajudge/EpiFusion_Vignettes ). The data is also provided directly as part of the EpiFusionUtilities package, and can be loaded directly into R using the functions baseline_dataset and sampling_dataset . Full framework workflow In this example, we will use the baseline dataset to show a full workflow using the EpiFusion Framework: (i) data preparation (ii) prior and parameter specification (iii) running EpiFusion (iv) parsing and plotting output. Data preparation First we load and inspect the data for this example using the EpiFusionUtilities function baseline_dataset() . This function loads a data frame with weekly case incidence (formatted with two columns, Cases and Date, where Cases = the number of epidemiological cases reported on the corresponding Date), a time-scaled phylogenetic tree, and samples from a tree posterior (with 50% burn-in removed) from a BEAST analysis which we will use in a later section (Phylogenetic Uncertainty). baseline_dataset () print (baseline_caseincidence[ 1 : 5 ,]) ## Cases Date ## 1 0 2024-01-08 ## 2 6 2024-01-15 ## 3 83 2024-01-22 ## 4 285 2024-01-29 ## 5 401 2024-02-05 print (baseline_tree) ## ## Phylogenetic tree with 59 tips and 58 internal nodes. ## ## Tip labels: ## sequence1|2024-01-25, sequence2|2024-01-30, sequence3|2024-02-12, sequence4|2024-01-30, sequence5|2024-02-04, sequence6|2024-02-17, … ## Node labels: ## node_1, node_4, node_14, node_97, node_106, node_158, … ## ## Rooted; includes branch lengths. print (baseline_treeposterior) ## 200 phylogenetic trees Next we set two date objects: the ‘index date’, or the earliest date from which we will model the outbreak origin date, and the date of sampling of the last observed sequence from the dataset. Whilst for this example we know (through the simulation process) that the outbreak origin was the 1st of January 2024, it is good practice to set the index date to some time before the date that we suspect the outbreak began in the location represented by our case and phylogenetic data, to ensure the outbreak dynamics of are fully captured. index_date <- as.Date ( "2023-12-26" ) last_sequence <- as.Date ( "2024-03-10" ) To prepare the tree objects for EpiFusion we can use the prepare_epifusion_tree function from EpiFusionUtilities . This function processes the tree(s) for input to EpiFusion and writes them to the provided file path. In the case where a single summary tree is provided to this function it also returns the processed tree as an R phylo object, which here we reassign to the variable fixed_tree . fixed_tree <- prepare_epifusion_tree (baseline_tree, index_date, last_sequence, "Data/Processed/baseline_fixed_tree.tree" ) Definition of parameters We will create an EpiFusion XML file using the generate_epifusion_xml function from EpiFusionUtilities . This function populates the below XML template with our data and creates a new file. It is often necessary to adjust some other parameters from their default values in this template. This can be achieved by providing additional arguments to the generate_epifusion_xml function, which we demonstrate below. FILESTEM 10 INCIDENCE INCIDENCETIMES 0.5 0 looseformbeta null null false poisson false false 200 2000 8 4 0.05 7 true 1 false false TruncatedNormal 0.15 0.05 0.0 false TruncatedNormal 0.001 0.0005 0.0 false TruncatedNormal 0.02 0.01 0.0 false Uniform 0.3 0.8 false Uniform 0.001 0.05 We will generate an EpiFusion XML using the summary tree we prepared with the prepare_epifusion_tree function and our loaded case incidence data. First we will make lists of the various parts of the XML file we wish to override from the default. For example, the below code represents the loggers chunk in the default XML that details how often we sample from the MCMC (every 10 MCMC steps): FILESTEM 10 To override this, we will make a list in R that we will later pass to the loggers argument of the generate_epifusion_xml function to specify our output folder filepath as Results/fixed_tree and sample from the MCMC chain every 10 steps. We will also make a parameters list to adjust the number of MCMC steps, thus run each chain for longer to ensure we get a satisfactory number of samples from the posterior. We will reduce the number of particles in the particle filter to 100, as this is sufficient for a short, simple analysis, and will slightly reduce runtime. loggers <- list ( fileBase = "Results/baseline_fixed_tree" , logEvery = 10 ) parameters <- list ( numSteps = 10000 , numParticles = 100 ) We will also slightly adjust the prior for initialBeta , or β 0 (infectivity at the beginning of the time series) from the default settings. As the default prior for γ is a truncated normal distribution with mean 0.15 , standard deviation 0.05 and lower bound 0.0 , by setting the initial β value as 0.1 < β < 0.5 we indicate that the initial R t is approximately between 0.66 and 3.33 ( R t = β / γ , i.e. 0.1 / 0.15 = 0.66 and 0.5 / 0.15 = 3.33 ). priors <- list ( initialBeta = list ( stepchange = "false" , disttype = "Uniform" , min = 0.1 , max = 0.5 )) In this example we are happy with the other parameters in the default XML, so we can generate the XML file Data/EpiFusion_XMLs/fixed_tree_inputfile.xml with the following code: generate_epifusion_XML ( tree = "Data/Processed/baseline_fixed_tree.tree" , case_incidence = baseline_caseincidence, index_date = index_date, loggers = loggers, priors = priors, parameters = parameters, xml_filepath = "Data/EpiFusion_XMLs/baseline_fixed_tree_inputfile.xml" ) Running EpiFusion To run EpiFusion for the fixed tree example, we will use the run_epifusion function from EpiFusionUtilities to run the program within our R session: run_epifusion ( "Data/EpiFusion_XMLs/baseline_fixed_tree_inputfile.xml" ) On conclusion of its analysis, EpiFusion saves a timings.txt file to the output folder with the total runtime in nanoseconds, which we examine and convert to minutes below: runtime <- suppressWarnings ( read.table ( "Results/baseline_fixed_tree/timings.txt" )[ 1 , 1 ]) / 6e10 paste0 ( "Runtime: " ,runtime, " minutes" ) ## [1] "Runtime: 10.5715153277833 minutes" Parsing and plotting the output First we will use the load_raw_epifusion function to import the full raw results. This function automatically produces plots ( Figure 4 ) of the likelihood and parameter traces using the plot_likelihood_trace and plot_parameter_trace functions. This allows us to check for convergence and help to identify what proportion of each chain to discard as burn-in. raw_output_fixed <- load_raw_epifusion ( "Results/baseline_fixed_tree/" ) Figure 4. (a) Likelihood and trace plot from an EpiFusion analysis produced by the 'plot_likelihood_trace' function in EpiFusionUtilities. (b) Parameter trace plots from an EpiFusion analysis produced by the 'plot_parameter_trace' function in EpiFusionUtilities. Next we can discard the burn-in from each MCMC chain and combine all chains into a combined posterior using the extract_posterior_epifusion function which takes a raw EpiFusion object and the proportion of each chain to discard as burn-in as its arguments. By default, the function returns means and Highest Posterior Density (HPD) intervals for the trajectories and parameters fitted by EpiFusion, however by specifying include_samples = TRUE we also instruct the function to return the actual posterior samples (minus burn-in) for inspection. This greatly increases the memory used by the posterior output object in your R environment, so is recommended for initial inspection of your results but not for downstream tasks such as loading posteriors from many analyses for plotting. parsed_output_fixed <- extract_posterior_epifusion (raw_output_fixed, 0.2 , include_samples = TRUE ) str (parsed_output_fixed, max.level = 2 ) ## List of 5 ## $ infection_trajectories : List of 4 ## ..$ mean_infection_trajectory : Named num [1:113] 0 1.22 1.54 1.73 1.96 … ## .. ..- attr(*, "names")= chr [1:113] "T_0" "T_1" "T_2" "T_3" … ## ..$ median_infection_trajectory : Named num [1:113] 0 1 1 1 2 2 2 2 5 6 … ## .. ..- attr(*, "names")= chr [1:113] "T_0" "T_1" "T_2" "T_3" … ## ..$ infection_trajectory_hpdintervals : List of 3 ## ..$ infection_trajectory_samples :'data.frame': 3208 obs. of 113 variables: ## $ rt_trajectories : List of 4 ## ..$ mean_rt_trajectory : Named num [1:113] 2.09 2.14 2.18 2.25 2.32 … ## .. ..- attr(*, "names")= chr [1:113] "T_0" "T_1" "T_2" "T_3" … ## ..$ median_rt_trajectory : Named num [1:113] 2.13 2.16 2.2 2.24 2.32 … ## .. ..- attr(*, "names")= chr [1:113] "T_0" "T_1" "T_2" "T_3" … ## ..$ rt_trajectory_hpdintervals : List of 3 ## ..$ rt_trajectory_samples :'data.frame': 3208 obs. of 113 variables: ## $ parameters :List of 5 ## ..$ gamma :List of 3 ## ..$ psi :List of 3 ## ..$ phi :List of 3 ## ..$ betaJitter :List of 3 ## ..$ initialBeta:List of 3 ## $ fitted_epi_cases : List of 4 ## ..$ mean_fitted_epi_cases : Named num [1:15] 0.251 12.306 84.751 297.153 412.487 … ## .. ..- attr(*, "names")= chr [1:15] "T_0" "T_1" "T_2" "T_3" … ## ..$ median_fitted_epi_cases : Named num [1:15] 0 12 84 296 412 233 109 51 23 10 … ## .. ..- attr(*, "names")= chr [1:15] "T_0" "T_1" "T_2" "T_3" … ## ..$ fitted_epi_cases_hpdintervals : List of 3 ## ..$ fitted_epi_cases_samples :'data.frame': 3208 obs. of 15 variables: ## $ cumulative_infections :List of 4 ## ..$ mean_cuminfection_trajectory : Named num [1:113] 0 0.219 0.542 0.961 1.44 … ## .. ..- attr(*, "names")= chr [1:113] "T_0" "T_1" "T_2" "T_3" … ## ..$ median_cuminfection_trajectory : Named num [1:113] 0 0 0 1 1 2 2 3 6 9 … ## .. ..- attr(*, "names")= chr [1:113] "T_0" "T_1" "T_2" "T_3" … ## ..$ cuminfection_trajectory_hpdintervals : List of 3 ## ..$ cuminfection_trajectory_samples :'data.frame': 3208 obs. of 113 variables: The extracted posterior object from the extract_posterior_epifusion function contains mean and HPD intervals of increasing width for infection, R t , cumulative infection and fitted epidemiological case trajectories. The trajectory_table function can parse these into a convenient table structured to be suitable for plotting with ggplot2 . This table is structured with a Time column for each day in the analysis, and Mean and upper and lower HPD interval (0.95, 0.88 and 0.66) columns for each trajectory type (infection, R t , cumulative infections). traj_table <- trajectory_table (parsed_output_fixed, index_date) colnames (traj_table) ## [1] "Time" "Mean_Infected" ## [3] "Lower95_Infected" "Upper95_Infected" ## [5] "Lower88_Infected" "Upper88_Infected" ## [7] "Lower66_Infected" "Upper66_Infected" ## [9] "Mean_Rt" "Lower95_Rt" ## [11] "Upper95_Rt" "Lower88_Rt" ## [13] "Upper88_Rt" "Lower66_Rt" ## [15] "Upper66_Rt" "Mean_CumulativeInfections" ## [17] "Lower95_CumulativeInfections" "Upper95_CumulativeInfections" ## [19] "Lower88_CumulativeInfections" "Upper88_CumulativeInfections" ## [21] "Lower66_CumulativeInfections" "Upper66_CumulativeInfections" #Show the first 5 columns and 3 rows of the traj_table knitr :: kable ( head (traj_table[, 1 : 5 ], n = 3 )) Time Mean_Infected Lower95_Infected Upper95_Infected Lower88_Infected 2023-12-26 0.000000 0 0 0 2023-12-27 1.218828 1 2 1 2023-12-28 1.542394 1 3 1 It is possible use this table with ggplot functions to plot and inspect the inferred trajectories. However we also provide a function, plot_trajectories that takes the trajectory table as input and automatically plots all three trajectory types ( Figure 5 ). plot_trajectories (traj_table) Figure 5. Infection, Rt and cumulative infection trajectories plotted by the EpiFusionUtilities function ‘plot_trajectories’. The plot_trajectories function also takes additional arguments to allow more customisation. For example, it is possible to provide a specific trajectory type to plot using the type argument, and specify bespoke plot colours using the plot_colours argument. Here we will plot only the R t trajectories in a specified colour (pink) ( Figure 6 ). plot_trajectories (traj_table, type = "rt" , plot_colours = "pink" ) Figure 6. Inferred R(t) trajectories using a combined EpiFusion model and a fixed tree, plotted with the EpiFusionUtilities function ‘plot_trajectories’. As this was a combined analysis that has used case incidence data, it is possible to examine the fit of the case incidence simulated within the model to the provided data. We already have the case incidence data loaded from the data preparation stage, so we can add the mean and HPD intervals of the fit to the existing table ( Figure 7 ). epi_data_and_fit_table % mutate ( Stat = "Observed Cases" ) %>% full_join ( data.frame ( Date = baseline_caseincidence $ Date, Stat = "Fitted Cases" , Cases = parsed_output_fixed $ fitted_epi_cases $ median_fitted_epi_cases, Lower95_Cases = parsed_output_fixed $ fitted_epi_cases $ fitted_epi_cases_hpdintervals $ HPD0 .95 $ Lower, Upper95_Cases = parsed_output_fixed $ fitted_epi_cases $ fitted_epi_cases_hpdintervals $ HPD0 .95 $ Upper )) %>% mutate ( Stat = factor (Stat, levels = c ( "Observed Cases" , "Fitted Cases" ))) ## Joining with ‘by = join_by(Cases, Date, Stat)’ ggplot (epi_data_and_fit_table, aes ( x = Date)) + geom_bar ( aes ( y = Cases, fill = Stat), stat = "identity" , position = "dodge" , col = NA , alpha = 0.7 ) + scale_fill_manual ( name = "" , values = c ( "#e95b0d" , "grey" )) + geom_errorbar ( aes ( ymin = Lower95_Cases, ymax = Upper95_Cases, col = Stat), position = "dodge" , show.legend = F) + scale_color_manual ( values = c ( NA , "black" )) + lshtm_theme () Figure 7. Fit of observed epidemiological cases to simulated cases by the EpiFusion model, plotted with ggplot2. Observed epidemiological cases are shown by the grey bars, with their corresponding fitted cases from EpiFusion shown to their right by the blue bars. The error bars for the fitted case incidence correspond to bounds of the 0.95 HPD interval. Finally we can examine the posteriors of the MCMC parameters. The posterior extraction process uses the R package stable .GR to perform gelman-rubin convergence tests on each parameter, and estimate the effective sample sizes of each. If the gelman-rubin statistic is less than 1.015 this indicates MCMC convergence. 18 If the MCMC has not converged it may be necessary to run each chain for longer. print (parsed_output_fixed $ parameters $ gamma $ rhat) ## [1] 1.001274 print (parsed_output_fixed $ parameters $ gamma $ ess) ## [1] 1052 We can also view the posterior density of a parameter by plotting the samples from the MCMC, which we can access from the posterior object due to setting include_samples = TRUE when we extracted the posterior earlier using extract_epifusion_posterior ( Figure 8 ). ggplot ( data = data.frame ( Gamma = parsed_output_fixed $ parameters $ gamma $ samples), aes ( x = Gamma)) + geom_density ( fill = "#01454f" , alpha = 0.3 ) + lshtm_theme () Figure 8. Posterior density of the gamma recovery/removal parameter, plotted using ggplot2. Phylogenetic uncertainty In the previous example we modelled the baseline outbreak dataset using a fixed time-scaled phylogenetic tree as the phylodynamic data source. However, in a real outbreak setting there is often uncertainty about the evolutionary relationships and hence the tree sturcture (phylogenetic uncertainty). Bayesian tree inference approaches such as BEAST 22 , 24 attempt to approximate the true tree by sampling trees from a posterior set obtained through MCMC, often yielding thousands of plausible tree structures under the provided data and model. A single maximum clade credibility tree can be summarised from this ‘tree posterior’ and was used in EpiFusion using workflow specified above. It is valuable, however, to assess how uncertainty in the tree structure may affect epidemiological parameters inferred through EpiFusion. Currently, this can be explored by using a tree posterior as the data input into EpiFusion, and sampling a unique tree from the posterior for use with each MCMC chain. Below we demonstrate this approach by once more modelling the baseline outbreak dataset, but this time using the tree posterior as the phylodynamic data source. Prepare data and parameters and run EpiFusion To prepare the tree posterior (which was already loaded into our environment when we used the baseline_dataset() function) we once again use the prepare_epifusion_tree function. This function will recognise that a tree posterior has been passed, and will write the processed trees to a file without returning anything to your R session. prepare_epifusion_tree (baseline_treeposterior, index_date, last_sequence, "Data/Processed/baseline_processed_tree_posterior.tree" ) Next we will generate the XML file for the analysis using the tree posterior. We again specify adjustments to the loggers chunk, specifying our desired output folder name and how often to sample from the MCMC and print to console. We will also increase the number of MCMC chains to 50, which, in conjunction with passing a tree posterior to EpiFusion, will instruct the model to run 50 chains, each using a different tree sampled at random from the tree posterior. This analysis will therefore take longer. loggers <- list ( fileBase = "Results/baseline_tree_posterior" , logEvery = 5 )parameters <- list ( numChains = 50 ) Similarly to the fixed tree example, we will adjust some of the default priors. As before, we will set the initial infectivity β 0 to between 0.1 and 0.5 . We will also narrow slightly narrow some priors using their inferred values as estimated from our previous example on the same dataset, in order to help the efficiency of the MCMC sampling process due to the extra number of chains we are running. priors <- list ( initialBeta = list ( stepchange = "false" , disttype = "Uniform" , min = 0.1 , max = 0.5 ), betaJitter = list ( stepchange = "false" , disttype = "Uniform" , min = 0.005 , max = 0.05 ), phi = list ( stepchange = "false" , disttype = "TruncatedNormal" , lowerbound = 0.0 , mean = 0.02 , standarddev = 0.005 )) Finally we generate an XML file using these parameters and priors for input into EpiFusion and run it: generate_epifusion_XML ( tree = "Data/Processed/baseline_processed_tree_posterior.tree" , case_incidence = baseline_caseincidence, index_date = index_date, loggers = loggers, parameters = parameters, priors = priors, xml_filepath = "Data/EpiFusion_XMLs/tree_posterior_inputfile.xml" ) run_epifusion ( "Data/EpiFusion_XMLs/tree_posterior_inputfile.xml" ) Inspecting each chain To examine the results of the model using the tree posterior we will again load the raw results with load_raw_epifusion . This time we will set suppress_plots to true . raw_phylouncertainty <- load_raw_epifusion ( "Results/baseline_tree_posterior/" , suppress_plots = TRUE ) To examine the effect the inclusion of the tree posterior has on the analysis, we can use another EpiFusionUtilities function plot_chainwise_trajectories . This function operates similarly to the plot_trajectories function, but separates the trajectories by chain for inspection, while discarding a proportion of the trajectories of each chain for burn-in. This allows us to see how the sampled tree, which differs between each chain, affects the inferred trajectories ( Figure 9 ). Here we can see that most of the chains converge on a similar set of trajectories to our fixed tree analysis, but some chains (and thus, some sampled trees) suggest other trajectory possibilities. plot_chainwise_trajectories (raw_phylouncertainty, 0.2 ) ## [1] "WARNING: Chain 1 got stuck, with an acceptance rate of 0.0." ## [1] "WARNING: Chain 34 got stuck, with an acceptance rate of 0.0." ## [1] "WARNING: Chain 50 got stuck, with an acceptance rate of 0.0." Figure 9. Inferred infection, R t and cumulative infection trajectories plotted using the ‘plot_chainwise_trajectories’ function of EpiFusionUtilities. In this plot we see a further capability of the plot_chainwise_trajectories function. MCMC chains that have become ‘stuck’ i.e. enter a state space where they do not accept any further MCMC steps and have an acceptance rate of 0% are plotted with dotted lines, to enable users to identify and discard them when extracting the posterior using the discard_chains argument of the extract_posterior_epifusion function. When we extract the posterior from our raw output object (while discarding the ‘stuck’ chains), the chains will be combined and this uncertainty will be represented in our posterior estimates. To further understand this uncertainty we will extract the posterior sample using the extract_posterior_epifusion function and again create a trajectory table using the trajectory_table function. Using this table, and our trajectory table from the fixed tree analysis, we can use ggplot2 to plot the trajectories from both analyses to demonstrate the effect of the phylogenetic uncertainty on the estimates ( Figure 10 ). The tree posterior approach is characterised by a widening of the HPD intervals around the mean fitted infection trajectory, due to the phylogenetic uncertainty. posterior_phylouncertainty <- extract_posterior_epifusion (raw_phylouncertainty, 0.3 , discard_chains = c ( 1 , 34 , 50 )) phylouncertainty_trajtable % mutate ( Approach = "Tree Posterior" ) combined_trajtable % mutate ( Approach = "Fixed Tree" ) %>% rbind (phylouncertainty_trajtable) ggplot (combined_trajtable, aes ( x = Time, col = Approach, fill = Approach)) + geom_line ( aes ( y = Mean_Infected)) + geom_ribbon ( aes ( ymin = Lower95_Infected, ymax = Upper95_Infected), col = NA , alpha = 0.2 ) + geom_ribbon ( aes ( ymin = Lower88_Infected, ymax = Upper88_Infected), col = NA , alpha = 0.2 ) + geom_ribbon ( aes ( ymin = Lower66_Infected, ymax = Upper66_Infected), col = NA , alpha = 0.2 ) + lshtm_theme () + labs ( y = "Individuals Infected" ) + facet_wrap ( ~ Approach, ncol = 1 ) Figure 10. Inferred infection trajectories from EpiFusion analyses using a fixed tree (red) vs a tree posterior (blue). This approach to combining chains sampled under different phylogenetic trees to form unified posteriors should be carefully employed. For the purposes of demonstration here we sample 50 trees in unique chains, however to adequately approximate the full tree posterior it is advised to conduct more samples. Further, if there is significant disparity in the inferred trajectories from different chains (i.e. under different trees), we recommend reexamining the tree posterior to check for overt phylodynamic uncertainty in your tree data and considering whether employing EpiFusion is suitable with highly uncertain phylogenies. Introducing rate changes While our previous examples with the baseline dataset describe an outbreak with constant sampling throughout, real life scenarios are often more complicated as the rates that govern our model, β , γ , ϕ and ψ vary over time. β is allowed to vary over time by default and is fit in the particle filter, but below we will address a common scenario where rates of sampling cases and genomes ( ϕ and ψ ) increase sharply at a given time point. For example, this occurred during the Brazilian Zika outbreak in 2015, where sampling sharply increased following the introduction of widespread PCR testing. 25 Data preparation We can load the data for this example using the EpiFusionUtilities function sampling_dataset() . We will use the same index date for this analysis as previously, but for this dataset the last sequence in the tree was sampled on March 17th, so we will adjust the ‘last_sequence’ date accordingly. As in our other examples, we prepare our tree data for EpiFusion using the prepare_epifusion_tree function. sampling_dataset () print (sampling_caseincidence[ 1 : 5 ,]) print (sampling_tree) last_sequence <- as.Date ( "2024-03-17" ) sampling_fixed_tree <- prepare_epifusion_tree (sampling_tree, index_date, last_sequence, "Data/Processed/sampling_fixed_tree.tree" ) Advanced parameterisation: Time variant prior distributions In this example we wish to parameterise the step-increase in sampling on February 5th in our model. We will do this by setting a ‘time variant prior’ for case sampling rate phi when we generate the XML file, and using the ‘paired psi’ feature ( Supplementary Information Appendix 3 ) to pair the genomic sampling rate psi to the case sampling rate. Previously in the EpiFusion input files, the phi block in the prior section consisted of the following XML code: false TruncatedNormal 0.02 0.01 0.0 A phi parameter with a step change is adjusted to look like this: true FixedParameter 35 TruncatedNormal 0.002 0.0001 0.0 TruncatedNormal 0.025 0.005 0.0 The key differences here include the setting of the stepchange parameter to true, and the introduction of two new sub-nodes, changetimes and distribs, that contain the prior distribution details for the times of the rate changes in days from the index date (changetimes), and the rates themselves ( distribs ). For a rate with n change points, there must be n + 1 distributions in distribs and n distributions in changetimes. These distributions are provided in tags with the format xn. While these adjustments can be made manually, it is also possible to parameterise this through the priors argument of generate_epifusion_xml using nested lists. First we will make a list of the phi changetimes (in this example there is only one). In this scenario we ‘know’ the date of the step change in sampling - February 5th, 41 days after our index date - so we will provide it as a fixed parameter. However it is feasible to infer this change, if desired, by providing any discrete non-fixed prior distribution for this parameter. phi_changetimes <- list ( x0 = list ( disttype = "FixedParameter" , value = 41 )) Next we will provide prior distributions for phi before and after the provided change time in the distribs . phi_distribs <- list ( x0 = list ( disttype = "TruncatedNormal" , mean = 0.005 , standarddev = 0.002 , lowerbound = 0.0 ), x1 = list ( disttype = "TruncatedNormal" , mean = 0.05 , standarddev = 0.02 , lowerbound = 0.0 )) The list structure we introduce below using the changetimes and distribs we have created mirrors the structure of the XML chunk. phi_prior <- list ( stepchange = "true" , changetime = phi_changetimes, distribs = phi_distribs) We can then feed this to the priors argument when we generate the XML file. We also will set pairedPsi to true in the parameters, and provide an empty pairedPsi in the priors. This specifies that psi is not to be fit by MCMC, and the genomic sampling rate psi is calculated as a proportion of the case sampling rate using the proportion of genomic sequences to cases in the data. Further information on this process is available in the Supplementary Information. generate_epifusion_XML ( tree = "Data/Processed/sampling_fixed_tree.tree" , case_incidence = sampling_caseincidence, index_date = index_date, loggers = list ( fileBase = "Results/sampling_step_change" , logEvery = 5 ), parameters = list ( pairedPsi = "true" , numSteps = 10000 ), priors = list ( phi = phi_prior, pairedPsi = "" ), xml_filepath = "Data/EpiFusion_XMLs/sampling_fixed_tree_inputfile.xml" ) run_epifusion ( "Data/EpiFusion_XMLs/sampling_fixed_tree_inputfile.xml" ) Pairing psi with phi in this way is optional; here we couple the rates as we know they should change at the same time. It is also possible to parameterise these separately, e.g. an increase in sequencing without a corresponding increase in case sampling. Parsing results To complete our analysis we will load our results using the load_raw_epifusion function once more, and inspect the parameter trace. Here we will suppress the automatically created plots, and specifically plot the parameter trace of interest (the time varying parameters) using the plot_parameter_trace function, but changing the default type from all to timevar ( Figure 11 ). raw_sampling <- load_raw_epifusion ( "Results/sampling_step_change/" , suppress_plots = TRUE ) plot_parameter_trace (raw_sampling, type = "timevar" ) Figure 11. Parameter traces from an EpiFusion analysis with a case sampling rate ( phi ) step change. Here the output from plot_parameter_trace looks slightly different to previous versions (e.g. Figure 4 ). The function automatically recognises the presence of parameters that vary over time, and plots their piecewise constant values (y-axis) across time (x-axis) in step graphs. This allows the inferred value over time to be intuitively understood from the plot. The lines are coloured by their sample index on a continuous gradient, making visible the values to which the each chain has converged (light blue). Here we see that despite each chain initiating at different values, the initial and final sampling rates across each chain converge to approximately the same values. This is shown by the light blue (later MCMC samples) lines occurring at the same y-axis value in each chain trace plot for the phi parameter. The parsing and plotting process for the rest of the results from this analysis follows the same steps as the other vignettes included in this article. Conclusions and Discussion The EpiFusion Analysis Framework is a novel workflow for implementing the EpiFusion joint epidemiological and phylodynamic inference model using the Java implementation of the model and the R package EpiFusionUtilities. This workflow is generalisable, utilising common R objects for data formatting ( data.frame and phylo or multiPhylo objects) and parameterisation (list objects). We detail the full analysis workflow here, including a new feature introduced since EpiFusion’s first description: introduction of the ability to explore the effect phylogenetic uncertainty by providing a tree posterior as data. Use of this approach is recommended for outbreaks where a time-scaled phylogenetic tree and case incidence data is available, and the desired result is continuous (to a daily resolution) models of pertinent outbreak trajectories such as R t and infections over time. The data sampled should arise from the same ‘outbreak system’; specifically the genomic sequences used to build the tree and the case data should be sampled from the same approximate geographic location, time period, and population. If a time-scaled phylogenetic tree is not already assembled, this may be generated from established phylodynamic tree estimation approaches such as BEAST 22 or Nextstrain. 26 The program runs efficiently for even very large trees, but run-time increases with the length of the time series under investigation, 10 accordingly we currently do not recommend EpiFusion for analyses of time periods of longer than five years. In these instances, other programs such as EpiNow2 27 (case incidence data only) or TimTam 28 , 29 (both genomic and case incidence data), written in R and Java (BEAST Framework) respectively, may be more appropriate. The documentation of reproducible analysis workflows, particularly for new tools, is essential for open research. 7 – 9 Providing efficient pipelines with corresponding instructions enables researchers to build on previous work to address empirical research in an efficient way, which can be of great importance during outbreak settings which are often time sensitive. 30 In the three vignettes described we provide examples of standard EpiFusion parameterisation, however there are many advanced options available to users to customise their analysis. These include capabilities for composite (non-parametric) prior distributions ( Supplementary Information Appendix 4) , multiple epidemiological observation model options ( Supplementary Information Appendix 2, ‘Model’ ), multiple options for fitting β t ( Supplementary Information Appendix 5 ), and buffer zones for rate step-changes ( Supplementary Information Appendix 6 ). Exploration of the effect of phylogenetic uncertainty is now incorporated in the program through allowing the use of a time-rooted phylogenetic tree posterior (from a software such as BEAST) to be used as data within the model. This new feature is an implementation rather than theoretical advancement: For each unique MCMC chain, a new tree is randomly sampled from this posterior and used as the tree data in the model. The resulting posteriors can subsequently be examined and combined by the user with post-hoc EpiFusionUtilities functions. Incorporating phylogenetic uncertainty predictably led to increased uncertainty in the model estimates in the combined posterior. We encourage care in implementing this approach, and thoroughly examining the effect of using different trees on the model estimates using the plot_parameter_trace and plot_chainwise_trajectories functions. Further, for efficiency in our example shown above, we sample 50 trees, whereas it may be necessary to increase this number to adequately approximate the tree posterior. Going forward we aim to investigate other approaches for incorporating phylogenetic uncertainty in the model in a more comprehensive manner. To demonstrate the advanced parameterisation options of the framework, we addressed an outbreak with a step-increase in case and genomic sequence sampling rates. While this example featured a single change in the modelled rates, this infrastructure is very flexible and can be used to add significant complexity to the model according to the user requirements. The current framework is robust, but has some limitations. Traditionally R packages such as EpiFusionUtilities are distributed using the R package ecosystem CRAN. However, CRAN does not accept packages which contain binary executable code, 31 so it would not have been possible to distribute an EpiFusion release (an executable jar file) with the package and enable running the model from within R. A likely future step in the software development process may be to fully integrate the model into the EpiFusionUtilities R package using R/Rcpp, to allow more universal usage for all users including those without a extensive phylodynamic experience and would enable the package to be hosted on CRAN. The requirement to provide a user defined index date, or earliest possible date of outbreak origin, is a practical implementation compromise that may result in incorrect conclusions if the index date is not set early enough (i.e., if the index date is accidentally set after the true date of outbreak origin). Currently this can be overcome by setting the index date to a longer time period before the suspected origin of the outbreak, however the resulting estimates during the earlier periods of the modelled time series should be treated carefully and will typically display high levels of uncertainty. Future distributions of this framework will aim to allow inference without this truncation to a specified index date, or allow the index date to be inferred within the model. In conclusion, this article aims to outline a reproducible framework for utilising our novel joint inference model using a functional R package and a binary executable file. We show how different parameterisations and options for the analysis can be implemented, including how to introduce phylogenetic uncertainty through the provided tree data, and time-variant prior distributions. We hope that clearly outlining a use case of the framework will facilitate its implementation by researchers to investigate hypotheses of public health importance in the future. Ethics and consent Ethical approval and consent were not required. Data availability statement and software availability For the purposes of open research, we make available all code and data used in this manuscript on GitHub. Source code The source code for EpiFusion is written in Java and available on GitHub at the following repository: https://github.com/ciarajudge/EpiFusion . The source code is made available under the GNU General Public License (v3) ( https://www.gnu.org/licenses/gpl-3.0.en.html ). The source code at the time of this publication is archived on Zenodo: https://doi.org/10.5281/zenodo.14973874 32 The source code for EpiFusionUtilities is written in R and is available on GitHub at the following repository: https://github.com/ciarajudge/EpiFusionUtilities . The source code is made available under the GNU General Public License (v3) ( https://www.gnu.org/licenses/gpl-3.0.en.html ). The source code at the time of this publication is archived on Zenodo: https://doi.org/10.5281/zenodo.14973878 33 Underlying data and analysis code The simulated datasets used in this manuscript have been described in Section 4 and are provided in the Open Science Framework repository ‘EpiFusion Analysis Framework Software Article’: https://doi.org/10.17605/OSF.IO/7W43Y . 34 The project contains the following underlying data: • baseline_caseindicence.RDS: weekly case incidence from the baseline simulated dataset (R data.frame) • baseline_treeposterior.RDS: posterior of time-scaled phylogenetic trees from the baseline simulated outbreak dataset (R S3 multiPhylo object) • baseline_tree.RDS: time-scaled phylogenetic tree from the baseline simulated outbreak dataset (R S3 phylo object) • sampling_caseindicence.RDS: weekly case incidence from the step-change in sampling simulated dataset (R data.frame) • sampling_tree.RDS: time-scaled phylogenetic tree from the step-change in sampling simulated outbreak dataset (R S3 phylo object) Data are made available under the terms of the Creative Commons Attribution 4.0 International Licence (CC-BY 4.0) ( https://creativecommons.org/licenses/by/4.0/ ). The code used to produce all analyses and plots in this manuscript is available on GitHub at the following repository: https://github.com/ciarajudge/EpiFusion_Vignettes . This repository is archived on Zenodo: https://doi.org/10.5281/zenodo.14973889 . 35 Data and code are made available under the terms of the Creative Commons Attribution 4.0 International Licence (CC-BY 4.0) ( https://creativecommons.org/licenses/by/4.0/ ). Extended data The extended data in this manuscript (additional figures, tables and appendices) is available as a Supplementary Information file which is provided in the Open Science Framework repository ‘EpiFusion Analysis Framework Software Article’: https://doi.org/10.17605/OSF.IO/7W43Y . 34 The project contains the following extended data: • supplementary_information.pdf: PDF file containing Appendices 1-6 with supplementary information. Acknowledgements The authors would like to thank Timothy Vaughan, Sam Abbott, Tanja Stadler, Louis Du Plessis and Timothy Russell for their role in the development of the model method, David Hodgson for his guidance on R package development and implementation, and Clara Brigitta for testing the package and vignettes. Bibliography 1. Jenner AL, Aogo RA, Davis CL, et al. : Leveraging Computational Modeling to Understand Infectious Diseases. Curr. Pathobiol. Rep. Sep. 2020; 8 (4): 149–161. PubMed Abstract | Publisher Full Text | Free Full Text 2. Pokutnaya D, Childers B, Arcury-Quandt AE, et al. : An implementation framework to improve the transparency and reproducibility of computational models of infectious diseases. PLoS Comput. Biol. Mar. 2023; 19 (3): e1010856. PubMed Abstract | Publisher Full Text | Free Full Text 3. Jombart T, Rolland M, Gruson H: CRAN task view: epidemiology.Oct. 22, 2024. Reference Source 4. Julia Epi. http 5. Heslop DJ, Chughtai AA, Bui CM, et al. : Publicly available software tools for decision-makers during an emergent epidemicsystematic evaluation of utility and usability. Epidemics. 2017; 21 : 1–12. PubMed Abstract | Publisher Full Text 6. epirecipes: A cookbook of epidemiological models in R, Python, Julia (and more). http 7. Henderson AS, Hickson RI, Furlong M, et al. : Reproducibility of COVID-era infectious disease models. Epidemics. Mar. 2024; 46 : 100743. PubMed Abstract | Publisher Full Text 8. Sy KTL, White LF, Nichols BE: Reproducible Science Is Vital for a Stronger Evidence Base During the COVID-19 Pandemic. Geogr. Anal. Nov. 2021. PubMed Abstract | Publisher Full Text | Free Full Text 9. Jalali MS, DiGennaro C, Guitar A, et al. : Evolution and reproducibility of simulation modeling in epidemiology and health policy over half a century. Epidemiol. Rev. Dec. 2021; 43 (1): 166–175. PubMed Abstract | Publisher Full Text | Free Full Text 10. Judge C, et al. : EpiFusion: Joint inference of the effective reproduction number by integrating phylodynamic and epidemiological modelling with particle filtering. PLoS Comput. Biol. Nov. 2024; 20 (11): e1012528. PubMed Abstract | Publisher Full Text | Free Full Text 11. Java programming language. http 12. Lupp M: Extensible Markup Language. Shekhar S, Xiong H, editors. Boston, MA: Springer US; 2008; pp. 307–307. Publisher Full Text 13. R Core Team: R: A language and environment for statistical computing. Vienna, Austria: R Foundation for Statistical Computing; 2020. Reference Source 14. Wickham H, Hester J, Chang W, et al. : Devtools: Tools to make developing r packages easier. 2022. Reference Source 15. Paradis E, Schliep K: Ape 5.0: An environment for modern phylogenetics and evolutionary analyses in r. Bioinformatics. Feb. 2019; 35 (3): 526–528. PubMed Abstract | Publisher Full Text 16. Schliep KP: Phangorn: Phylogenetic analysis in r. Bioinformatics. 2011; 27 (4): 592–593. PubMed Abstract | Publisher Full Text | Free Full Text 17. Hamra G, MacLehose R, Richardson D: Markov chain monte carlo: An introduction for epidemiologists. Int. J. Epidemiol. Apr. 2013; 42 (2): 627–634. PubMed Abstract | Publisher Full Text | Free Full Text 18. Gelman A, Rubin DB: Inference from iterative simulation using multiple sequences. Stat. Sci. Nov. 1992; 7 (4): 457–472. Publisher Full Text 19. Vaughan TG: ReMASTER: Improved phylodynamic simulation for BEAST 2.7. bioRxiv. Oct. 2023. pp. 2023.10.09.561485–2023.10.09.561485. Publisher Full Text 20. Wohl S, Schaffner SF, Sabeti PC: Genomic analysis of viral outbreaks. Annu. Rev. Virol. 2016; 3 : 173–195. PubMed Abstract | Publisher Full Text | Free Full Text 21. Hill V, Ruis C, Bajaj S, et al. : Progress and challenges in virus genomic epidemiology. Trends Parasitol. 2021; 37 (12): 1038–1049. Publisher Full Text 22. Bouckaert R, et al. : BEAST 2.5: An advanced software platform for bayesian evolutionary analysis. PLoS Comput. Biol. 2019; 15 (4): e1006650–e1006650. PubMed Abstract | Publisher Full Text | Free Full Text 23. Stadler T, Kühnert D, Bonhoeffer S, et al. : Birth-death skyline plot reveals temporal changes of epidemic spread in HIV and hepatitis c virus (HCV). Proc. Natl. Acad. Sci. USA. 2013; 110 (1): 228–233. PubMed Abstract | Publisher Full Text | Free Full Text 24. Drummond AJ, Rambaut A: BEAST: Bayesian evolutionary analysis by sampling trees. BMC Evol. Biol. Nov. 2007; 7 (1): 214. PubMed Abstract | Publisher Full Text | Free Full Text 25. Brady OJ, et al. : The association between zika virus infection and microcephaly in brazil 20152017: An observational analysis of over 4 million births. PLoS Med. Mar. 2019; 16 (3): e1002755–e1002755. PubMed Abstract | Publisher Full Text | Free Full Text 26. Hadfield J, et al. : NextStrain: Real-time tracking of pathogen evolution. Bioinformatics. 2018; 34 (23): 4121–4123. PubMed Abstract | Publisher Full Text | Free Full Text 27. Abbott S, et al. : EpiNow2: Estimate real-time case counts and time-varying epidemiological parameters. 2024. Reference Source 28. Zarebski AE, du Plessis L , Parag KV, et al. : A computationally tractable birth-death model that combines phylogenetic and epidemiological data. PLoS Comput. Biol. 2022; 18 (2): e1009805. PubMed Abstract | Publisher Full Text | Free Full Text 29. Zarebski AE, Zwaans A, Gutierrez B, et al. : Estimating epidemic dynamics with genomic and time series data. medRxiv. Aug. 2023. pp. 2023.08.03.23293620–2023.08.03.23293620. Publisher Full Text 30. Kucharski AJ, Hodcroft EB, Kraemer MUG: Sharing, synthesis and sustainability of data analysis for epidemic preparedness in europe. Lancet Reg. Health Eur. Oct. 2021; 9 : 100215. PubMed Abstract | Publisher Full Text | Free Full Text 31. CRAN repository policy. http 32. Judge C: GitHub Repository, ciarajudge/EpiFusion: EpiFusionv1.0. Zenodo. 2025. Publisher Full Text 33. Judge C: GitHub Repository, ciarajudge/EpiFusionUtilities: EpiFusionv1.0.0. Zenodo. 2025. Publisher Full Text 34. Judge C: EpiFusion Analysis Framework Software Article. Dataset. 2025. Publisher Full Text 35. Judge C: GitHub Repository, ciarajudge/EpiFusion_Vignettes: F1000 Article Release. Zenodo. 2025. Publisher Full Text Comments on this article Comments (0) Version 1 VERSION 1 PUBLISHED 28 Mar 2025 ADD YOUR COMMENT Comment Author details Author details 1 Department of Infectious Disease Epidemiology and Dynamics, London School of Hygiene and Tropical Medicine Faculty of Epidemiology and Population Health, London, England, UK 2 Centre for Mathematical Modelling of Infectious Diseases, London School of Hygiene and Tropical Medicine, London, UK 3 Department of Pathobiology and Population Sciences, The Royal Veterinary College, Hatfield, England, UK Ciara Judge Roles: Conceptualization, Data Curation, Formal Analysis, Investigation, Methodology, Project Administration, Resources, Software, Validation, Visualization, Writing – Original Draft Preparation, Writing – Review & Editing Oliver Brady Roles: Conceptualization, Methodology, Project Administration, Supervision, Writing – Review & Editing Sarah Hill Roles: Conceptualization, Methodology, Project Administration, Supervision, Writing – Review & Editing Competing interests No competing interests were disclosed. Grant information CJ was supported by a Bloomsbury Colleges PhD Studentship and a National University of Ireland Denis Phelan Scholarship. OJB was supported by a UK Medical Research Council Career Development Award (MR/V031112/1). SCH was supported by a Sir Henry Wellcome Postdoctoral Fellowship from the Wellcome Trust (220414/Z/20/Z) [https://welcome.org/]. For the purpose of open access, the authors have applied a CC BY public copyright licence to any Author Accepted Manuscript version arising from this submission. The funders had no role in study design, data collection and analysis, decision to publish, or preparation of the manuscript. The funders had no role in study design, data collection and analysis, decision to publish, or preparation of the manuscript. Article Versions (1) version 1 Published: 28 Mar 2025, 14:345 https://doi.org/10.12688/f1000research.162719.1 Copyright © 2025 Judge C et al . This is an open access article distributed under the terms of the Creative Commons Attribution License , which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. Download Export To Sciwheel Bibtex EndNote ProCite Ref. Manager (RIS) Sente metrics Views Downloads F1000Research - - PubMed Central info_outline Data from PMC are received and updated monthly. - - Citations open_in_new 0 open_in_new 0 open_in_new SEE MORE DETAILS CITE how to cite this article Judge C, Brady O and Hill S. The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.12688/f1000research.162719.1 ) NOTE: If applicable, it is important to ensure the information in square brackets after the title is included in all citations of this article. COPY CITATION DETAILS track receive updates on this article Track an article to receive email alerts on any updates to this article. TRACK THIS ARTICLE Share Open Peer Review Current Reviewer Status: ? Key to Reviewer Statuses VIEW HIDE Approved The paper is scientifically sound in its current form and only minor, if any, improvements are suggested Approved with reservations A number of small changes, sometimes more significant revisions are required to address specific details and improve the papers academic merit. Not approved Fundamental flaws in the paper seriously undermine the findings and conclusions Version 1 VERSION 1 PUBLISHED 28 Mar 2025 Views 0 Cite How to cite this report: Featherstone LA. Reviewer Report For: The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.5256/f1000research.178965.r376911 ) The direct URL for this report is: https://f1000research.com/articles/14-345/v1#referee-response-376911 NOTE: it is important to ensure the information in square brackets after the title is included in this citation. Close Copy Citation Details Reviewer Report 03 Jun 2025 Leo A Featherstone , The University of Melbourne, Melbourne, Victoria, Australia Approved VIEWS 0 https://doi.org/10.5256/f1000research.178965.r376911 Overview Judge et al. present the EpiFusionUtilities R package. It provides an R interface for the EpiFusion program implemented in java, but with the key extension to accommodating phylogenetic uncertainty. This is a valuable contribution both in providing a ... Continue reading READ ALL Overview Judge et al. present the EpiFusionUtilities R package. It provides an R interface for the EpiFusion program implemented in java, but with the key extension to accommodating phylogenetic uncertainty. This is a valuable contribution both in providing a means to address phylogenetic uncertainty and by improving accesibility through an R interface. The examples provided are comprehensive and explained with good clarity. Some points for clarification P6: " It is also possible to test multiple extractions extract_posterior_epifusion() with different burn-in proportions, and inspect the gelman-rubin statistics of the parameters, which indicate convergence if below 1.015 " It would be helpful to outline how the Gelman-Rubin statistic relates to effective sample size (ESS), which will be more familiar to BEAST users who appear to be part of the intended user base here. Could users equivalently read output into the `coda` R package to calculate ESS for MCMC traces? P16: " ...It is valuable, however, to assess how uncertainty in the tree structure may affect epidemiological parameters inferred through EpiFusion. Currently, this can be explored by using a tree posterior as the data input into EpiFusion, and sampling a unique tree from the posterior for use with each MCMC chain... " Does the input strictly have to be a posterior distribution of trees? I gather the program is useful for comparing the effects of any set of candidate trees in a multiPhylo object, which I think is a really useful feature! P22 Figure 11 : I'm concerned that any patterns in colour could be obscured by overlapping of states. Would you consider faceting by sub-groupings of samples or perhaps implementing some version of a parallel coordinates plot to better tease apart states? Here's an example: (https://beastiary.wytamma.com/plots/parallel-coordinates/) from the beastiary [1] program. P22: " The program runs efficiently for even very large trees, but run-time increases with the length of the time series under investigation,10 accordingly we currently do not recommend EpiFusion for analyses of time periods of longer than five years " It sounds like the number of data points in the time series is the issue rather than the total timespan. If so, can you provide an upper limit on the workable number of rows in the time series? E.g. I assume 5 years of monthly or weekly time series data would be better than daily? P23: " Currently this can be overcome by setting the index date to a longer time period before the suspected origin of the outbreak, however the resulting estimates during the earlier periods of the modelled time series should be treated carefully and will typically display high levels of uncertainty. Future distributions of this framework will aim to allow inference without this truncation to a specified index date, or allow the index date to be inferred within the model. " Please elaborate on how overly conservative index dates affect inference. Is it correct to intuit that having very old index date would deflate estimates of transmission rate? How would this interact with the 5-year time limit you proposed above? P17: Typo: " We will also narrow slightly narrow some priors " Is the rationale for developing the new software tool clearly explained? Yes Is the description of the software tool technically sound? Yes Are sufficient details of the code, methods and analysis (if applicable) provided to allow replication of the software development and its use by others? Yes Is sufficient information provided to allow interpretation of the expected output datasets and any results generated using the tool? Yes Are the conclusions about the tool and its performance adequately supported by the findings presented in the article? Yes References 1. Wirth W, Duchene S: Real-Time and Remote MCMC Trace Inspection with Beastiary. Molecular Biology and Evolution . 2022; 39 (5). Publisher Full Text Competing Interests: No competing interests were disclosed. Reviewer Expertise: Phylodynamics; Phylogenetics I confirm that I have read this submission and believe that I have an appropriate level of expertise to confirm that it is of an acceptable scientific standard. Close READ LESS CITE CITE HOW TO CITE THIS REPORT Featherstone LA. Reviewer Report For: The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.5256/f1000research.178965.r376911 ) The direct URL for this report is: https://f1000research.com/articles/14-345/v1#referee-response-376911 NOTE: it is important to ensure the information in square brackets after the title is included in all citations of this article. COPY CITATION DETAILS Report a concern Respond or Comment COMMENT ON THIS REPORT Views 0 Cite How to cite this report: Guinat C. Reviewer Report For: The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.5256/f1000research.178965.r376910 ) The direct URL for this report is: https://f1000research.com/articles/14-345/v1#referee-response-376910 NOTE: it is important to ensure the information in square brackets after the title is included in this citation. Close Copy Citation Details Reviewer Report 15 May 2025 Claire Guinat , Interactions Hôtes-Agents Pathogènes (IHAP), Université de Toulouse, INRAE, Toulouse, France Approved with Reservations VIEWS 0 https://doi.org/10.5256/f1000research.178965.r376910 Overall comment This documentation is very relevant to facilitate the correct use of the EpiFusion tool and is essential for open research. However, the text and code should be harmonized/complemented by what is also presented in the online ... Continue reading READ ALL Overall comment This documentation is very relevant to facilitate the correct use of the EpiFusion tool and is essential for open research. However, the text and code should be harmonized/complemented by what is also presented in the online tutorial on the GitHub page. The first part, which I think aims to be more generic, is a bit confusing; it becomes clearer when we reach the applications. I ran the different parts of the code, which run smoothly. However, here are a few points that might improve the manuscript: I also went to https://github.com/ciarajudge/EpiFusion/tree/main/examples => What are the links between the three tutorials provided on GitHub and this paper? The connection is unclear. It would be helpful to integrate all sources of information or clarify their respective purposes to avoid fragmentation. Table 1 – About Data => Is the tree time-calibrated? Please clarify whether this refers to an MCC tree or a posterior sample of time-scalibrated trees. About Parameters => The term “parameters” usually refers to model parameters. Here, it appears to refer to inference parameters or hyperparameters. Please clarify this distinction. About Model => What are the available model options? The XML shows a Poisson model, but further explanation is needed on what each model represents (e.g., incidence process), and how to choose one over another. Add library(EpiFusionUtilities) after devtools::install_github(...) => This addition would improve clarity and ensure reproducibility for users unfamiliar with the package. Index_case If this date cannot be estimated and must be fixed, what are the implications? Could you clarify how users should handle uncertainty, perhaps by suggesting a sensitivity analysis? Also, is this date just an example or related to real data? “If there is uncertainty in the date of origin of the outbreak we recommend setting the index date to earlier than the estimated date.” => Please clarify what is meant by "estimated date"—is it based on genetic data, case reports, or another source? “To prepare a tree or posterior set of trees for EpiFusion” => The documentation should clarify whether trees must be time-calibrated. This is crucial for users preparing their data. prepare_epifusion_tree(...) => Are users expected to use the tree provided in the GitHub tutorial? Providing a simple MCC tree as an example would be helpful for learning purposes. “This function populates a template XML...” => It would help to list default parameter values and priors explicitly here. Also, clarify terminology: "priors" and "parameters" typically refer to biological model settings, whereas here they seem to relate to the inference framework (MCMC, particle filtering, etc.). CSV case format for incidence data => Please give an explicit description of the required format (e.g., columns, headers). You could refer to the full workflow tutorial but be explicit here too. generate_epifusion_XML(...) => The full workflow tutorial uses a different example and mentions priors, but it's unclear which parameters are being referred to. I recommend listing all adjustable priors (e.g., ψ, ϕ, betajitter) and defining them clearly. run_epifusion("epifusion_input.xml") => Could you include an estimate of run time or a way to monitor progress, similar to BEAST logs? This would help users plan their analyses. Output files (betas.csv, params.txt, acceptance.txt) => Clarify that params_chain0.csv is the output referenced as params.txt. Are these MCMC parameters or model parameters? Define what the “acceptance” file contains and how to interpret acceptance rates. “It is possible to process this raw output manually...” => Before visualizing outputs, users should be advised to assess convergence (e.g., trace plots, Gelman-Rubin statistics). Mention this step earlier in the process. Rt estimates => Where are the Rt estimates? Can users specify whether Rt is estimated from tree only, case data only, or combined? Clarifying this would be very useful. Use cases section => The term “Use cases” might be misleading, since “case” is already used for case incidence data. Perhaps “Applications” would be a clearer section title. “Finally, in ‘Introducing Rate Changes’” => Consider rewording as “Introducing sampling rate changes” to be more specific. Structured populations => Is it possible to use the method for structured populations and estimate different Rt values per subpopulation? Clarify whether this is supported or planned. “To generate the data...” using ReMaster.19 => Do we assume that all cases are reported? Clarify whether the incidence file reflects total or sampled incidence, since under-reporting is common in real-world outbreaks. “...csv file with dated counts of weekly incidence” => Does incidence have to be weekly? Could it be daily or in another time unit? Specify how to align tree and case data temporal scales. Methods vs. Use Cases => The “Use Cases” section is much clearer than the “Methods” section. Consider stating explicitly that the methods part is a generic overview and that detailed application examples follow. include_samples = TRUE => It is unclear what changes when this is set to TRUE. Does it apply burn-in and return a trimmed posterior sample? Please clarify the effect of this option. parsed_output_fixed If users want to compute their own summary statistics (e.g., medians), should they use the raw output after burn-in? Clarify the recommended procedure. “Finally we can examine the posteriors of the MCMC parameters...” => Introduce convergence checks (Gelman-Rubin, ESS) earlier in the workflow. Also, define acronyms like ESS and rhat, and explain what these values represent and how to interpret them. print(parsed_output_fixed$parameters$gamma$rhat) output => It’s not clear to beginners what this output means. Relate it clearly to the earlier explanation of convergence diagnostics. “However, in a real outbreak setting there is often uncertainty...” => Typo: "sturcture" should be "structure". “...sampled at random from the tree posterior...” => Please clarify: if multiple trees are sampled, does this represent a sensitivity analysis across tree uncertainty? The phrasing earlier in the document suggests that only one tree is used per run. “...run 50 chains, each using a different tree sampled...” => This is now clearer, thanks. It might help to emphasize that this is the way to explore tree uncertainty. Side question => I wonder why the authors of the original EpiFusion paper are not included in this manuscript? Their inclusion would make sense if the method is being described or re-implemented. Is the rationale for developing the new software tool clearly explained? Yes Is the description of the software tool technically sound? Yes Are sufficient details of the code, methods and analysis (if applicable) provided to allow replication of the software development and its use by others? Partly Is sufficient information provided to allow interpretation of the expected output datasets and any results generated using the tool? Partly Are the conclusions about the tool and its performance adequately supported by the findings presented in the article? Yes Competing Interests: No competing interests were disclosed. Reviewer Expertise: epidemiology, infectious diseases, transmission dynamics, phylodynamics I confirm that I have read this submission and believe that I have an appropriate level of expertise to confirm that it is of an acceptable scientific standard, however I have significant reservations, as outlined above. Close READ LESS CITE CITE HOW TO CITE THIS REPORT Guinat C. Reviewer Report For: The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.5256/f1000research.178965.r376910 ) The direct URL for this report is: https://f1000research.com/articles/14-345/v1#referee-response-376910 NOTE: it is important to ensure the information in square brackets after the title is included in all citations of this article. COPY CITATION DETAILS Report a concern Respond or Comment COMMENT ON THIS REPORT Views 0 Cite How to cite this report: Dhanasekaran V and Xie R. Reviewer Report For: The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.5256/f1000research.178965.r374093 ) The direct URL for this report is: https://f1000research.com/articles/14-345/v1#referee-response-374093 NOTE: it is important to ensure the information in square brackets after the title is included in this citation. Close Copy Citation Details Reviewer Report 07 May 2025 Vijaykrishna Dhanasekaran , The University of Hong Kong, Hong Kong, Hong Kong Ruopeng Xie , The University of Hong Kong, Hong Kong, Hong Kong Approved VIEWS 0 https://doi.org/10.5256/f1000research.178965.r374093 This manuscript provides a valuable practical extension of the EpiFusion framework, offering clear guidance for implementing joint phylodynamic-epidemiological analyses via the EpiFusionUtilities R package. The inclusion of vignettes and real-world outbreak case studies significantly enhances reproducibility and accessibility, bridging the ... Continue reading READ ALL This manuscript provides a valuable practical extension of the EpiFusion framework, offering clear guidance for implementing joint phylodynamic-epidemiological analyses via the EpiFusionUtilities R package. The inclusion of vignettes and real-world outbreak case studies significantly enhances reproducibility and accessibility, bridging the gap between theoretical models and applied public health research. Below are suggestions to further strengthen the work: 1. The emphasis on reproducibility is a major strength. To ensure seamless replication across systems, the authors could: · Encapsulate dependencies by providing Docker containers or platform-agnostic virtual environments (e.g., via renv). · Document software versions explicitly, including a sessionInfo() output, R/Java version requirements, and a requirements.txt file (or equivalent) to help users mirror the analysis environment. 2. While the focus on EpiFusionUtilities is appropriate, the manuscript would benefit from a comparative discussion of how EpiFusion complements or differs from established tools (e.g., BEAST, PhyDyn, Outbreaker2). A concise table or paragraph highlighting unique features (e.g., joint modeling of genomic and epidemiological data) and limitations (e.g., computational scalability) would help users assess its suitability for their needs. 3. The manuscript includes analyses of two outbreak datasets. Briefly justify their selection and relevance to contemporary public health challenges to strengthen the narrative. A more explicit discussion of the framework’s assumptions and limitations would improve its practical utility: · The model assumes a single infected individual (single index) initiates the outbreak. Discuss its sensitivity to this assumption and whether the model can accommodate multiple introductions. · While the manuscript notes that phylogenetic uncertainty affects parameter estimation, it should also address how variation in tree-building methods (e.g., ML vs. Bayesian approaches) might propagate into epidemiological inferences. · Guidance on computational performance (e.g., runtime benchmarks for larger datasets or complex models) would help users gauge feasibility for their own work. Is the rationale for developing the new software tool clearly explained? Yes Is the description of the software tool technically sound? Yes Are sufficient details of the code, methods and analysis (if applicable) provided to allow replication of the software development and its use by others? Yes Is sufficient information provided to allow interpretation of the expected output datasets and any results generated using the tool? Yes Are the conclusions about the tool and its performance adequately supported by the findings presented in the article? Yes Competing Interests: No competing interests were disclosed. We confirm that we have read this submission and believe that we have an appropriate level of expertise to confirm that it is of an acceptable scientific standard. Close READ LESS CITE CITE HOW TO CITE THIS REPORT Dhanasekaran V and Xie R. Reviewer Report For: The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.5256/f1000research.178965.r374093 ) The direct URL for this report is: https://f1000research.com/articles/14-345/v1#referee-response-374093 NOTE: it is important to ensure the information in square brackets after the title is included in all citations of this article. COPY CITATION DETAILS Report a concern Respond or Comment COMMENT ON THIS REPORT Comments on this article Comments (0) Version 1 VERSION 1 PUBLISHED 28 Mar 2025 ADD YOUR COMMENT Comment keyboard_arrow_left keyboard_arrow_right Open Peer Review Reviewer Status info_outline Alongside their report, reviewers assign a status to the article: Approved The paper is scientifically sound in its current form and only minor, if any, improvements are suggested Approved with reservations A number of small changes, sometimes more significant revisions are required to address specific details and improve the papers academic merit. Not approved Fundamental flaws in the paper seriously undermine the findings and conclusions Reviewer Reports Invited Reviewers 1 2 3 Version 1 28 Mar 25 read read read Vijaykrishna Dhanasekaran , The University of Hong Kong, Hong Kong, Hong Kong Ruopeng Xie , The University of Hong Kong, Hong Kong, Hong Kong Claire Guinat , Interactions Hôtes-Agents Pathogènes (IHAP), Université de Toulouse, INRAE, Toulouse, France Leo A Featherstone , The University of Melbourne, Melbourne, Australia Comments on this article All Comments (0) Add a comment Sign up for content alerts Sign Up You are now signed up to receive this alert Browse by related subjects keyboard_arrow_left Back to all reports Reviewer Report 0 Views copyright © 2025 Featherstone L. This is an open access peer review report distributed under the terms of the Creative Commons Attribution License , which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. 03 Jun 2025 | for Version 1 Leo A Featherstone , The University of Melbourne, Melbourne, Victoria, Australia 0 Views copyright © 2025 Featherstone L. This is an open access peer review report distributed under the terms of the Creative Commons Attribution License , which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. format_quote Cite this report speaker_notes Responses (0) Approved info_outline Alongside their report, reviewers assign a status to the article: Approved The paper is scientifically sound in its current form and only minor, if any, improvements are suggested Approved with reservations A number of small changes, sometimes more significant revisions are required to address specific details and improve the papers academic merit. Not approved Fundamental flaws in the paper seriously undermine the findings and conclusions Overview Judge et al. present the EpiFusionUtilities R package. It provides an R interface for the EpiFusion program implemented in java, but with the key extension to accommodating phylogenetic uncertainty. This is a valuable contribution both in providing a means to address phylogenetic uncertainty and by improving accesibility through an R interface. The examples provided are comprehensive and explained with good clarity. Some points for clarification P6: " It is also possible to test multiple extractions extract_posterior_epifusion() with different burn-in proportions, and inspect the gelman-rubin statistics of the parameters, which indicate convergence if below 1.015 " It would be helpful to outline how the Gelman-Rubin statistic relates to effective sample size (ESS), which will be more familiar to BEAST users who appear to be part of the intended user base here. Could users equivalently read output into the `coda` R package to calculate ESS for MCMC traces? P16: " ...It is valuable, however, to assess how uncertainty in the tree structure may affect epidemiological parameters inferred through EpiFusion. Currently, this can be explored by using a tree posterior as the data input into EpiFusion, and sampling a unique tree from the posterior for use with each MCMC chain... " Does the input strictly have to be a posterior distribution of trees? I gather the program is useful for comparing the effects of any set of candidate trees in a multiPhylo object, which I think is a really useful feature! P22 Figure 11 : I'm concerned that any patterns in colour could be obscured by overlapping of states. Would you consider faceting by sub-groupings of samples or perhaps implementing some version of a parallel coordinates plot to better tease apart states? Here's an example: (https://beastiary.wytamma.com/plots/parallel-coordinates/) from the beastiary [1] program. P22: " The program runs efficiently for even very large trees, but run-time increases with the length of the time series under investigation,10 accordingly we currently do not recommend EpiFusion for analyses of time periods of longer than five years " It sounds like the number of data points in the time series is the issue rather than the total timespan. If so, can you provide an upper limit on the workable number of rows in the time series? E.g. I assume 5 years of monthly or weekly time series data would be better than daily? P23: " Currently this can be overcome by setting the index date to a longer time period before the suspected origin of the outbreak, however the resulting estimates during the earlier periods of the modelled time series should be treated carefully and will typically display high levels of uncertainty. Future distributions of this framework will aim to allow inference without this truncation to a specified index date, or allow the index date to be inferred within the model. " Please elaborate on how overly conservative index dates affect inference. Is it correct to intuit that having very old index date would deflate estimates of transmission rate? How would this interact with the 5-year time limit you proposed above? P17: Typo: " We will also narrow slightly narrow some priors " Is the rationale for developing the new software tool clearly explained? Yes Is the description of the software tool technically sound? Yes Are sufficient details of the code, methods and analysis (if applicable) provided to allow replication of the software development and its use by others? Yes Is sufficient information provided to allow interpretation of the expected output datasets and any results generated using the tool? Yes Are the conclusions about the tool and its performance adequately supported by the findings presented in the article? Yes References 1. Wirth W, Duchene S: Real-Time and Remote MCMC Trace Inspection with Beastiary. Molecular Biology and Evolution . 2022; 39 (5). Publisher Full Text Competing Interests No competing interests were disclosed. Reviewer Expertise Phylodynamics; Phylogenetics I confirm that I have read this submission and believe that I have an appropriate level of expertise to confirm that it is of an acceptable scientific standard. reply Respond to this report Responses (0) Featherstone LA. Peer Review Report For: The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.5256/f1000research.178965.r376911) NOTE: it is important to ensure the information in square brackets after the title is included in this citation. The direct URL for this report is: https://f1000research.com/articles/14-345/v1#referee-response-376911 keyboard_arrow_left Back to all reports Reviewer Report 0 Views copyright © 2025 Guinat C. This is an open access peer review report distributed under the terms of the Creative Commons Attribution License , which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. 15 May 2025 | for Version 1 Claire Guinat , Interactions Hôtes-Agents Pathogènes (IHAP), Université de Toulouse, INRAE, Toulouse, France 0 Views copyright © 2025 Guinat C. This is an open access peer review report distributed under the terms of the Creative Commons Attribution License , which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. format_quote Cite this report speaker_notes Responses (0) Approved With Reservations info_outline Alongside their report, reviewers assign a status to the article: Approved The paper is scientifically sound in its current form and only minor, if any, improvements are suggested Approved with reservations A number of small changes, sometimes more significant revisions are required to address specific details and improve the papers academic merit. Not approved Fundamental flaws in the paper seriously undermine the findings and conclusions Overall comment This documentation is very relevant to facilitate the correct use of the EpiFusion tool and is essential for open research. However, the text and code should be harmonized/complemented by what is also presented in the online tutorial on the GitHub page. The first part, which I think aims to be more generic, is a bit confusing; it becomes clearer when we reach the applications. I ran the different parts of the code, which run smoothly. However, here are a few points that might improve the manuscript: I also went to https://github.com/ciarajudge/EpiFusion/tree/main/examples => What are the links between the three tutorials provided on GitHub and this paper? The connection is unclear. It would be helpful to integrate all sources of information or clarify their respective purposes to avoid fragmentation. Table 1 – About Data => Is the tree time-calibrated? Please clarify whether this refers to an MCC tree or a posterior sample of time-scalibrated trees. About Parameters => The term “parameters” usually refers to model parameters. Here, it appears to refer to inference parameters or hyperparameters. Please clarify this distinction. About Model => What are the available model options? The XML shows a Poisson model, but further explanation is needed on what each model represents (e.g., incidence process), and how to choose one over another. Add library(EpiFusionUtilities) after devtools::install_github(...) => This addition would improve clarity and ensure reproducibility for users unfamiliar with the package. Index_case If this date cannot be estimated and must be fixed, what are the implications? Could you clarify how users should handle uncertainty, perhaps by suggesting a sensitivity analysis? Also, is this date just an example or related to real data? “If there is uncertainty in the date of origin of the outbreak we recommend setting the index date to earlier than the estimated date.” => Please clarify what is meant by "estimated date"—is it based on genetic data, case reports, or another source? “To prepare a tree or posterior set of trees for EpiFusion” => The documentation should clarify whether trees must be time-calibrated. This is crucial for users preparing their data. prepare_epifusion_tree(...) => Are users expected to use the tree provided in the GitHub tutorial? Providing a simple MCC tree as an example would be helpful for learning purposes. “This function populates a template XML...” => It would help to list default parameter values and priors explicitly here. Also, clarify terminology: "priors" and "parameters" typically refer to biological model settings, whereas here they seem to relate to the inference framework (MCMC, particle filtering, etc.). CSV case format for incidence data => Please give an explicit description of the required format (e.g., columns, headers). You could refer to the full workflow tutorial but be explicit here too. generate_epifusion_XML(...) => The full workflow tutorial uses a different example and mentions priors, but it's unclear which parameters are being referred to. I recommend listing all adjustable priors (e.g., ψ, ϕ, betajitter) and defining them clearly. run_epifusion("epifusion_input.xml") => Could you include an estimate of run time or a way to monitor progress, similar to BEAST logs? This would help users plan their analyses. Output files (betas.csv, params.txt, acceptance.txt) => Clarify that params_chain0.csv is the output referenced as params.txt. Are these MCMC parameters or model parameters? Define what the “acceptance” file contains and how to interpret acceptance rates. “It is possible to process this raw output manually...” => Before visualizing outputs, users should be advised to assess convergence (e.g., trace plots, Gelman-Rubin statistics). Mention this step earlier in the process. Rt estimates => Where are the Rt estimates? Can users specify whether Rt is estimated from tree only, case data only, or combined? Clarifying this would be very useful. Use cases section => The term “Use cases” might be misleading, since “case” is already used for case incidence data. Perhaps “Applications” would be a clearer section title. “Finally, in ‘Introducing Rate Changes’” => Consider rewording as “Introducing sampling rate changes” to be more specific. Structured populations => Is it possible to use the method for structured populations and estimate different Rt values per subpopulation? Clarify whether this is supported or planned. “To generate the data...” using ReMaster.19 => Do we assume that all cases are reported? Clarify whether the incidence file reflects total or sampled incidence, since under-reporting is common in real-world outbreaks. “...csv file with dated counts of weekly incidence” => Does incidence have to be weekly? Could it be daily or in another time unit? Specify how to align tree and case data temporal scales. Methods vs. Use Cases => The “Use Cases” section is much clearer than the “Methods” section. Consider stating explicitly that the methods part is a generic overview and that detailed application examples follow. include_samples = TRUE => It is unclear what changes when this is set to TRUE. Does it apply burn-in and return a trimmed posterior sample? Please clarify the effect of this option. parsed_output_fixed If users want to compute their own summary statistics (e.g., medians), should they use the raw output after burn-in? Clarify the recommended procedure. “Finally we can examine the posteriors of the MCMC parameters...” => Introduce convergence checks (Gelman-Rubin, ESS) earlier in the workflow. Also, define acronyms like ESS and rhat, and explain what these values represent and how to interpret them. print(parsed_output_fixed$parameters$gamma$rhat) output => It’s not clear to beginners what this output means. Relate it clearly to the earlier explanation of convergence diagnostics. “However, in a real outbreak setting there is often uncertainty...” => Typo: "sturcture" should be "structure". “...sampled at random from the tree posterior...” => Please clarify: if multiple trees are sampled, does this represent a sensitivity analysis across tree uncertainty? The phrasing earlier in the document suggests that only one tree is used per run. “...run 50 chains, each using a different tree sampled...” => This is now clearer, thanks. It might help to emphasize that this is the way to explore tree uncertainty. Side question => I wonder why the authors of the original EpiFusion paper are not included in this manuscript? Their inclusion would make sense if the method is being described or re-implemented. Is the rationale for developing the new software tool clearly explained? Yes Is the description of the software tool technically sound? Yes Are sufficient details of the code, methods and analysis (if applicable) provided to allow replication of the software development and its use by others? Partly Is sufficient information provided to allow interpretation of the expected output datasets and any results generated using the tool? Partly Are the conclusions about the tool and its performance adequately supported by the findings presented in the article? Yes Competing Interests No competing interests were disclosed. Reviewer Expertise epidemiology, infectious diseases, transmission dynamics, phylodynamics I confirm that I have read this submission and believe that I have an appropriate level of expertise to confirm that it is of an acceptable scientific standard, however I have significant reservations, as outlined above. reply Respond to this report Responses (0) Guinat C. Peer Review Report For: The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.5256/f1000research.178965.r376910) NOTE: it is important to ensure the information in square brackets after the title is included in this citation. The direct URL for this report is: https://f1000research.com/articles/14-345/v1#referee-response-376910 keyboard_arrow_left Back to all reports Reviewer Report 0 Views copyright © 2025 Dhanasekaran V et al. This is an open access peer review report distributed under the terms of the Creative Commons Attribution License , which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. 07 May 2025 | for Version 1 Vijaykrishna Dhanasekaran , The University of Hong Kong, Hong Kong, Hong Kong Ruopeng Xie , The University of Hong Kong, Hong Kong, Hong Kong 0 Views copyright © 2025 Dhanasekaran V et al. This is an open access peer review report distributed under the terms of the Creative Commons Attribution License , which permits unrestricted use, distribution, and reproduction in any medium, provided the original work is properly cited. format_quote Cite this report speaker_notes Responses (0) Approved info_outline Alongside their report, reviewers assign a status to the article: Approved The paper is scientifically sound in its current form and only minor, if any, improvements are suggested Approved with reservations A number of small changes, sometimes more significant revisions are required to address specific details and improve the papers academic merit. Not approved Fundamental flaws in the paper seriously undermine the findings and conclusions This manuscript provides a valuable practical extension of the EpiFusion framework, offering clear guidance for implementing joint phylodynamic-epidemiological analyses via the EpiFusionUtilities R package. The inclusion of vignettes and real-world outbreak case studies significantly enhances reproducibility and accessibility, bridging the gap between theoretical models and applied public health research. Below are suggestions to further strengthen the work: 1. The emphasis on reproducibility is a major strength. To ensure seamless replication across systems, the authors could: · Encapsulate dependencies by providing Docker containers or platform-agnostic virtual environments (e.g., via renv). · Document software versions explicitly, including a sessionInfo() output, R/Java version requirements, and a requirements.txt file (or equivalent) to help users mirror the analysis environment. 2. While the focus on EpiFusionUtilities is appropriate, the manuscript would benefit from a comparative discussion of how EpiFusion complements or differs from established tools (e.g., BEAST, PhyDyn, Outbreaker2). A concise table or paragraph highlighting unique features (e.g., joint modeling of genomic and epidemiological data) and limitations (e.g., computational scalability) would help users assess its suitability for their needs. 3. The manuscript includes analyses of two outbreak datasets. Briefly justify their selection and relevance to contemporary public health challenges to strengthen the narrative. A more explicit discussion of the framework’s assumptions and limitations would improve its practical utility: · The model assumes a single infected individual (single index) initiates the outbreak. Discuss its sensitivity to this assumption and whether the model can accommodate multiple introductions. · While the manuscript notes that phylogenetic uncertainty affects parameter estimation, it should also address how variation in tree-building methods (e.g., ML vs. Bayesian approaches) might propagate into epidemiological inferences. · Guidance on computational performance (e.g., runtime benchmarks for larger datasets or complex models) would help users gauge feasibility for their own work. Is the rationale for developing the new software tool clearly explained? Yes Is the description of the software tool technically sound? Yes Are sufficient details of the code, methods and analysis (if applicable) provided to allow replication of the software development and its use by others? Yes Is sufficient information provided to allow interpretation of the expected output datasets and any results generated using the tool? Yes Are the conclusions about the tool and its performance adequately supported by the findings presented in the article? Yes Competing Interests No competing interests were disclosed. We confirm that we have read this submission and believe that we have an appropriate level of expertise to confirm that it is of an acceptable scientific standard. reply Respond to this report Responses (0) Dhanasekaran V and Xie R. Peer Review Report For: The EpiFusion Analysis Framework for joint phylodynamic and epidemiological analysis of outbreak characteristics [version 1; peer review: 2 approved, 1 approved with reservations] . F1000Research 2025, 14 :345 ( https://doi.org/10.5256/f1000research.178965.r374093) NOTE: it is important to ensure the information in square brackets after the title is included in this citation. The direct URL for this report is: https://f1000research.com/articles/14-345/v1#referee-response-374093 Alongside their report, reviewers assign a status to the article: Approved - the paper is scientifically sound in its current form and only minor, if any, improvements are suggested Approved with reservations - A number of small changes, sometimes more significant revisions are required to address specific details and improve the papers academic merit. Not approved - fundamental flaws in the paper seriously undermine the findings and conclusions Adjust parameters to alter display View on desktop for interactive features Includes Interactive Elements View on desktop for interactive features Competing Interests Policy Provide sufficient details of any financial or non-financial competing interests to enable users to assess whether your comments might lead a reasonable person to question your impartiality. Consider the following examples, but note that this is not an exhaustive list: Examples of 'Non-Financial Competing Interests' Within the past 4 years, you have held joint grants, published or collaborated with any of the authors of the selected paper. You have a close personal relationship (e.g. parent, spouse, sibling, or domestic partner) with any of the authors. You are a close professional associate of any of the authors (e.g. scientific mentor, recent student). You work at the same institute as any of the authors. You hope/expect to benefit (e.g. favour or employment) as a result of your submission. You are an Editor for the journal in which the article is published. Examples of 'Financial Competing Interests' You expect to receive, or in the past 4 years have received, any of the following from any commercial organisation that may gain financially from your submission: a salary, fees, funding, reimbursements. You expect to receive, or in the past 4 years have received, shared grant support or other funding with any of the authors. You hold, or are currently applying for, any patents or significant stocks/shares relating to the subject matter of the paper you are commenting on. Stay Updated Sign up for content alerts and receive a weekly or monthly email with all newly published articles Register with F1000Research Already registered? Sign in Not now, thanks close PLEASE NOTE If you are an AUTHOR of this article, please check that you signed in with the account associated with this article otherwise we cannot automatically identify your role as an author and your comment will be labelled as a “User Comment”. If you are a REVIEWER of this article, please check that you have signed in with the account associated with this article and then go to your account to submit your report, please do not post your review here. If you do not have access to your original account, please contact us . All commenters must hold a formal affiliation as per our Policies . The information that you give us will be displayed next to your comment. User comments must be in English, comprehensible and relevant to the article under discussion. We reserve the right to remove any comments that we consider to be inappropriate, offensive or otherwise in breach of the User Comment Terms and Conditions . Commenters must not use a comment for personal attacks. When criticisms of the article are based on unpublished data, the data should be made available. I accept the User Comment Terms and Conditions Please confirm that you accept the User Comment Terms and Conditions. Affiliation ✕ refresh Please enter your institution. Note: To add your institution or organisation, start typing the name and then select the correct name from the list. Where applicable, the name will appear in both the original language and in English. Do not paste in the name. If the name does not appear in the drop-down list, we will display the information you have entered. ✕ refresh Country/Region * USA UK Canada China France Germany Afghanistan Aland Islands Albania Algeria American Samoa Andorra Angola Anguilla Antarctica Antigua and Barbuda Argentina Armenia Aruba Australia Austria Azerbaijan Bahamas Bahrain Bangladesh Barbados Belarus Belgium Belize Benin Bermuda Bhutan Bolivia Bosnia and Herzegovina Botswana Bouvet Island Brazil British Indian Ocean Territory British Virgin Islands Brunei Bulgaria Burkina Faso Burundi Cambodia Cameroon Canada Cape Verde Cayman Islands Central African Republic Chad Chile China Christmas Island Cocos (Keeling) Islands Colombia Comoros Congo Cook Islands Costa Rica Cote d'Ivoire Croatia Cuba Cyprus Czech Republic Democratic Republic of the Congo Denmark Djibouti Dominica Dominican Republic Ecuador Egypt El Salvador Equatorial Guinea Eritrea Estonia Ethiopia Falkland Islands Faroe Islands Federated States of Micronesia Fiji Finland France French Guiana French Polynesia French Southern Territories Gabon Georgia Germany Ghana Gibraltar Greece Greenland Grenada Guadeloupe Guam Guatemala Guernsey Guinea Guinea-Bissau Guyana Haiti Heard Island and Mcdonald Islands Holy See (Vatican City State) Honduras Hong Kong Hungary Iceland India Indonesia Iran Iraq Ireland Israel Italy Jamaica Japan Jersey Jordan Kazakhstan Kenya Kiribati Kosovo (Serbia and Montenegro) Kuwait Kyrgyzstan Lao People's Democratic Republic Latvia Lebanon Lesotho Liberia Libya Liechtenstein Lithuania Luxembourg Macao Madagascar Malawi Malaysia Maldives Mali Malta Marshall Islands Martinique Mauritania Mauritius Mayotte Mexico Minor Outlying Islands of the United States Moldova Monaco Mongolia Montenegro Montserrat Morocco Mozambique Myanmar Namibia Nauru Nepal Netherlands Antilles New Caledonia New Zealand Nicaragua Niger Nigeria Niue Norfolk Island North Korea North Macedonia Northern Mariana Islands Norway Oman Pakistan Palau Palestinian Territory Panama Papua New Guinea Paraguay Peru Philippines Pitcairn Poland Portugal Puerto Rico Qatar Reunion Romania Russian Federation Rwanda Saint Helena Saint Kitts and Nevis Saint Lucia Saint Pierre and Miquelon Saint Vincent and the Grenadines Samoa San Marino Sao Tome and Principe Saudi Arabia Senegal Serbia Seychelles Sierra Leone Singapore Slovakia Slovenia Solomon Islands Somalia South Africa South Georgia and the South Sandwich Is South Korea South Sudan Spain Sri Lanka Sudan Suriname Svalbard and Jan Mayen Swaziland Sweden Switzerland Syria Taiwan Tajikistan Tanzania Thailand The Gambia The Netherlands Timor-Leste Togo Tokelau Tonga Trinidad and Tobago Tunisia Turkey Turkmenistan Turks and Caicos Islands Tuvalu UK USA Uganda Ukraine United Arab Emirates United States Virgin Islands Uruguay Uzbekistan Vanuatu Venezuela Vietnam Wallis and Futuna West Bank and Gaza Strip Western Sahara Yemen Zambia Zimbabwe Please select your country/region. You must enter a comment. Competing Interests Please disclose any competing interests that might be construed to influence your judgment of the article's or peer review report's validity or importance. Competing Interests Policy Provide sufficient details of any financial or non-financial competing interests to enable users to assess whether your comments might lead a reasonable person to question your impartiality. Consider the following examples, but note that this is not an exhaustive list: Examples of 'Non-Financial Competing Interests' Within the past 4 years, you have held joint grants, published or collaborated with any of the authors of the selected paper. You have a close personal relationship (e.g. parent, spouse, sibling, or domestic partner) with any of the authors. You are a close professional associate of any of the authors (e.g. scientific mentor, recent student). You work at the same institute as any of the authors. You hope/expect to benefit (e.g. favour or employment) as a result of your submission. You are an Editor for the journal in which the article is published. Examples of 'Financial Competing Interests' You expect to receive, or in the past 4 years have received, any of the following from any commercial organisation that may gain financially from your submission: a salary, fees, funding, reimbursements. You expect to receive, or in the past 4 years have received, shared grant support or other funding with any of the authors. You hold, or are currently applying for, any patents or significant stocks/shares relating to the subject matter of the paper you are commenting on. Please state your competing interests The comment has been saved. An error has occurred. Please try again. Cancel Post var lTitle = "The EpiFusion Analysis Framework for joint...".replace("'", ''); var linkedInUrl = "http://www.linkedin.com/shareArticle?url=https://f1000research.com/articles/14-345/v1" + "&title=" + encodeURIComponent(lTitle) + "&summary=" + encodeURIComponent('Read the article by '); var deliciousUrl = "https://del.icio.us/post?url=https://f1000research.com/articles/14-345/v1&title=" + encodeURIComponent(lTitle); var redditUrl = "http://reddit.com/submit?url=https://f1000research.com/articles/14-345/v1" + "&title=" + encodeURIComponent(lTitle); linkedInUrl += encodeURIComponent('Judge C et al.'); var offsetTop = /chrome/i.test( navigator.userAgent ) ? 4 : -10; var addthis_config = { ui_offset_top: offsetTop, services_compact : "facebook,twitter,www.linkedin.com,www.mendeley.com,reddit.com", services_expanded : "facebook,twitter,www.linkedin.com,www.mendeley.com,reddit.com", services_custom : [ { name: "LinkedIn", url: linkedInUrl, icon:"/img/icon/at_linkedin.svg" }, { name: "Mendeley", url: "http://www.mendeley.com/import/?url=https://f1000research.com/articles/14-345/v1/mendeley", icon:"/img/icon/at_mendeley.svg" }, { name: "Reddit", url: redditUrl, icon:"/img/icon/at_reddit.svg" }, ] }; var addthis_share = { url: "https://f1000research.com/articles/14-345", templates : { twitter : "The EpiFusion Analysis Framework for joint phylodynamic and epidemiological.... Judge C et al., published by " + "@F1000Research" + ", https://f1000research.com/articles/14-345/v1" } }; if (typeof(addthis) != "undefined"){ addthis.addEventListener('addthis.ready', checkCount); addthis.addEventListener('addthis.menu.share', checkCount); } $(".f1r-shares-twitter").attr("href", "https://twitter.com/intent/tweet?text=" + addthis_share.templates.twitter); $(".f1r-shares-facebook").attr("href", "https://www.facebook.com/sharer/sharer.php?u=" + addthis_share.url); $(".f1r-shares-linkedin").attr("href", addthis_config.services_custom[0].url); $(".f1r-shares-reddit").attr("href", addthis_config.services_custom[2].url); $(".f1r-shares-mendelay").attr("href", addthis_config.services_custom[1].url); function checkCount(){ setTimeout(function(){ $(".addthis_button_expanded").each(function(){ var count = $(this).text(); if (count !== "" && count != "0") $(this).removeClass("is-hidden"); else $(this).addClass("is-hidden"); }); }, 1000); } close How to cite this report {{reportCitation}} Cancel Copy Citation Details $(function(){R.ui.buttonDropdowns('.dropdown-for-downloads');}); $(function(){R.ui.toolbarDropdowns('.toolbar-dropdown-for-downloads');}); $.get("/articles/acj/162719/178965") new F1000.Clipboard(); new F1000.ThesaurusTermsDisplay("articles", "article", "178965"); $(document).ready(function() { $( "#frame1" ).on('load', function() { var mydiv = $(this).contents().find("div"); var h = mydiv.height(); console.log(h) }); var tooltipLivingFigure = jQuery(".interactive-living-figure-label .icon-more-info"), titleLivingFigure = tooltipLivingFigure.attr("title"); tooltipLivingFigure.simpletip({ fixed: true, position: ["-115", "30"], baseClass: 'small-tooltip', content:titleLivingFigure + " " }); tooltipLivingFigure.removeAttr("title"); $("body").on("click", ".cite-living-figure", function(e) { e.preventDefault(); var ref = $(this).attr("data-ref"); $(this).closest(".living-figure-list-container").find("#" + ref).fadeIn(200); }); $("body").on("click", ".close-cite-living-figure", function(e) { e.preventDefault(); $(this).closest(".popup-window-wrapper").fadeOut(200); }); $(document).on("mouseup", function(e) { var metricsContainer = $(".article-metrics-popover-wrapper"); if (!metricsContainer.is(e.target) && metricsContainer.has(e.target).length === 0) { $(".article-metrics-close-button").click(); } }); var articleId = $('#articleId').val(); if($("#main-article-count-box").attachArticleMetrics) { $("#main-article-count-box").attachArticleMetrics(articleId, { articleMetricsView: true }); } }); var figshareWidget = $(".new_figshare_widget"); if (figshareWidget.length > 0) { window.figshare.load("f1000", function(Widget) { // Select a tag/tags defined in your page. In this tag we will place the widget. _.map(figshareWidget, function(el){ var widget = new Widget({ articleId: $(el).attr("figshare_articleId") //height:300 // this is the height of the viewer part. [Default: 550] }); widget.initialize(); // initialize the widget widget.mount(el); // mount it in a tag that's on your page // this will save the widget on the global scope for later use from // your JS scripts. This line is optional. //window.widget = widget; }); }); } close Error Close Add Reset F1000.MICROSERVICES.AFFILIATION = ''; $(document).ready(function () { $('.js-affiliations-form').each((index, form) => { new AffiliationForm({ formId: form.id, institutionErrorSelector: '.comment-enter-institution', departmentErrorSelector: '.comment-enter-department', placeSelector: '.js-add-comment-place', stateSelector: '.js-add-comment-state', zipCodeSelector: '.js-add-comment-zipcode', countrySelector: '.js-add-comment-country', countryErrorSelector: '.comment-enter-country', }); }); }); $(document).ready(function () { var reportIds = { "376909": 0, "374093": 19, "374092": 0, "376908": 0, "376911": 11, "374095": 0, "376910": 10, "374094": 0, "376907": 0, "376906": 0, "374101": 0, "374100": 0, "374097": 0, "376913": 0, "374096": 0, "376912": 0, "374099": 0, "376915": 0, "374098": 0, "376914": 0, }; $(".referee-response-container,.js-referee-report").each(function(index, el) { var reportId = $(el).attr("data-reportid"), reportCount = reportIds[reportId] || 0; $(el).find(".comments-count-container,.js-referee-report-views").html(reportCount); }); var uuidInput = $("#article_uuid"), oldUUId = uuidInput.val(), newUUId = "25d37a7b-211c-4208-bf1e-c269e91479ab"; uuidInput.val(newUUId); $("a[href*='article_uuid=']").each(function(index, el) { var newHref = $(el).attr("href").replace(oldUUId, newUUId); $(el).attr("href", newHref); }); }); An innovative open access publishing platform offering rapid publication and open peer review, whilst supporting data deposition and sharing. Browse Gateways Collections How it Works Contact For Developers Cookie Notice Privacy Notice RSS Submit Your Research Follow us © 2012-2026 F1000 Research Ltd. ISSN 2046-1402 | Legal | Partner of Research4Life • CrossRef • ORCID • FAIRSharing R.templateTests.simpleTemplate = R.template(' $text $text $text $text $text '); R.templateTests.runTests(); var F1000platform = new F1000.Platform({ name: "f1000research", displayName: "F1000Research", hostName: "f1000research.com", id: "1", editorialEmail: "[email protected]", infoEmail: "[email protected]", usePmcStats: true }); $(function(){R.ui.dropdowns('.dropdown-for-authors, .dropdown-for-about, .dropdown-for-myresearch');}); // $(function(){R.ui.dropdowns('.dropdown-for-referees');}); $(document).ready(function () { if ($(".cookie-warning").is(":visible")) { $(".sticky").css("margin-bottom", "35px"); $(".devices").addClass("devices-and-cookie-warning"); } $(".cookie-warning .close-button").click(function (e) { $(".devices").removeClass("devices-and-cookie-warning"); $(".sticky").css("margin-bottom", "0"); }); $("#tweeter-feed .tweet-message").each(function (i, message) { var self = $(message); self.html(linkify(self.html())); }); $(".partner").on("mouseenter mouseleave", function() { $(this).find(".gray-scale, .colour").toggleClass("is-hidden"); }); }); Sign In Remember me Forgotten your password? Sign In Cancel Email or password not correct. Please try again Please wait... $(function(){ // Note: All the setup needs to run against a name attribute and *not* the id due the clonish // nature of facebox... $("a[id=googleSignInButton]").click(function(event){ event.preventDefault(); $("input[id=oAuthSystem]").val("GOOGLE"); $("form[id=oAuthForm]").submit(); }); $("a[id=facebookSignInButton]").click(function(event){ event.preventDefault(); $("input[id=oAuthSystem]").val("FACEBOOK"); $("form[id=oAuthForm]").submit(); }); $("a[id=orcidSignInButton]").click(function(event){ event.preventDefault(); $("input[id=oAuthSystem]").val("ORCID"); $("form[id=oAuthForm]").submit(); }); }); If you've forgotten your password, please enter your email address below and we'll send you instructions on how to reset your password. The email address should be the one you originally registered with F1000. Email address not valid, please try again You registered with F1000 via Google, so we cannot reset your password. To sign in, please click here . If you still need help with your Google account password, please click here . You registered with F1000 via Facebook, so we cannot reset your password. To sign in, please click here . If you still need help with your Facebook account password, please click here . Code not correct, please try again Reset password Cancel Email us for further assistance. Server error, please try again. If your email address is registered with us, we will email you instructions to reset your password. If you think you should have received this email but it has not arrived, please check your spam filters and/or contact for further assistance. Please wait... Register $(document).ready(function () { signIn.createSignInAsRow($("#sign-in-form-gfb-popup")); $(".target-field").each(function () { var uris = $(this).val().split("/"); if (uris.pop() === "login") { $(this).val(uris.toString().replace(",","/")); } }); });

Text is read by the "Ask this paper" AI Q&A widget below. Extraction quality varies by source — PMC NXML preserves structure cleanly, OA-HTML may include some navigation residue, and OA-PDF can have broken hyphenation. The publisher copy (via DOI) is the canonical version.

My notes (saved in your browser only)

Ask this paper AI returns verbatim quotes from the full text · source: preprint-html

Answers must be backed by verbatim quotes from this paper's full text. Hallucinated quotes are dropped automatically; if no verbatim passage answers the question, we say so. How this works

Citation neighborhood (no data yet)

We don't have any in-corpus citations linked to this paper yet. This is a recent paper (2025) — citers typically take a year or two to land, and the OpenAlex reference graph may still be filling in.

Source provenance

europepmc
last seen: 2026-05-20T01:45:00.602351+00:00