diff --git a/README.md b/README.md index babad9010d..02dac0cd37 100644 --- a/README.md +++ b/README.md @@ -63,20 +63,21 @@ For example: - `run_synthea Massachusetts` - `run_synthea Alaska Juneau` - `run_synthea -s 12345` - - `run_synthea -p 1000` - `run_synthea -s 987 Washington Seattle` - `run_synthea -s 21 -p 100 Utah "Salt Lake City"` - `run_synthea -m metabolic*` + - `run_synthea -m *covid19* -p 1000` COVID 19 test data Some settings can be changed in `./src/main/resources/synthea.properties`. SyntheaTM will output patient records in C-CDA and FHIR formats in `./output`. ### TCP functionality -This project has functionality added specifically for TCT which includes: +This project has functionality added specifically for TCP which includes: - Saving data to local files (now using an argument) - Sending patients directly to a FHIR server - Sending files to AWS S3 +- creating data linked to gluu inum ### Saving files locally In order to save files locally (json format) you have to add the following argument on the command line @@ -116,16 +117,16 @@ need to follow the steps to configure your programmatic access to AWS. For the Role to assume you'll need to user the entire ARN and that role has to be able to see the configured bucket. -### Adding Person generated percentage -If we want to link more than one patient to a single person (empi) we can include +### Adding patients linked to gluu inum +In order to create patients linked to a gluu inum the following flag should be added, this flag is mandatory because +it is handling the population to be created ``` --per +-gluu ,,, ``` -this parameter tells synthea to generate a percentage of persons based on the total population parameter (-p), for example -if we are sending 100 patients, and we want to generate 50% of persona, this will link 2 patients per person, the usage -would be as follows +this parameter tells synthea to generate a certain amount of ALIVE patients based on the configuration, the first name +must match with a user name being returned from the Person API ``` -run_synthea -p 100 -fhir -per 50 +run_synthea -fhir -gluu Test,1,greenday,1 ``` ### SyntheaTM GraphViz Generate graphical visualizations of SyntheaTM rules and modules. diff --git a/src/main/java/App.java b/src/main/java/App.java index c2c25fac37..4cec1c0e87 100644 --- a/src/main/java/App.java +++ b/src/main/java/App.java @@ -1,12 +1,13 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.Queue; +import java.util.*; +import org.mitre.synthea.client.IPersonService; import org.mitre.synthea.engine.Generator; import org.mitre.synthea.export.FhirR4; +import org.mitre.synthea.export.cp.IPersonFetcher; +import org.mitre.synthea.export.cp.PersonFetcher; import org.mitre.synthea.helpers.Config; /* @@ -72,16 +73,28 @@ public static void main(String[] args) throws Exception { options.saveLocally = true; }else if (currArg.equalsIgnoreCase("-s3")) { options.saveIntoS3 = true; - }else if (currArg.equalsIgnoreCase("-per")) { - FhirR4.percentage = Integer.parseInt(argsQ.poll()); + }else if (currArg.equalsIgnoreCase("-gluu")) { + String gluuData = argsQ.poll(); + String[] data = gluuData.split(","); + if((data.length%2)!=0){ + throw new Exception("Invalid gluu data."); + } + int population = 0; + Map config = new HashMap<>(); + for(int x=0;x> getPersons(); +} diff --git a/src/main/java/org/mitre/synthea/client/TCPPerson.java b/src/main/java/org/mitre/synthea/client/TCPPerson.java new file mode 100644 index 0000000000..c4a186e847 --- /dev/null +++ b/src/main/java/org/mitre/synthea/client/TCPPerson.java @@ -0,0 +1,36 @@ +package org.mitre.synthea.client; + +import com.google.gson.annotations.SerializedName; + +public class TCPPerson { + @SerializedName("last_name") + private String lastName; + @SerializedName("gluu_id") + private String gluuId; + @SerializedName("first_name") + private String firstNae; + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getGluuId() { + return gluuId; + } + + public void setGluuId(String gluuId) { + this.gluuId = gluuId; + } + + public String getFirstNae() { + return firstNae; + } + + public void setFirstNae(String firstNae) { + this.firstNae = firstNae; + } +} diff --git a/src/main/java/org/mitre/synthea/export/FhirR4.java b/src/main/java/org/mitre/synthea/export/FhirR4.java index c4d16b730c..ebf29c38e1 100644 --- a/src/main/java/org/mitre/synthea/export/FhirR4.java +++ b/src/main/java/org/mitre/synthea/export/FhirR4.java @@ -9,14 +9,7 @@ import java.awt.geom.Point2D; import java.io.IOException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; import org.hl7.fhir.r4.model.Address; @@ -126,6 +119,7 @@ import org.hl7.fhir.r4.model.codesystems.DoseRateType; import org.hl7.fhir.utilities.xhtml.NodeType; import org.hl7.fhir.utilities.xhtml.XhtmlNode; +import org.mitre.synthea.client.TCPPerson; import org.mitre.synthea.engine.Components; import org.mitre.synthea.engine.Components.Attachment; import org.mitre.synthea.helpers.Config; @@ -164,9 +158,9 @@ public class FhirR4 { private static final String UNITSOFMEASURE_URI = "http://unitsofmeasure.org"; private static final String DICOM_DCM_URI = "http://dicom.nema.org/resources/ontology/DCM"; private static final String MEDIA_TYPE_URI = "http://terminology.hl7.org/CodeSystem/media-type"; - public static int counter = 0; - public static int total = 0; - public static int percentage = 0; + + public static Map population; + public static List persons; @SuppressWarnings("rawtypes") private static final Map raceEthnicityCodes = loadRaceEthnicityCodes(); @@ -361,14 +355,20 @@ public static String convertToFHIRJson(Person person, long stopTime) { @SuppressWarnings("rawtypes") private static BundleEntryComponent basicInfo(Person person, Bundle bundle, long stopTime) { String uniqueID = null; - if (FhirR4.percentage == 0) { - uniqueID = UUID.randomUUID().toString(); - } else { - int picker = ((FhirR4.total * FhirR4.percentage) / 100); - if (FhirR4.counter == picker) { - FhirR4.counter = 0; - } - uniqueID = UUID.nameUUIDFromBytes(String.valueOf(FhirR4.counter++).getBytes()).toString(); + Optional> toProcess = + FhirR4.population.entrySet().stream().filter(e -> !e.getValue().equals(0)).findFirst(); + if (!toProcess.isPresent()) { + throw new RuntimeException("Bad configuration"); + } + + Optional personConfig = FhirR4.persons.stream().filter(p->p.getFirstNae().equals(toProcess.get().getKey())) + .findFirst(); + if(!personConfig.isPresent()){ + throw new RuntimeException("Person " + toProcess.get().getKey() + " not found"); + } + uniqueID = UUID.fromString(personConfig.get().getGluuId()).toString(); + if (person.alive(stopTime)) { + toProcess.get().setValue(toProcess.get().getValue() - 1); } Patient patientResource = new Patient(); diff --git a/src/main/java/org/mitre/synthea/export/cp/IPersonFetcher.java b/src/main/java/org/mitre/synthea/export/cp/IPersonFetcher.java new file mode 100644 index 0000000000..de461f0507 --- /dev/null +++ b/src/main/java/org/mitre/synthea/export/cp/IPersonFetcher.java @@ -0,0 +1,10 @@ +package org.mitre.synthea.export.cp; + +import org.mitre.synthea.client.TCPPerson; + +import java.io.IOException; +import java.util.List; + +public interface IPersonFetcher { + List getTcpPersons() throws IOException; +} diff --git a/src/main/java/org/mitre/synthea/export/cp/PersonFetcher.java b/src/main/java/org/mitre/synthea/export/cp/PersonFetcher.java new file mode 100644 index 0000000000..f3347d2726 --- /dev/null +++ b/src/main/java/org/mitre/synthea/export/cp/PersonFetcher.java @@ -0,0 +1,44 @@ +package org.mitre.synthea.export.cp; + +import com.google.gson.JsonObject; +import okhttp3.OkHttpClient; +import org.mitre.synthea.client.IHapiFhirService; +import org.mitre.synthea.client.IPersonService; +import org.mitre.synthea.client.TCPPerson; +import org.mitre.synthea.helpers.Config; +import retrofit2.Call; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class PersonFetcher implements IPersonFetcher { + private IPersonService personService; + + public PersonFetcher() { + OkHttpClient.Builder httpClient = new OkHttpClient.Builder() + .callTimeout(2, TimeUnit.MINUTES) + .connectTimeout(20, TimeUnit.SECONDS) + .readTimeout(2, TimeUnit.MINUTES) + .writeTimeout(30, TimeUnit.SECONDS); + Retrofit retrofit = new Retrofit.Builder() + .baseUrl(Config.get("exporter.person.api")) + .addConverterFactory(GsonConverterFactory.create()) + .client(httpClient.build()) + .build(); + this.personService = retrofit.create(IPersonService.class); + } + + public List getTcpPersons() throws IOException { + Call> res = personService.getPersons(); + Response> response = res.execute(); + if (!response.isSuccessful()) { + throw new RuntimeException("Error getting persons"); + } + return response.body(); + + } +} diff --git a/src/main/resources/synthea.properties b/src/main/resources/synthea.properties index 9cb8f218e6..0859838c32 100644 --- a/src/main/resources/synthea.properties +++ b/src/main/resources/synthea.properties @@ -1,6 +1,7 @@ # Starting with a properties file because it requires no additional dependencies exporter.fhir.fhirServer = http://localhost:8080/ +exporter.person.api = https://o5d4mbjac1.execute-api.us-east-1.amazonaws.com/ exporter.aws.role = arn:aws:iam::789379687343:role/DevDevops exporter.aws.bucket = commonhealth-synthea exporter.baseDirectory = ./output/