diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/404.html b/404.html new file mode 100644 index 0000000000..9980424e0b --- /dev/null +++ b/404.html @@ -0,0 +1,413 @@ + + + + + + + + + + + + + + + + + + Artificial Primary Care Data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000000..1cf13b9f9d Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/javascripts/bundle.b78d2936.min.js b/assets/javascripts/bundle.b78d2936.min.js new file mode 100644 index 0000000000..520d0e513c --- /dev/null +++ b/assets/javascripts/bundle.b78d2936.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Ri=Object.create;var gr=Object.defineProperty;var ki=Object.getOwnPropertyDescriptor;var Hi=Object.getOwnPropertyNames,kt=Object.getOwnPropertySymbols,Pi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,on=Object.prototype.propertyIsEnumerable;var nn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&nn(e,r,t[r]);if(kt)for(var r of kt(t))on.call(t,r)&&nn(e,r,t[r]);return e};var an=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&kt)for(var n of kt(e))t.indexOf(n)<0&&on.call(e,n)&&(r[n]=e[n]);return r};var Ht=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var $i=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Hi(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=ki(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ri(Pi(e)):{},$i(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var cn=Ht((xr,sn)=>{(function(e,t){typeof xr=="object"&&typeof sn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(T){return!!(T&&T!==document&&T.nodeName!=="HTML"&&T.nodeName!=="BODY"&&"classList"in T&&"contains"in T.classList)}function c(T){var Qe=T.type,De=T.tagName;return!!(De==="INPUT"&&s[Qe]&&!T.readOnly||De==="TEXTAREA"&&!T.readOnly||T.isContentEditable)}function f(T){T.classList.contains("focus-visible")||(T.classList.add("focus-visible"),T.setAttribute("data-focus-visible-added",""))}function u(T){T.hasAttribute("data-focus-visible-added")&&(T.classList.remove("focus-visible"),T.removeAttribute("data-focus-visible-added"))}function p(T){T.metaKey||T.altKey||T.ctrlKey||(a(r.activeElement)&&f(r.activeElement),n=!0)}function m(T){n=!1}function d(T){a(T.target)&&(n||c(T.target))&&f(T.target)}function h(T){a(T.target)&&(T.target.classList.contains("focus-visible")||T.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(T.target))}function v(T){document.visibilityState==="hidden"&&(o&&(n=!0),G())}function G(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function oe(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(T){T.target.nodeName&&T.target.nodeName.toLowerCase()==="html"||(n=!1,oe())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),G(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var fn=Ht(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(f){return!1}},r=t(),n=function(f){var u={next:function(){var p=f.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(f){return encodeURIComponent(f).replace(/%20/g,"+")},i=function(f){return decodeURIComponent(String(f).replace(/\+/g," "))},s=function(){var f=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof f){var d=this;p.forEach(function(oe,N){d.append(N,oe)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),f._entries&&(f._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(c,f){typeof c!="string"&&(c=String(c)),f&&typeof f!="string"&&(f=String(f));var u=document,p;if(f&&(e.location===void 0||f!==e.location.href)){f=f.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=f,u.head.appendChild(p);try{if(p.href.indexOf(f)!==0)throw new Error(p.href)}catch(T){throw new Error("URL unable to set base "+f+" due to "+T)}}var m=u.createElement("a");m.href=c,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=c,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!f)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,G=!0,oe=this;["append","delete","set"].forEach(function(T){var Qe=h[T];h[T]=function(){Qe.apply(h,arguments),v&&(G=!1,oe.search=h.toString(),G=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,G&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(c){Object.defineProperty(s,c,{get:function(){return this._anchorElement[c]},set:function(f){this._anchorElement[c]=f},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(c){a(c)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(c){this._anchorElement.search=c,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var c=this;return function(){return c.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(c){this._anchorElement.href=c,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(c){this._anchorElement.pathname=c},enumerable:!0},origin:{get:function(){var c={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],f=this._anchorElement.port!=c&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(f?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(c){},enumerable:!0},username:{get:function(){return""},set:function(c){},enumerable:!0}}),i.createObjectURL=function(c){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(c){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var Kr=Ht((Mt,qr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof qr=="object"?qr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ci}});var s=i(279),a=i.n(s),c=i(370),f=i.n(c),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(O){return!1}}var d=function(O){var E=p()(O);return m("cut"),E},h=d;function v(j){var O=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[O?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var G=function(O,E){var H=v(O);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},oe=function(O){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof O=="string"?H=G(O,E):O instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(O==null?void 0:O.type)?H=G(O.value,E):(H=p()(O),m("copy")),H},N=oe;function T(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?T=function(E){return typeof E}:T=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},T(j)}var Qe=function(){var O=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=O.action,H=E===void 0?"copy":E,I=O.container,q=O.target,Me=O.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&T(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function wi(j,O){if(!(j instanceof O))throw new TypeError("Cannot call a class as a function")}function rn(j,O){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=f()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",Rt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(Rt?"success":"error",{action:Me,text:Rt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(Rt){Me=Me&&!!document.queryCommandSupported(Rt)}),Me}}]),E}(a()),Ci=Ai},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=f.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function c(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function f(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=c},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function c(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return f(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function f(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=c},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),f=document.createRange();f.selectNodeContents(i),c.removeAllRanges(),c.addRange(f),s=c.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function f(){c.off(i,f),s.apply(a,arguments)}return f._=s,this.on(i,f,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,f=a.length;for(c;c{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var ns=/["'&<>]/;Go.exports=os;function os(e){var t=""+e,r=ns.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(f[0]===6||f[0]===2)){r=0;continue}if(f[0]===3&&(!i||f[1]>i[0]&&f[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{c(n[m](d))}catch(h){p(i[0][3],h)}}function c(m){m.value instanceof et?Promise.resolve(m.value.v).then(f,u):p(i[0][2],m)}function f(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function ln(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),o(a,c,s.done,s.value)})}}function o(i,s,a,c){Promise.resolve(c).then(function(f){i({value:f,done:a})},s)}}function A(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var $t=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),c=a.next();!c.done;c=a.next()){var f=c.value;f.remove(this)}}catch(v){t={error:v}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(A(u))try{u()}catch(v){i=v instanceof $t?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{mn(h)}catch(v){i=i!=null?i:[],v instanceof $t?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new $t(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)mn(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function It(e){return e instanceof Ie||e&&"closed"in e&&A(e.remove)&&A(e.add)&&A(e.unsubscribe)}function mn(e){A(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new En(r,n)},t}(F);var En=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,c=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Ut);var Tn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Wt);var Te=new Tn(Sn);var _=new F(function(e){return e.complete()});function Dt(e){return e&&A(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return A(Cr(e))?e.pop():void 0}function Oe(e){return Dt(Cr(e))?e.pop():void 0}function Vt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function zt(e){return A(e==null?void 0:e.then)}function Nt(e){return A(e[ft])}function qt(e){return Symbol.asyncIterator&&A(e==null?void 0:e[Symbol.asyncIterator])}function Kt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Ni(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qt=Ni();function Yt(e){return A(e==null?void 0:e[Qt])}function Gt(e){return pn(this,arguments,function(){var r,n,o,i;return Pt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Bt(e){return A(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(Nt(e))return qi(e);if(pt(e))return Ki(e);if(zt(e))return Qi(e);if(qt(e))return On(e);if(Yt(e))return Yi(e);if(Bt(e))return Gi(e)}throw Kt(e)}function qi(e){return new F(function(t){var r=e[ft]();if(A(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Ki(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?L(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Vn(function(){return new Xt}))}}function zn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(f){var u,p,m,d=0,h=!1,v=!1,G=function(){p==null||p.unsubscribe(),p=void 0},oe=function(){G(),u=m=void 0,h=v=!1},N=function(){var T=u;oe(),T==null||T.unsubscribe()};return y(function(T,Qe){d++,!v&&!h&&G();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,c))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,G(),p=$r(oe,o,$e),De.error($e)},complete:function(){h=!0,G(),p=$r(oe,s),De.complete()}}),U(T).subscribe(u))})(f)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function er(e){return C(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),B())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Qn(e){return C(b(window,"load"),b(window,"resize")).pipe(Ce(0,Te),l(()=>Xe(e)),V(Xe(e)))}function tr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return C(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Te),l(()=>tr(e)),V(tr(e)))}var Gn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Dr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),ga?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Dr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=va.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Bn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Xn=typeof WeakMap!="undefined"?new WeakMap:new Gn,Zn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ya.getInstance(),n=new Aa(t,r,this);Xn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Zn.prototype[e]=function(){var t;return(t=Xn.get(this))[e].apply(t,arguments)}});var Ca=function(){return typeof rr.ResizeObserver!="undefined"?rr.ResizeObserver:Zn}(),eo=Ca;var to=new x,Ra=$(()=>k(new eo(e=>{for(let t of e)to.next(t)}))).pipe(g(e=>C(ze,k(e)).pipe(R(()=>e.disconnect()))),J(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(L(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ir(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var ro=new x,ka=$(()=>k(new IntersectionObserver(e=>{for(let t of e)ro.next(t)},{threshold:0}))).pipe(g(e=>C(ze,k(e)).pipe(R(()=>e.disconnect()))),J(1));function ar(e){return ka.pipe(S(t=>t.observe(e)),g(t=>ro.pipe(L(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function no(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),B())}var sr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function oo(e){return sr[e].checked}function Ke(e,t){sr[e].checked!==t&&sr[e].click()}function Ue(e){let t=sr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function Ha(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Pa(){return C(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function io(){let e=b(window,"keydown").pipe(L(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:oo("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),L(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!Ha(n,r)}return!0}),pe());return Pa().pipe(g(t=>t?_:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function ao(){return new x}function so(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)so(e,r)}function M(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)so(n,o);return n}function cr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function co(){return location.hash.substring(1)}function Vr(e){let t=M("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function $a(){return b(window,"hashchange").pipe(l(co),V(co()),L(e=>e.length>0),J(1))}function fo(){return $a().pipe(l(e=>ce(`[id="${e}"]`)),L(e=>typeof e!="undefined"))}function zr(e){let t=matchMedia(e);return Zt(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function uo(){let e=matchMedia("print");return C(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function Nr(e,t){return e.pipe(g(r=>r?t():_))}function fr(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>_),g(r=>r.status!==200?Tt(()=>new Error(r.statusText)):k(r)))}function We(e,t){return fr(e,t).pipe(g(r=>r.json()),J(1))}function po(e,t){let r=new DOMParser;return fr(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),J(1))}function ur(e){let t=M("script",{src:e});return $(()=>(document.head.appendChild(t),C(b(t,"load"),b(t,"error").pipe(g(()=>Tt(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function lo(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function mo(){return C(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(lo),V(lo()))}function ho(){return{width:innerWidth,height:innerHeight}}function bo(){return b(window,"resize",{passive:!0}).pipe(l(ho),V(ho()))}function vo(){return Q([mo(),bo()]).pipe(l(([e,t])=>({offset:e,size:t})),J(1))}function pr(e,{viewport$:t,header$:r}){let n=t.pipe(Z("size")),o=Q([n,r]).pipe(l(()=>Xe(e)));return Q([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:c,y:f}])=>({offset:{x:s.x-c,y:s.y-f+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,c,f)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:c,error:f});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Dev setup

+

Dev setup can be found in the README.

+

Development

+

There are two types of development for the code:

+
    +
  • +

    To develop the underlying engine see java.md.

    +
  • +
  • +

    To develop the underlying information that the simulation works on read below about the resources and data sources

    +
  • +
+

Resource in swpc_synthea

+
├── src/main/resources
+|   ├── export
+|   ├── geogrpahy
+|   ├── keep_modules
+|   ├── modules
+|   ├── physiology
+|   ├── providers
+|   ├── templates
+|   biometrics.yml
+|   birthweights.csv
+|   bmi_correlations.json
+|   cdc_growth_charts.json
+|   cdc_wtleninf.csv
+|   gdb_disability_weights.csv
+|   growth_data_error_rates.json
+|   htn_drugs.csv
+|   immunization_schedule.json
+|   language_lookup.json
+|   names.yml
+|   nhanes_two_year_olds_bmi.csv
+|   race_ethinicity_codes.json
+|   shr_mapping.csv
+|   telemedicine_config.json
+|   us_core_mapping.csv
+
+

We'll now highlight a few key files for the simulation inputs

+

geography/demographics.csv

+

This file sets the general demographics for the population created during this simulation, such as age distributions and town populations. The meanings of the different columns in this file can be found here.

+

The demographics breakdowns are done by the full region rather than per town as information per town was not available.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Column NameContainsData Sources for UK Version
IDTown ID numbermonotonically increasing from 1
COUNTYCounty Code where town is locatedTOWN_211CODE column from ONS data table
NAMETown NameTOWN_211NAME column from above ONS table
STNAMERegion NameREGION/COUNTRY from above ONS table
POPESTIMATE2015Population of that townTOTAL population rows for 2019 from above ONS data
CTYNAMECounty Name where town is locatedrange of wikipedia sites for the towns
TOT_POPtotal county populationONS Region data
Ethnicity (includes ASIAN, BLACK, MIXED, WHITE, OTHER columns)Percentage of the population that is of a certain ethnicity1NHS Health Survey England
Ages (includes all age breakdown columns)percentage of population in different age groupsAnother NHS Health Survey England2
Income (includes all income breakdown columns)percentage of population in different income bracketsONS Employment data3
LESS_THAN_HSfraction of people with no qualifications, or level 1 or 2 of education (as classified by ONS)ONS Education data
HS_DEGREEfraction of people with level 3 educationSame as above
SOME_COLLEGEfraction of people with apprenticeshipsSame as above
BS_DEGREEfraction of people with level 4 educationSame as above
+

Many of the above sources are complimented by data from the 2021 census

+

geography/sdoh.csv

+

This file contains information on social determinants of health for the different regions.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Column NameContainsData Sources for UK Version
FOOD_INSECURITYpercentage of people with food insecuritySheffield University study
SEVERE_HOUSING_COST_BURDENpercentage of people with severe housing cost burden 4Government English housing survey
UNEMPLOYMENTpercentage of unemploymentONS local labour market data
NO_VEHICLE_ACCESSpercentage of the population with no access to a vehicleONS census data
+

geogrpahy/postcodes.csv

+

Originally called zipcodes.csv but changed to use the English word. Postcode information found here.

+

modules/

+

Store for the clinical modules saved as jsons. Most of these are currently based on the original US SyntheaTM version. See index.md for a list of changed modules.

+

providers/

+

These file sets different medical facilities for patients to attend in the simulation.

+

GP practices in the South West were found in the NHS digital GP Practice Data, and the conversion from postcode to latitude and longitude was done using the grid reference finder.

+
+
+
    +
  1. +

    Ethnicity categories were changed from the American version to align better with UK ethnicity breakdowns 

    +
  2. +
  3. +

    Under 18 ages set to 0 as we are only interested in an adult population currently. 

    +
  4. +
  5. +

    Income brackets don't match exactly, and so estimations of the breakdowns within the brackets used in Synthea had to be done. 

    +
  6. +
  7. +

    We used data on mortgagors who found affording their mortgage very or fairly difficult (table AT2_8) plus renters who found affording their rent very or fairly difficult over the total number of people surveyed in the study used. This data was only available for the whole country. 

    +
  8. +
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000000..097181e52e --- /dev/null +++ b/index.html @@ -0,0 +1,525 @@ + + + + + + + + + + + + + + + + + + + + Artificial Primary Care Data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Generating Primary Care Data Using UK Version of Synthea

+

Primary care records are crucial for understanding healthcare interactions at both the population and individual levels. However, these records are difficult to obtain and integrate with other services, hindering innovation due to data unavailability and privacy concerns.

+

Our project aims to address this by developing a code base to generate primary care electronic health records. We start by creating a synthetic population that mirrors a region in England, and then adapt the US-based tool Synthea for the English NHS context (particularly focusing on the South West of England). We chose Synthea as it is already a highly developed, accuracy tested synthetic generator, and adapting it is relatively simple with clinical input. It is also highly efficient and quick to generate large amounts of data.

+

See the data science website for more details on the aims of the project.

+

Usage and Limitations

+

The aim of Synthea is to produce data that is "Realistic but not real." +This means that data produced by Synthea can be used to trial systems, and to test software and procedures, but it should not be used to draw statistical insight or do analysis.

+

The UK adaptation of Synthea has removed several features which were US specific, and integrates UK statistics +Details of the available features can be found here

+

Evaluation

+

The functionality and stability of the release has been "smoke-tested" by assuring valid outputs can be optained when using various option flags described in the documentation.

+

In the current release of the UK Adaptation of Synthea there have not been any statistical validations of outputs.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/java/index.html b/java/index.html new file mode 100644 index 0000000000..d40f92a4d7 --- /dev/null +++ b/java/index.html @@ -0,0 +1,693 @@ + + + + + + + + + + + + + + + + + + + + + + Java - Artificial Primary Care Data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + +

Java Src Code

+

App.java

+

The engine behind the simualtion is built in Java and can be seen in src/main/java

+
├── src/main/java 
+|   ├── App.java 
+
+

The App class provides a command-line interface to run the Synthea generation engine. It handles various command-line arguments to configure the simulation, including options for seeding, population size, date ranges, and other settings. The class includes methods to display usage information and to parse and validate the command-line arguments. It then uses these arguments to configure and run the Synthea generator, which simulates patient health records.

+

Main code structure

+

The rest of the Java code has the following structure and documentation is provided mostly through in-line comments.

+
├── src/main/java 
+|   ├── App.java 
+|   |   ├── org/mitre/synthea
+|   |   |   ├── editors
+|   |   |   ├── engine
+|   |   |   ├── export
+|   |   |   ├── helpers
+|   |   |   |   ├── physiology
+|   |   |   ├── identity
+|   |   |   ├── modules
+|   |   |   ├── world
+|   |   |   |   ├── agents
+|   |   |   |   |   ├── behaviors
+|   |   |   |   ├── concepts
+|   |   |   |   ├── geography
+|   |   |   |   |   ├── quadtree
+
+

A couple of key files to note include

+

engine/Generator.java

+

The Generator class is responsible for simulating the creation of a population of people and their health records over time. The population is generated according to configurable options such as population size, seed for random number generation, location, and demographic criteria. The Generator supports multithreaded execution to speed up the simulation process.

+

engine/HealthRecordEditor.java

+

The HealthRecordEditor offers an interface that can be implemented to modify a Synthea Person's HealthRecord. At the end of every time step in the simulation, the Synthea framework will invoke the shouldRun method. If the shouldRun function returns true, the framework will then invoke the process method. The process method will be passed any encounters that were created in the past time step.

+

HealthRecordEditors are intended to simulate actions that happen to an individual's health record. This includes loss or corruption of information through user entry error or information system defects.

+

HealthRecordEditors SHOULD NOT be used to simulate clinical interactions on the underlying physical state / circumstances of the Synthea Person. Those should be implemented in Synthea modules.

+

engine/Module.java

+

Module represents the entry point of a generic module.

+

The modules map is the static list of generic modules. It is loaded once per process, and the list of modules is shared between the generated population. Because we share modules across the population, it is important that States are cloned before they are executed. This keeps the "master" copy of the module clean.

+

engine/State.java

+

The State class represents an abstract base class for different types of states in a simulation module within the Synthea framework. Each state represents a distinct event or action that occurs to a person (e.g., an encounter, condition onset, procedure, etc.) as part of the simulation of their healthcare journey.

+

States define the logic for what happens to the person when they are processed by the simulation engine, including transitions to subsequent states based on conditions, time delays, and other factors. Subclasses of State implement specific behaviors and actions, such as recording a medical condition or administering a medication.

+

engine/Transition.java

+

Transition represents all the transition types within the generic module framework.

+

identitiy/Entity.java

+

This class represents a set of desired demographic information about a Person to be simulated. Typically in Synthea, a person's demographic information is made via random weighted selections and an individual stays in the same place for their entire life. An Entity can be used to specify demographic information. Additionally, information can be supplied that allows the simulation to mimic someone moving their primary place of residence.

+

This class contains basic-level demographic information, such as date of birth and gender. More detailed information is contained in Seeds. Each Entity is made up of a list of Seeds, which represent the demographic information for a Person over a specified time range.

+

As an example, a Person can have a seed to represent their birthplace. 10 years later, their family moves, so another seed would be added to their record reflecting their new address

+

Seeds have one or more Variants. This is a representation of have the demographic information will be when placed in the exported health record. It can be used to represent data errors or variations typically seen in demographic information, such as nicknames, typos, old addresses, etc.

+

modules/

+

Various java files for some of the default modules including BloodPressureValueGenerator, DeathModule, and the EncounterModule which defines the threshold for which a patient seeks symptom-driven care.

+

world/agents/

+

Files for creating new clincians, persons and providers.

+

world/geography

+

Ingests the geography information for locations and places.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/outputs/index.html b/outputs/index.html new file mode 100644 index 0000000000..dbf5b03e17 --- /dev/null +++ b/outputs/index.html @@ -0,0 +1,541 @@ + + + + + + + + + + + + + + + + + + + + + + Example Outputs - Artificial Primary Care Data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Example of Outputs from swpc_sythea

+

For a current csv run the outputs are stored in the outputs/csv folder. These output files include: +- allergies.csv +- careplans.csv +- claims_transactions.csv +- claims.csv +- conditions.csv +- devices.csv +- encounters.csv +- imaging_studies.csv +- immunizations.csv +- medications.csv +- observations.csv +- organizations.csv +- patients.csv +- procedures.csv +- providers.csv +- supplies.csv

+

Showing blood test reading for an individual

+

PLACEHOLDER

+

Showing total activity by provider and location

+

PLACEHOLDER

+

Showing total number of patients with hypertension by time within the entire simulation

+

PLACEHOLDER

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000000..8375599d18 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Generating Primary Care Data Using UK Version of Synthea","text":"

Primary care records are crucial for understanding healthcare interactions at both the population and individual levels. However, these records are difficult to obtain and integrate with other services, hindering innovation due to data unavailability and privacy concerns.

Our project aims to address this by developing a code base to generate primary care electronic health records. We start by creating a synthetic population that mirrors a region in England, and then adapt the US-based tool Synthea for the English NHS context (particularly focusing on the South West of England). We chose Synthea as it is already a highly developed, accuracy tested synthetic generator, and adapting it is relatively simple with clinical input. It is also highly efficient and quick to generate large amounts of data.

See the data science website for more details on the aims of the project.

"},{"location":"#usage-and-limitations","title":"Usage and Limitations","text":"

The aim of Synthea is to produce data that is \"Realistic but not real.\" This means that data produced by Synthea can be used to trial systems, and to test software and procedures, but it should not be used to draw statistical insight or do analysis.

The UK adaptation of Synthea has removed several features which were US specific, and integrates UK statistics Details of the available features can be found here

"},{"location":"#evaluation","title":"Evaluation","text":"

The functionality and stability of the release has been \"smoke-tested\" by assuring valid outputs can be optained when using various option flags described in the documentation.

In the current release of the UK Adaptation of Synthea there have not been any statistical validations of outputs.

"},{"location":"dev/","title":"Dev setup","text":"

Dev setup can be found in the README.

"},{"location":"dev/#development","title":"Development","text":"

There are two types of development for the code:

  • To develop the underlying engine see java.md.

  • To develop the underlying information that the simulation works on read below about the resources and data sources

"},{"location":"dev/#resource-in-swpc_synthea","title":"Resource in swpc_synthea","text":"
\u251c\u2500\u2500 src/main/resources\n|   \u251c\u2500\u2500 export\n|   \u251c\u2500\u2500 geogrpahy\n|   \u251c\u2500\u2500 keep_modules\n|   \u251c\u2500\u2500 modules\n|   \u251c\u2500\u2500 physiology\n|   \u251c\u2500\u2500 providers\n|   \u251c\u2500\u2500 templates\n|   biometrics.yml\n|   birthweights.csv\n|   bmi_correlations.json\n|   cdc_growth_charts.json\n|   cdc_wtleninf.csv\n|   gdb_disability_weights.csv\n|   growth_data_error_rates.json\n|   htn_drugs.csv\n|   immunization_schedule.json\n|   language_lookup.json\n|   names.yml\n|   nhanes_two_year_olds_bmi.csv\n|   race_ethinicity_codes.json\n|   shr_mapping.csv\n|   telemedicine_config.json\n|   us_core_mapping.csv\n

We'll now highlight a few key files for the simulation inputs

"},{"location":"dev/#geographydemographicscsv","title":"geography/demographics.csv","text":"

This file sets the general demographics for the population created during this simulation, such as age distributions and town populations. The meanings of the different columns in this file can be found here.

The demographics breakdowns are done by the full region rather than per town as information per town was not available.

Column Name Contains Data Sources for UK Version ID Town ID number monotonically increasing from 1 COUNTY County Code where town is located TOWN_211CODE column from ONS data table NAME Town Name TOWN_211NAME column from above ONS table STNAME Region Name REGION/COUNTRY from above ONS table POPESTIMATE2015 Population of that town TOTAL population rows for 2019 from above ONS data CTYNAME County Name where town is located range of wikipedia sites for the towns TOT_POP total county population ONS Region data Ethnicity (includes ASIAN, BLACK, MIXED, WHITE, OTHER columns) Percentage of the population that is of a certain ethnicity1 NHS Health Survey England Ages (includes all age breakdown columns) percentage of population in different age groups Another NHS Health Survey England2 Income (includes all income breakdown columns) percentage of population in different income brackets ONS Employment data3 LESS_THAN_HS fraction of people with no qualifications, or level 1 or 2 of education (as classified by ONS) ONS Education data HS_DEGREE fraction of people with level 3 education Same as above SOME_COLLEGE fraction of people with apprenticeships Same as above BS_DEGREE fraction of people with level 4 education Same as above

Many of the above sources are complimented by data from the 2021 census

"},{"location":"dev/#geographysdohcsv","title":"geography/sdoh.csv","text":"

This file contains information on social determinants of health for the different regions.

Column Name Contains Data Sources for UK Version FOOD_INSECURITY percentage of people with food insecurity Sheffield University study SEVERE_HOUSING_COST_BURDEN percentage of people with severe housing cost burden 4 Government English housing survey UNEMPLOYMENT percentage of unemployment ONS local labour market data NO_VEHICLE_ACCESS percentage of the population with no access to a vehicle ONS census data"},{"location":"dev/#geogrpahypostcodescsv","title":"geogrpahy/postcodes.csv","text":"

Originally called zipcodes.csv but changed to use the English word. Postcode information found here.

"},{"location":"dev/#modules","title":"modules/","text":"

Store for the clinical modules saved as jsons. Most of these are currently based on the original US SyntheaTM version. See index.md for a list of changed modules.

"},{"location":"dev/#providers","title":"providers/","text":"

These file sets different medical facilities for patients to attend in the simulation.

GP practices in the South West were found in the NHS digital GP Practice Data, and the conversion from postcode to latitude and longitude was done using the grid reference finder.

  1. Ethnicity categories were changed from the American version to align better with UK ethnicity breakdowns\u00a0\u21a9

  2. Under 18 ages set to 0 as we are only interested in an adult population currently.\u00a0\u21a9

  3. Income brackets don't match exactly, and so estimations of the breakdowns within the brackets used in Synthea had to be done.\u00a0\u21a9

  4. We used data on mortgagors who found affording their mortgage very or fairly difficult (table AT2_8) plus renters who found affording their rent very or fairly difficult over the total number of people surveyed in the study used. This data was only available for the whole country.\u00a0\u21a9

"},{"location":"java/","title":"Java Src Code","text":""},{"location":"java/#appjava","title":"App.java","text":"

The engine behind the simualtion is built in Java and can be seen in src/main/java

\u251c\u2500\u2500 src/main/java \n|   \u251c\u2500\u2500 App.java \n

The App class provides a command-line interface to run the Synthea generation engine. It handles various command-line arguments to configure the simulation, including options for seeding, population size, date ranges, and other settings. The class includes methods to display usage information and to parse and validate the command-line arguments. It then uses these arguments to configure and run the Synthea generator, which simulates patient health records.

"},{"location":"java/#main-code-structure","title":"Main code structure","text":"

The rest of the Java code has the following structure and documentation is provided mostly through in-line comments.

\u251c\u2500\u2500 src/main/java \n|   \u251c\u2500\u2500 App.java \n|   |   \u251c\u2500\u2500 org/mitre/synthea\n|   |   |   \u251c\u2500\u2500 editors\n|   |   |   \u251c\u2500\u2500 engine\n|   |   |   \u251c\u2500\u2500 export\n|   |   |   \u251c\u2500\u2500 helpers\n|   |   |   |   \u251c\u2500\u2500 physiology\n|   |   |   \u251c\u2500\u2500 identity\n|   |   |   \u251c\u2500\u2500 modules\n|   |   |   \u251c\u2500\u2500 world\n|   |   |   |   \u251c\u2500\u2500 agents\n|   |   |   |   |   \u251c\u2500\u2500 behaviors\n|   |   |   |   \u251c\u2500\u2500 concepts\n|   |   |   |   \u251c\u2500\u2500 geography\n|   |   |   |   |   \u251c\u2500\u2500 quadtree\n

A couple of key files to note include

"},{"location":"java/#enginegeneratorjava","title":"engine/Generator.java","text":"

The Generator class is responsible for simulating the creation of a population of people and their health records over time. The population is generated according to configurable options such as population size, seed for random number generation, location, and demographic criteria. The Generator supports multithreaded execution to speed up the simulation process.

"},{"location":"java/#enginehealthrecordeditorjava","title":"engine/HealthRecordEditor.java","text":"

The HealthRecordEditor offers an interface that can be implemented to modify a Synthea Person's HealthRecord. At the end of every time step in the simulation, the Synthea framework will invoke the shouldRun method. If the shouldRun function returns true, the framework will then invoke the process method. The process method will be passed any encounters that were created in the past time step.

HealthRecordEditors are intended to simulate actions that happen to an individual's health record. This includes loss or corruption of information through user entry error or information system defects.

HealthRecordEditors SHOULD NOT be used to simulate clinical interactions on the underlying physical state / circumstances of the Synthea Person. Those should be implemented in Synthea modules.

"},{"location":"java/#enginemodulejava","title":"engine/Module.java","text":"

Module represents the entry point of a generic module.

The modules map is the static list of generic modules. It is loaded once per process, and the list of modules is shared between the generated population. Because we share modules across the population, it is important that States are cloned before they are executed. This keeps the \"master\" copy of the module clean.

"},{"location":"java/#enginestatejava","title":"engine/State.java","text":"

The State class represents an abstract base class for different types of states in a simulation module within the Synthea framework. Each state represents a distinct event or action that occurs to a person (e.g., an encounter, condition onset, procedure, etc.) as part of the simulation of their healthcare journey.

States define the logic for what happens to the person when they are processed by the simulation engine, including transitions to subsequent states based on conditions, time delays, and other factors. Subclasses of State implement specific behaviors and actions, such as recording a medical condition or administering a medication.

"},{"location":"java/#enginetransitionjava","title":"engine/Transition.java","text":"

Transition represents all the transition types within the generic module framework.

"},{"location":"java/#identitiyentityjava","title":"identitiy/Entity.java","text":"

This class represents a set of desired demographic information about a Person to be simulated. Typically in Synthea, a person's demographic information is made via random weighted selections and an individual stays in the same place for their entire life. An Entity can be used to specify demographic information. Additionally, information can be supplied that allows the simulation to mimic someone moving their primary place of residence.

This class contains basic-level demographic information, such as date of birth and gender. More detailed information is contained in Seeds. Each Entity is made up of a list of Seeds, which represent the demographic information for a Person over a specified time range.

As an example, a Person can have a seed to represent their birthplace. 10 years later, their family moves, so another seed would be added to their record reflecting their new address

Seeds have one or more Variants. This is a representation of have the demographic information will be when placed in the exported health record. It can be used to represent data errors or variations typically seen in demographic information, such as nicknames, typos, old addresses, etc.

"},{"location":"java/#modules","title":"modules/","text":"

Various java files for some of the default modules including BloodPressureValueGenerator, DeathModule, and the EncounterModule which defines the threshold for which a patient seeks symptom-driven care.

"},{"location":"java/#worldagents","title":"world/agents/","text":"

Files for creating new clincians, persons and providers.

"},{"location":"java/#worldgeography","title":"world/geography","text":"

Ingests the geography information for locations and places.

"},{"location":"outputs/","title":"Example of Outputs from swpc_sythea","text":"

For a current csv run the outputs are stored in the outputs/csv folder. These output files include: - allergies.csv - careplans.csv - claims_transactions.csv - claims.csv - conditions.csv - devices.csv - encounters.csv - imaging_studies.csv - immunizations.csv - medications.csv - observations.csv - organizations.csv - patients.csv - procedures.csv - providers.csv - supplies.csv

"},{"location":"outputs/#showing-blood-test-reading-for-an-individual","title":"Showing blood test reading for an individual","text":"

PLACEHOLDER

"},{"location":"outputs/#showing-total-activity-by-provider-and-location","title":"Showing total activity by provider and location","text":"

PLACEHOLDER

"},{"location":"outputs/#showing-total-number-of-patients-with-hypertension-by-time-within-the-entire-simulation","title":"Showing total number of patients with hypertension by time within the entire simulation","text":"

PLACEHOLDER

"},{"location":"ukadaptions/","title":"UK Adaptions to SyntheTM","text":"

Stage 1: Removing non-English NHS functions and simplifying the Java to an MVP

Functions relating to:

  • Flexporter (functionality which could be brought back later)
  • Payers and related managers
  • Insurance plans
  • Claims (mostly for medications)
  • Income, healthcare expenses and coverage
  • Cost
  • Exporting as DSTU2 or STU3
  • Cardiovascular disease module (as this is a US-based calculator)
  • ASCVD, Framingam and C19 Immunizations (as these are all US-based and not applicable)
  • CMSStateCodeMapper

These functions have all been commented using a UKAdp tag to keep an audit trail. These adaptions result in 113 sections of code commented out across 16 files (all within the src/main/java/org/mitre/synthea/).

Stage 2: Adapting Resource files for UK South West Region context

  • Replace demographics.csv with South West towns and cities
  • Replace fipscodes.csv with County GSS codes
  • Update social determinants of health (sdoh.csv) file with food insecurity, severe housing cost burdens, unemployment, and vehicle access values correct for the UK regions.
  • Replace timezones.csv with GMT
  • Replace zipcodes.csv with uk based postcodes
  • Keep birthweights.csv as US version (for the moment)
  • Keep bmi_correlations.json as US version (for the moment)
  • Keep cdc_growth_charts.json as US version (for the moment)
  • Keep gbd_disability_weigths.csv as US version (for the moment)
  • Update immunization_scheldule.json to vaccine schedules used in the UK
  • Update synthea.properties to remove unused exporter and payer functionality and amend inputs for South West Region.
  • Reduce the care settings down to hospitals, primary care and urgent care, and update these to have South West facilities.

There are still many US-based nuances that need to be dealt with such as payer columns still appearing in the outputs.

Stage 3: Module Update

The Hypertension module and the Hypertension medication module have been made based on the NICE guidelines for hypertension diagnosis, management and medication, together with some clinical input. However, they are still waiting on further clinical input, in particular for the choice of specific medications prescribed.

Find documentation on the differences between NICE and the original version of these modules at: /docs/compare_hypertension_to_nice.pdf

"},{"location":"users/","title":"Setup swpc_Synthea","text":"

See Readme

"},{"location":"users/#creating-a-patient-dataset","title":"Creating a patient dataset","text":"

See the original Synthea documentationt that can be found here.

"},{"location":"users/#interegating-a-patient-dataset","title":"Interegating a patient dataset","text":"

PLACEHOLDER

"},{"location":"users/#configuration","title":"Configuration","text":""},{"location":"users/#synthea-properties","title":"Synthea Properties","text":"

The src/main/resources/synthea.properties file controls the main configuration of the simulation

Here is a reduced view of the file for the main configuration options used in swpc_synthea and their default values

exporter.baseDirectory = ./output/\nexporter.use_uuid_filenames = false\nexporter.subfolders_by_id_substring = false\nexporter.years_of_history = 10\nexporter.metadata.export = true\nexporter.encoding = UTF-8\nexporter.csv.export = true\n\n# the number of patients to generate, by default\n# this can be overridden by passing a different value to the Generator constructor\ngenerate.default_population = 5\n\n# the number of threads to use for the generator, set the value to -1 to match the number of\n# available processors (as per Runtime.getRuntime().availableProcessors())\n# defaults to -1 if not specified\ngenerate.thread_pool_size = -1\n\ngenerate.log_patients.detail = simple\n# options are \"none\", \"simple\", or \"detailed\" (without quotes). defaults to simple if another value is used\n# none = print nothing to the console during generation\n# simple = print patient names once they are generated.\n# detailed = print patient names, atributes, vital signs, etc..  May slow down processing\n\ngenerate.timestep = 604800000\n# time is in ms\n# 1000 * 60 * 60 * 24 * 7 = 604800000\n\ngenerate.demographics.default_file = geography/demographics.csv\ngenerate.geography.postcodes.default_file = geography/postcodes.csv\ngenerate.geography.country_code = England\ngenerate.geography.timezones.default_file = geography/timezones.csv\ngenerate.geography.foreign.birthplace.default_file = geography/foreign_birthplace.json\ngenerate.geography.sdoh.default_file = geography/sdoh.csv\n\n# Lookup Table Folder location\ngenerate.lookup_tables = modules/lookup_tables/\n\n# if criteria are provided, (for example, only_dead_patients, only_alive_patients, or a \"patient keep module\" with -k flag)\n# this is the maximum number of times synthea will loop over a single slot attempting to produce a matching patient.\n# after this many failed attempts, it will throw an exception.\n# set this to 0 to allow for unlimited attempts (but be aware of the possibility that it will never complete!)\ngenerate.max_attempts_to_keep_patient = 1000\n\n# Probability of each person having a middle name. 0 is zero, 1.0 is 100% chance.\ngenerate.middle_names = 0.80\n\n# if true, the entire population will use veteran prevalence data\ngenerate.veteran_population_override = false\n\n# these should add up to 1.0\n# weighting and categories are inspired by the following but there are no specific hard numbers to point to\n# http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1694190/pdf/amjph00543-0042.pdf\n# http://www.ncbi.nlm.nih.gov/pubmed/8122813\ngenerate.demographics.socioeconomic.weights.income = 0.2\ngenerate.demographics.socioeconomic.weights.education = 0.7\ngenerate.demographics.socioeconomic.weights.occupation = 0.1\n\ngenerate.demographics.socioeconomic.score.low = 0.0\ngenerate.demographics.socioeconomic.score.middle = 0.25\ngenerate.demographics.socioeconomic.score.high = 0.66\n\ngenerate.demographics.socioeconomic.education.less_than_hs.min = 0.0\ngenerate.demographics.socioeconomic.education.less_than_hs.max = 0.5\ngenerate.demographics.socioeconomic.education.hs_degree.min = 0.1\ngenerate.demographics.socioeconomic.education.hs_degree.max = 0.75\ngenerate.demographics.socioeconomic.education.some_college.min = 0.3\ngenerate.demographics.socioeconomic.education.some_college.max = 0.85\ngenerate.demographics.socioeconomic.education.bs_degree.min = 0.5\ngenerate.demographics.socioeconomic.education.bs_degree.max = 1.0\n\n# The average family size in the US is 3.13. The 2010 FPL for a 3-person household is $18310. Tuned it to $17550 for realistic medicaid/ACA enrollments.\ngenerate.demographics.socioeconomic.income.poverty = 17550\ngenerate.demographics.socioeconomic.income.high = 75000\n\ngenerate.birthweights.default_file = birthweights.csv\ngenerate.birthweights.logging = false\n\n# Providers\ngenerate.providers.hospitals.default_file = providers/hospitals.csv\n# --generate.providers.longterm.default_file = providers/longterm.csv\n# --generate.providers.nursing.default_file = providers/nursing.csv\n# --generate.providers.rehab.default_file = providers/rehab.csv\n# --generate.providers.hospice.default_file = providers/hospice.csv\n# --generate.providers.dialysis.default_file = providers/dialysis.csv\n# --generate.providers.homehealth.default_file = providers/home_health_agencies.csv\n# --generate.providers.veterans.default_file = providers/va_facilities.csv\ngenerate.providers.urgentcare.default_file = providers/urgent_care_facilities.csv\ngenerate.providers.primarycare.default_file = providers/primary_care_facilities.csv\n# --generate.providers.ihs.hospitals.default_file = providers/ihs_facilities.csv\n# --generate.providers.ihs.primarycare.default_file = providers/ihs_centers.csv\n\n# Provider selection behavior\n# How patients select a provider organization:\n#  nearest - select the closest provider. See generate.providers.maximum_search_distance\n#  random  - select randomly.\n#  network - select a random provider in your insurance network. same as random except it changes every time the patient switches insurance provider.\n#  medicare - select the nearest provider that can bill Medicare. If no Medicare provider is found, it defaults back to \"nearest\".\ngenerate.providers.selection_behavior = nearest\n\n# if a provider cannot be found for a certain type of service,\n# this will default to the nearest hospital.\ngenerate.providers.default_to_hospital_on_failure = true\n\n# Quit Smoking\nlifecycle.quit_smoking.baseline = 0.01\nlifecycle.quit_smoking.timestep_delta = -0.01\nlifecycle.quit_smoking.smoking_duration_factor_per_year = 1.0\n\n# Quit Alcoholism\nlifecycle.quit_alcoholism.baseline = 0.001\nlifecycle.quit_alcoholism.timestep_delta = -0.001\nlifecycle.quit_alcoholism.alcoholism_duration_factor_per_year = 1.0\n\n# Adherence\nlifecycle.adherence.baseline = 0.05\n\n# set this to true to enable randomized \"death by natural causes\"\n# highly recommended if \"only_dead_patients\" is true\nlifecycle.death_by_natural_causes = false\n\n# set this to enable \"death by loss of care\" or missed care,\n# e.g. not covered by insurance or otherwise unaffordable.\n# only functional if \"generate.payers.loss_of_care\" is also true.\nlifecycle.death_by_loss_of_care = false\n\n# Use physiology simulations to generate some VitalSigns\nphysiology.generators.enabled = false\n\n# Allow physiology module states to be executed\n# If false, all Physiology state objects will immediately redirect to the state defined in\n# the alt_direct_transition field\nphysiology.state.enabled = false\n\n# set to true to introduce errors in height, weight and BMI observations for people\n# under 20 years old\ngrowtherrors = false\n
"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000000..385d9675c7 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,33 @@ + + + + None + 2024-08-21 + daily + + + None + 2024-08-21 + daily + + + None + 2024-08-21 + daily + + + None + 2024-08-21 + daily + + + None + 2024-08-21 + daily + + + None + 2024-08-21 + daily + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000000..f9f8c442d0 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/ukadaptions/index.html b/ukadaptions/index.html new file mode 100644 index 0000000000..7bf4f7033b --- /dev/null +++ b/ukadaptions/index.html @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + + + + UK Adaptations - Artificial Primary Care Data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

UK Adaptions to SyntheTM

+

Stage 1: Removing non-English NHS functions and simplifying the Java to an MVP

+

Functions relating to:

+
    +
  • Flexporter (functionality which could be brought back later)
  • +
  • Payers and related managers
  • +
  • Insurance plans
  • +
  • Claims (mostly for medications)
  • +
  • Income, healthcare expenses and coverage
  • +
  • Cost
  • +
  • Exporting as DSTU2 or STU3
  • +
  • Cardiovascular disease module (as this is a US-based calculator)
  • +
  • ASCVD, Framingam and C19 Immunizations (as these are all US-based and not applicable)
  • +
  • CMSStateCodeMapper
  • +
+

These functions have all been commented using a UKAdp tag to keep an audit trail. These adaptions result in 113 sections of code commented out across 16 files (all within the src/main/java/org/mitre/synthea/).

+

Stage 2: Adapting Resource files for UK South West Region context

+
    +
  • Replace demographics.csv with South West towns and cities
  • +
  • Replace fipscodes.csv with County GSS codes
  • +
  • Update social determinants of health (sdoh.csv) file with food insecurity, severe housing cost burdens, unemployment, and vehicle access values correct for the UK regions.
  • +
  • Replace timezones.csv with GMT
  • +
  • Replace zipcodes.csv with uk based postcodes
  • +
  • Keep birthweights.csv as US version (for the moment)
  • +
  • Keep bmi_correlations.json as US version (for the moment)
  • +
  • Keep cdc_growth_charts.json as US version (for the moment)
  • +
  • Keep gbd_disability_weigths.csv as US version (for the moment)
  • +
  • Update immunization_scheldule.json to vaccine schedules used in the UK
  • +
  • Update synthea.properties to remove unused exporter and payer functionality and amend inputs for South West Region.
  • +
  • Reduce the care settings down to hospitals, primary care and urgent care, and update these to have South West facilities.
  • +
+

There are still many US-based nuances that need to be dealt with such as payer columns still appearing in the outputs.

+

Stage 3: Module Update

+

The Hypertension module and the Hypertension medication module have been made based on the NICE guidelines for hypertension diagnosis, management and medication, together with some clinical input. However, they are still waiting on further clinical input, in particular for the choice of specific medications prescribed.

+

Find documentation on the differences between NICE and the original version of these modules at: /docs/compare_hypertension_to_nice.pdf

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/users/index.html b/users/index.html new file mode 100644 index 0000000000..a3aaf83ed3 --- /dev/null +++ b/users/index.html @@ -0,0 +1,590 @@ + + + + + + + + + + + + + + + + + + + + + + Users - Artificial Primary Care Data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Setup swpc_Synthea

+

See Readme

+

Creating a patient dataset

+

See the original Synthea documentationt that can be found here.

+

Interegating a patient dataset

+

PLACEHOLDER

+

Configuration

+

Synthea Properties

+

The src/main/resources/synthea.properties file controls the main configuration of the simulation

+

Here is a reduced view of the file for the main configuration options used in swpc_synthea and their default values

+
exporter.baseDirectory = ./output/
+exporter.use_uuid_filenames = false
+exporter.subfolders_by_id_substring = false
+exporter.years_of_history = 10
+exporter.metadata.export = true
+exporter.encoding = UTF-8
+exporter.csv.export = true
+
+# the number of patients to generate, by default
+# this can be overridden by passing a different value to the Generator constructor
+generate.default_population = 5
+
+# the number of threads to use for the generator, set the value to -1 to match the number of
+# available processors (as per Runtime.getRuntime().availableProcessors())
+# defaults to -1 if not specified
+generate.thread_pool_size = -1
+
+generate.log_patients.detail = simple
+# options are "none", "simple", or "detailed" (without quotes). defaults to simple if another value is used
+# none = print nothing to the console during generation
+# simple = print patient names once they are generated.
+# detailed = print patient names, atributes, vital signs, etc..  May slow down processing
+
+generate.timestep = 604800000
+# time is in ms
+# 1000 * 60 * 60 * 24 * 7 = 604800000
+
+generate.demographics.default_file = geography/demographics.csv
+generate.geography.postcodes.default_file = geography/postcodes.csv
+generate.geography.country_code = England
+generate.geography.timezones.default_file = geography/timezones.csv
+generate.geography.foreign.birthplace.default_file = geography/foreign_birthplace.json
+generate.geography.sdoh.default_file = geography/sdoh.csv
+
+# Lookup Table Folder location
+generate.lookup_tables = modules/lookup_tables/
+
+# if criteria are provided, (for example, only_dead_patients, only_alive_patients, or a "patient keep module" with -k flag)
+# this is the maximum number of times synthea will loop over a single slot attempting to produce a matching patient.
+# after this many failed attempts, it will throw an exception.
+# set this to 0 to allow for unlimited attempts (but be aware of the possibility that it will never complete!)
+generate.max_attempts_to_keep_patient = 1000
+
+# Probability of each person having a middle name. 0 is zero, 1.0 is 100% chance.
+generate.middle_names = 0.80
+
+# if true, the entire population will use veteran prevalence data
+generate.veteran_population_override = false
+
+# these should add up to 1.0
+# weighting and categories are inspired by the following but there are no specific hard numbers to point to
+# http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1694190/pdf/amjph00543-0042.pdf
+# http://www.ncbi.nlm.nih.gov/pubmed/8122813
+generate.demographics.socioeconomic.weights.income = 0.2
+generate.demographics.socioeconomic.weights.education = 0.7
+generate.demographics.socioeconomic.weights.occupation = 0.1
+
+generate.demographics.socioeconomic.score.low = 0.0
+generate.demographics.socioeconomic.score.middle = 0.25
+generate.demographics.socioeconomic.score.high = 0.66
+
+generate.demographics.socioeconomic.education.less_than_hs.min = 0.0
+generate.demographics.socioeconomic.education.less_than_hs.max = 0.5
+generate.demographics.socioeconomic.education.hs_degree.min = 0.1
+generate.demographics.socioeconomic.education.hs_degree.max = 0.75
+generate.demographics.socioeconomic.education.some_college.min = 0.3
+generate.demographics.socioeconomic.education.some_college.max = 0.85
+generate.demographics.socioeconomic.education.bs_degree.min = 0.5
+generate.demographics.socioeconomic.education.bs_degree.max = 1.0
+
+# The average family size in the US is 3.13. The 2010 FPL for a 3-person household is $18310. Tuned it to $17550 for realistic medicaid/ACA enrollments.
+generate.demographics.socioeconomic.income.poverty = 17550
+generate.demographics.socioeconomic.income.high = 75000
+
+generate.birthweights.default_file = birthweights.csv
+generate.birthweights.logging = false
+
+# Providers
+generate.providers.hospitals.default_file = providers/hospitals.csv
+# --generate.providers.longterm.default_file = providers/longterm.csv
+# --generate.providers.nursing.default_file = providers/nursing.csv
+# --generate.providers.rehab.default_file = providers/rehab.csv
+# --generate.providers.hospice.default_file = providers/hospice.csv
+# --generate.providers.dialysis.default_file = providers/dialysis.csv
+# --generate.providers.homehealth.default_file = providers/home_health_agencies.csv
+# --generate.providers.veterans.default_file = providers/va_facilities.csv
+generate.providers.urgentcare.default_file = providers/urgent_care_facilities.csv
+generate.providers.primarycare.default_file = providers/primary_care_facilities.csv
+# --generate.providers.ihs.hospitals.default_file = providers/ihs_facilities.csv
+# --generate.providers.ihs.primarycare.default_file = providers/ihs_centers.csv
+
+# Provider selection behavior
+# How patients select a provider organization:
+#  nearest - select the closest provider. See generate.providers.maximum_search_distance
+#  random  - select randomly.
+#  network - select a random provider in your insurance network. same as random except it changes every time the patient switches insurance provider.
+#  medicare - select the nearest provider that can bill Medicare. If no Medicare provider is found, it defaults back to "nearest".
+generate.providers.selection_behavior = nearest
+
+# if a provider cannot be found for a certain type of service,
+# this will default to the nearest hospital.
+generate.providers.default_to_hospital_on_failure = true
+
+# Quit Smoking
+lifecycle.quit_smoking.baseline = 0.01
+lifecycle.quit_smoking.timestep_delta = -0.01
+lifecycle.quit_smoking.smoking_duration_factor_per_year = 1.0
+
+# Quit Alcoholism
+lifecycle.quit_alcoholism.baseline = 0.001
+lifecycle.quit_alcoholism.timestep_delta = -0.001
+lifecycle.quit_alcoholism.alcoholism_duration_factor_per_year = 1.0
+
+# Adherence
+lifecycle.adherence.baseline = 0.05
+
+# set this to true to enable randomized "death by natural causes"
+# highly recommended if "only_dead_patients" is true
+lifecycle.death_by_natural_causes = false
+
+# set this to enable "death by loss of care" or missed care,
+# e.g. not covered by insurance or otherwise unaffordable.
+# only functional if "generate.payers.loss_of_care" is also true.
+lifecycle.death_by_loss_of_care = false
+
+# Use physiology simulations to generate some VitalSigns
+physiology.generators.enabled = false
+
+# Allow physiology module states to be executed
+# If false, all Physiology state objects will immediately redirect to the state defined in
+# the alt_direct_transition field
+physiology.state.enabled = false
+
+# set to true to introduce errors in height, weight and BMI observations for people
+# under 20 years old
+growtherrors = false
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file