Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Test Infrastructure

git-svn-id: https://elmar.ips.cs.tu-bs.de/svn/arden2bytecode/trunk@5 20415b1c-3eea-de11-af57-000476a39db3
  • Loading branch information...
commit 2a7b14d2deb0db6a59e51fdabe8ef9648a3dfcac 1 parent 35de255
@dgrunwald authored
View
1  .classpath
@@ -2,5 +2,6 @@
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="bin"/>
</classpath>
View
122 src/arden/compiler/CodeGenerator.java
@@ -0,0 +1,122 @@
+package arden.compiler;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+
+import arden.codegenerator.ClassFileWriter;
+import arden.codegenerator.FieldReference;
+import arden.codegenerator.MethodWriter;
+import arden.runtime.ArdenNumber;
+import arden.runtime.ArdenString;
+import arden.runtime.MedicalLogicModuleImplementation;
+
+/**
+ * This class is responsible for generating the
+ * MedicalLogicModuleImplementation-derived class.
+ *
+ * @author Daniel Grunwald
+ */
+class CodeGenerator {
+ private String className;
+ private ClassFileWriter classFileWriter;
+ private MethodWriter staticInitializer;
+ private HashMap<String, FieldReference> stringLiterals = new HashMap<String, FieldReference>();
+ private HashMap<Double, FieldReference> numberLiterals = new HashMap<Double, FieldReference>();
+ private int nextFieldIndex;
+
+ private MethodWriter getStaticInitializer() {
+ if (staticInitializer == null) {
+ staticInitializer = classFileWriter.createStaticInitializer();
+ }
+ return staticInitializer;
+ }
+
+ /**
+ * Gets a reference to the static field that stores an ArdenString with the
+ * specified value.
+ */
+ public FieldReference getStringLiteral(String value) {
+ try {
+ FieldReference ref = stringLiterals.get(value);
+ if (ref == null) {
+ ref = classFileWriter.declareField("literal" + (nextFieldIndex++), ArdenString.class, Modifier.PRIVATE
+ | Modifier.STATIC | Modifier.FINAL);
+ stringLiterals.put(value, ref);
+ getStaticInitializer().newObject(ArdenString.class);
+ getStaticInitializer().dup();
+ getStaticInitializer().loadStringConstant(value);
+
+ getStaticInitializer().invokeConstructor(ArdenString.class.getConstructor(String.class));
+
+ getStaticInitializer().storeStaticField(ref);
+ }
+ return ref;
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets a reference to the static field that stores an ArdenNumber with the
+ * specified value.
+ */
+ public FieldReference getNumberLiteral(double value) {
+ try {
+ FieldReference ref = numberLiterals.get(value);
+ if (ref == null) {
+ ref = classFileWriter.declareField("literal" + (nextFieldIndex++), ArdenNumber.class, Modifier.PRIVATE
+ | Modifier.STATIC | Modifier.FINAL);
+ numberLiterals.put(value, ref);
+ getStaticInitializer().newObject(ArdenNumber.class);
+ getStaticInitializer().dup();
+ getStaticInitializer().loadDoubleConstant(value);
+
+ getStaticInitializer().invokeConstructor(ArdenNumber.class.getConstructor(Double.TYPE));
+
+ getStaticInitializer().storeStaticField(ref);
+ }
+ return ref;
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public CodeGenerator(String mlmName) {
+ this.className = mlmName;
+ this.classFileWriter = new ClassFileWriter(mlmName, MedicalLogicModuleImplementation.class);
+ }
+
+ /** Saves the class file */
+ public void save(DataOutput output) throws IOException {
+ classFileWriter.save(output);
+ }
+
+ /** Loads the Java class. */
+ @SuppressWarnings("unchecked")
+ public Class<? extends MedicalLogicModuleImplementation> loadClassFromMemory() {
+ byte[] data;
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream s = new DataOutputStream(bos);
+ classFileWriter.save(s);
+ s.close();
+ data = bos.toByteArray();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ try {
+ ClassLoader classLoader = new InMemoryClassLoader(className, data);
+ return (Class<? extends MedicalLogicModuleImplementation>) classLoader.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
View
144 src/arden/compiler/Compiler.java
@@ -1,122 +1,64 @@
package arden.compiler;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutput;
-import java.io.DataOutputStream;
import java.io.IOException;
-import java.lang.reflect.Modifier;
-import java.util.HashMap;
+import java.io.PushbackReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
-import arden.codegenerator.ClassFileWriter;
-import arden.codegenerator.FieldReference;
-import arden.codegenerator.MethodWriter;
-import arden.runtime.ArdenNumber;
-import arden.runtime.ArdenString;
-import arden.runtime.MedicalLogicModuleImplementation;
+import arden.compiler.analysis.DepthFirstAdapter;
+import arden.compiler.lexer.Lexer;
+import arden.compiler.lexer.LexerException;
+import arden.compiler.node.AMlm;
+import arden.compiler.node.Start;
+import arden.compiler.parser.Parser;
+import arden.compiler.parser.ParserException;
+import arden.runtime.MedicalLogicModule;
/**
- * This class is responsible for generating the
- * MedicalLogicModuleImplementation-derived class.
+ * The main class of the compiler.
*
* @author Daniel Grunwald
*/
public class Compiler {
- private String className;
- private ClassFileWriter classFileWriter;
- private MethodWriter staticInitializer;
- private HashMap<String, FieldReference> stringLiterals = new HashMap<String, FieldReference>();
- private HashMap<Double, FieldReference> numberLiterals = new HashMap<Double, FieldReference>();
- private int nextFieldIndex;
-
- private MethodWriter getStaticInitializer() {
- if (staticInitializer == null) {
- staticInitializer = classFileWriter.createStaticInitializer();
- }
- return staticInitializer;
+ public MedicalLogicModule compileMlm(Reader input) throws CompilerException, IOException {
+ List<MedicalLogicModule> output = compile(input);
+ if (output.size() != 1)
+ throw new CompilerException("Expected only a single MLM per file");
+ return output.get(0);
}
- /**
- * Gets a reference to the static field that stores an ArdenString with the
- * specified value.
- */
- public FieldReference getStringLiteral(String value) {
+ public List<MedicalLogicModule> compile(Reader input) throws CompilerException, IOException {
+ Lexer lexer = new Lexer(new PushbackReader(input, 1024));
+ Parser parser = new Parser(lexer);
+ Start syntaxTree;
try {
- FieldReference ref = stringLiterals.get(value);
- if (ref == null) {
- ref = classFileWriter.declareField("literal" + (nextFieldIndex++), ArdenString.class, Modifier.PRIVATE
- | Modifier.STATIC | Modifier.FINAL);
- stringLiterals.put(value, ref);
- getStaticInitializer().newObject(ArdenString.class);
- getStaticInitializer().dup();
- getStaticInitializer().loadStringConstant(value);
-
- getStaticInitializer().invokeConstructor(ArdenString.class.getConstructor(String.class));
-
- getStaticInitializer().storeStaticField(ref);
- }
- return ref;
- } catch (SecurityException e) {
- throw new RuntimeException(e);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException(e);
+ syntaxTree = parser.parse();
+ } catch (ParserException e) {
+ throw new CompilerException(e);
+ } catch (LexerException e) {
+ throw new CompilerException(e);
}
+ return compile(syntaxTree);
}
- /**
- * Gets a reference to the static field that stores an ArdenNumber with the
- * specified value.
- */
- public FieldReference getNumberLiteral(double value) {
- try {
- FieldReference ref = numberLiterals.get(value);
- if (ref == null) {
- ref = classFileWriter.declareField("literal" + (nextFieldIndex++), ArdenNumber.class, Modifier.PRIVATE
- | Modifier.STATIC | Modifier.FINAL);
- numberLiterals.put(value, ref);
- getStaticInitializer().newObject(ArdenNumber.class);
- getStaticInitializer().dup();
- getStaticInitializer().loadDoubleConstant(value);
-
- getStaticInitializer().invokeConstructor(ArdenNumber.class.getConstructor(Double.TYPE));
-
- getStaticInitializer().storeStaticField(ref);
+ public List<MedicalLogicModule> compile(Start syntaxTree) {
+ final ArrayList<MedicalLogicModule> output = new ArrayList<MedicalLogicModule>();
+ // find all AMlm nodes and compile each individually
+ syntaxTree.apply(new DepthFirstAdapter() {
+ @Override
+ public void caseAMlm(AMlm node) {
+ output.add(compileMlm(node));
}
- return ref;
- } catch (SecurityException e) {
- throw new RuntimeException(e);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException(e);
- }
+ });
+ return output;
}
- public Compiler(String mlmName) {
- this.className = mlmName;
- this.classFileWriter = new ClassFileWriter(mlmName, MedicalLogicModuleImplementation.class);
- }
-
- /** Saves the class file */
- public void save(DataOutput output) throws IOException {
- classFileWriter.save(output);
- }
-
- /** Loads the Java class. */
- @SuppressWarnings("unchecked")
- public Class<? extends MedicalLogicModuleImplementation> loadClassFromMemory() {
- byte[] data;
- try {
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream s = new DataOutputStream(bos);
- classFileWriter.save(s);
- s.close();
- data = bos.toByteArray();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- try {
- ClassLoader classLoader = new InMemoryClassLoader(className, data);
- return (Class<? extends MedicalLogicModuleImplementation>) classLoader.loadClass(className);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(e);
- }
+ public MedicalLogicModule compileMlm(AMlm node) {
+ System.out.println(node.toString());
+ node.apply(new PrintTreeVisitor(System.out));
+
+
+ return null;
}
}
View
18 src/arden/compiler/CompilerException.java
@@ -0,0 +1,18 @@
+package arden.compiler;
+
+/**
+ * This exception is used to report compiler errors.
+ *
+ * @author Daniel Grunwald
+ */
+public class CompilerException extends Exception {
+ private static final long serialVersionUID = -4674298085134149649L;
+
+ public CompilerException(Throwable innerException) {
+ super(innerException);
+ }
+
+ public CompilerException(String message) {
+ super(message);
+ }
+}
View
34 src/arden/compiler/PrintTreeVisitor.java
@@ -0,0 +1,34 @@
+package arden.compiler;
+
+import java.io.PrintStream;
+
+import arden.compiler.analysis.DepthFirstAdapter;
+import arden.compiler.node.Node;
+
+public class PrintTreeVisitor extends DepthFirstAdapter {
+ PrintStream out;
+ int indentation;
+
+ public PrintTreeVisitor(PrintStream out) {
+ if (out == null)
+ throw new IllegalArgumentException();
+ this.out = out;
+ }
+
+ private void indent() {
+ for (int i = 0; i < indentation; i++)
+ out.print('\t');
+ }
+
+ @Override
+ public void defaultIn(Node node) {
+ indent();
+ out.println(node.getClass().getName());
+ indentation++;
+ }
+
+ @Override
+ public void defaultOut(Node node) {
+ indentation--;
+ }
+}
View
18 src/arden/runtime/MedicalLogicModule.java
@@ -21,10 +21,9 @@ public MedicalLogicModule(Class<? extends MedicalLogicModuleImplementation> claz
public MedicalLogicModuleImplementation createInstance(ExecutionContext context) throws InvocationTargetException {
if (context == null)
throw new IllegalArgumentException();
-
+
// We know the class has an appropriate constructor because we compiled
- // it,
- // so wrap all the checked exceptions that should never occur.
+ // it, so wrap all the checked exceptions that should never occur.
Constructor<? extends MedicalLogicModuleImplementation> ctor;
try {
ctor = clazz.getConstructor(ExecutionContext.class);
@@ -43,4 +42,17 @@ public MedicalLogicModuleImplementation createInstance(ExecutionContext context)
throw new RuntimeException(e);
}
}
+
+ public ArdenValue run(ExecutionContext context) throws InvocationTargetException
+ {
+ MedicalLogicModuleImplementation impl = createInstance(context);
+ try {
+ if (impl.logic(context))
+ return impl.action(context);
+ else
+ return ArdenNull.INSTANCE;
+ } catch (Exception ex) {
+ throw new InvocationTargetException(ex);
+ }
+ }
}
View
3  src/arden/runtime/MedicalLogicModuleImplementation.java
@@ -14,4 +14,7 @@ public MedicalLogicModuleImplementation(ExecutionContext context) {
if (context == null)
throw new IllegalArgumentException();
}
+
+ public abstract boolean logic(ExecutionContext context);
+ public abstract ArdenValue action(ExecutionContext context);
}
View
30 src/arden/tests/ActionTemplate.mlm
@@ -0,0 +1,30 @@
+maintenance:
+ title: Test;;
+ mlmname: test_mlm;;
+ arden: Version 2;;
+ version: 1.00;;
+ institution: TU Braunschweig;;
+ author: Daniel Grunwald;;
+ specialist: ;;
+ date: 2009-12-23;;
+ validation: testing;;
+library:
+ purpose:
+ Template for unit tests;;
+ explanation:
+ This MLM is used for several unit tests.;;
+ keywords:
+ Test Purpose;;
+ citations:
+ ;;
+knowledge:
+ type: data-driven;;
+ data: ;;
+evoke: /* this MLM is called directly */;;
+logic:
+ conclude true;
+ ;;
+action:
+ $ACTION
+ ;;
+end:
View
49 src/arden/tests/CompilerTests.java
@@ -0,0 +1,49 @@
+package arden.tests;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+
+import arden.compiler.Compiler;
+import arden.compiler.CompilerException;
+import arden.runtime.MedicalLogicModule;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CompilerTests {
+ private static String inputStreamToString(InputStream in) throws IOException {
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
+ StringBuilder stringBuilder = new StringBuilder();
+
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ stringBuilder.append(line);
+ stringBuilder.append("\n");
+ }
+
+ bufferedReader.close();
+ return stringBuilder.toString();
+ }
+
+ public MedicalLogicModule parseAction(String actionCode) throws CompilerException {
+ try {
+ InputStream s = CompilerTests.class.getResourceAsStream("ActionTemplate.mlm");
+ String fullCode = inputStreamToString(s).replace("$ACTION", actionCode);
+ Compiler c = new Compiler();
+ return c.compileMlm(new StringReader(fullCode));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void SimpleWrite() throws Exception {
+ TestContext context = new TestContext();
+ MedicalLogicModule mlm = parseAction("write \"Hello, World\"");
+ mlm.run(context);
+ Assert.assertEquals("Hello, World\n", context.getOutputText());
+ }
+}
View
24 src/arden/tests/TestContext.java
@@ -0,0 +1,24 @@
+package arden.tests;
+
+import arden.runtime.ArdenValue;
+import arden.runtime.ExecutionContext;
+
+public class TestContext implements ExecutionContext {
+
+ @Override
+ public ArdenValue read(String query) {
+ throw new RuntimeException("Unexpected read");
+ }
+
+ StringBuilder b = new StringBuilder();
+
+ @Override
+ public void write(String message) {
+ b.append(message);
+ b.append("\n");
+ }
+
+ public String getOutputText() {
+ return b.toString();
+ }
+}
View
64 src/arden/tests/x2.1.mlm
@@ -0,0 +1,64 @@
+maintenance:
+ title: Fractional excretion of sodium;;
+ mlmname: fractional_na;;
+ arden: Version 2;;
+ version: 1.00;;
+ institution: Columbia-Presbyterian Medical Center;;
+ author: George Hripcsak, M.D.(hripcsak@cucis.cis.columbia.edu);;
+ specialist: ;;
+ date: 1991-03-13;;
+ validation: testing;;
+library:
+ purpose:
+ Calculate the fractional excretion of sodium whenever urine electrolytes are stored. (This MLM demonstrates data interpretation across independent laboratory results.);;
+ explanation:
+ The fractional excretion of sodium is calculated from the urine sodium and creatinine and the most recent serum sodium and creatinine (where they occurred within the past 24 hours). A value less than 1.0 % is considered low.;;
+ keywords: fractional excretion, serum sodium, azotemia;;
+ citations:
+ 1. Steiner RW. Interpreting the fractional excretion of sodium. Am J Med 1984:77:699-702.;;
+knowledge:
+ type: data-driven;;
+ data:
+ let (urine_na, urine_creat) be read last ({urine electrolytes where evoking} where they occurred within past 24 hours) ;
+ let (serum_na, serum_creat) be read last ({serum electrolytes where they are not null}where they occurred within past 24 hours) ;
+ let urine_electrolyte_storage be event {storage of urine electrolytes}
+ ;;
+evoke:
+ urine_electrolyte_storage;;
+logic:
+ /* calculate fractional excretion of sodium */
+ let fractional_na be 100 * (urine_na / urine_creat)/
+ (serum_na / serum_creat) ;
+ /* if the frational Na is invalid (e.g., if the */
+ /* urine or serum sample is QNS) then stop here */
+ if fractional_na is null then
+ conclude false ;
+ endif ;
+ /* check whether the fractional Na is low */
+ let low_fractional_na be fractional_na < 1.0 ;
+ /* send the message */
+ conclude true;
+ ;;
+ action:
+ if low_fractional_na then
+ write "The calculated fractional excretion of sodium is low ("
+ || fractional_na || "). If the patient is azotemic, " ||
+ "this number may indicate: volume depletion, " ||
+ "hepatic failure, congestive heart failure, acute " ||
+ "glomerulonephritis, oliguric myoglobinuric or " ||
+ "hemoglobinuric renal failure, oliguric contrast " ||
+ "nephrotoxicity, polyuric renal failure with severe " ||
+ "burns, renal transplant rejection, 10 % of cases " ||
+ "with non-oliguric acute tubular necrosis, and " ||
+ "several other forms of renal injury.";
+ else
+ write "The calculated fractional excretion of sodium is " ||
+ "not low (" || fractional_na || "). If the patient " ||
+ "is azotemic, this may indicate: acute renal " ||
+ "parenchymal injury, volume depletion coexisting " ||
+ "with diurectic use or pre-existing chronic renal " ||
+ "disease, and up to 10 % of cases of uncomplicated " ||
+ "volume depletion.";
+ endif;
+ ;;
+end:
View
96 src/arden/tests/x2.2.mlm
@@ -0,0 +1,96 @@
+maintenance:
+ title: Screen for hypercalcemia for Dr. B.'s study;;
+ mlmname: hypercalcemia_for_b;;
+ arden: Version 2;;
+ version: 2.02;;
+ institution: Columbia-Presbyterian Medical Center;;
+ author: George Hripcsak, M.D.;;
+ specialist: ;;
+ date: 1990-12-04;;
+ validation: research;;
+library:
+ purpose:
+ Screen for hypercalcemia for Dr. B.'s study. (This MLM demonstrates screening patients for clinical trials.);;
+ explanation:
+ The storage of a serum calcium value evokes this MLM. If a serum albumin is available from the same blood sample as the calcium, then the corrected calcium is calculated, and patients with actual or corrected calcium greater than or equal 11.5 are accepted; if such a serum albumin is not available, then patients with actual calcium greater than or equal 11.0 are accepted. Patients with serum creatinine greater than 6.0 are excluded from the study.;;
+ keywords: hypercalcemia;;
+ citations: ;;
+knowledge:
+ type: data-driven;;
+ data:
+ /* the storage of a calcium value evokes this MLM */
+ storage_of_calcium := event {'06210519','06210669'} ;
+ /* total calcium in mg/dL */
+ calcium := read last {'06210519','06210669';'CALCIUM'} ;
+ /* albumin in g/dL */
+ evoking_albumin := read last {'06210669';'ALBUMIN' where evoking} ;
+ /* albumin in g/dL; not necessarily from same test as Ca */
+ last_albumin := read last ({'06210669';'ALBUMIN'}
+ where it occurred within past 2 weeks) ;
+ /* creatinine in mg/dL; not necessarily from same test as Ca */
+ creatinine := read last ({'06210669','06210545','06000545';'CREAT'}
+ where it occurred within past 2 weeks) ;
+ ;;
+evoke:
+ storage_of_calcium;;
+logic:
+ /* make sure the Ca is present (vs. hemolyzed, ...) */
+ IF calcium is not present THEN
+ conclude false ;
+ ENDIF ;
+ /* if creatinine is present and greater than 6, then stop now */
+ IF creatinine is present THEN
+ IF creatinine is greater than 6.0 THEN
+ conclude false ;
+ ENDIF ;
+ ENDIF ;
+ /* is an albumin present for the same sample as the calcium */
+ IF evoking_albumin is present THEN
+ /* calculate the corrected calcium */
+ IF evoking_albumin is less than 4.0 THEN
+ corrected_calcium := calcium + (4.0-evoking_albumin)*0.8 ;
+ ELSE
+ /* corrected is never less than actual */
+ corrected_calcium := calcium ;
+ ENDIF ;
+ /* test for total or corrected calcium >= 11.5 */
+ IF calcium >= 11.5 OR corrected_calcium >= 11.5 THEN
+ message1 := "calcium = " || calcium || " on " || time of calcium || " (corrected calcium = " || corrected_calcium || ")" ;
+ message1 := message1||" ; albumin = "||evoking_albumin ;
+ IF creatinine is present THEN
+ message1 := message1||
+ " ; last creatinine = "||creatinine ;
+ message1 := message1||
+ " ; (total or corrected calcium " ||
+ "was at least 11.5)" ;
+ conclude true ;
+ ELSE
+ conclude false ;
+ ENDIF ;
+ ENDIF;
+ /* no evoking albumin was present */
+ ELSE
+ /* check for true calcium >= 11.0 */
+ IF calcium >= 11.0 THEN
+ message1 := "calcium = "||calcium||" on "||time of calcium ;
+ IF last_albumin is present THEN
+ message1 := message1||" ; last albumin "||
+ "(not from same blood sample as calcium) = "||
+ last_albumin ;
+ IF creatinine is present THEN
+ message1 := message1|| " ; last creatinine = "
+ ||creatinine ;
+ message1 := message1||
+ " ; (total calcium was at least 11.0; "||
+ "corrected calcium was not calculated)" ;
+ conclude true ;
+ ELSE
+ conclude false ;
+ ENDIF ;
+ ENDIF ;
+ ENDIF ;
+ ENDIF ;
+ ;;
+ action: write "hypercalcemia study: " || message1;;
+ urgency: 50;;
+end:
View
37 src/arden/tests/x2.3.mlm
@@ -0,0 +1,37 @@
+maintenance:
+ title: Check for penicillin allergy;;
+ mlmname: pen_allergy;;
+ arden: ;;
+ version: 1.00;;
+ institution: Columbia-Presbyterian Medical Center;;
+ author: George Hripcsak, M.D.;;
+ specialist: ;;
+ date: 1991-03-18;;
+ validation: testing;;
+library:
+ purpose:
+ When a penicillin is prescribed, check for an allergy. (This MLM demonstrates checking for contraindications.);;
+ explanation:
+ This MLM is evoked when a penicillin medication is ordered. An alert is generated because the patient has an allergy to penicillin recorded.
+ ;;
+ keywords: penicillin; allergy;;
+ citations: ;;
+knowledge:
+ type: data-driven;;
+ data:
+ /* an order for a penicillin evokes this MLM */
+ penicillin_order := event {medication_order where class = penicillin};
+ /* find allergies */
+ penicillin_allergy := read last {allergy where agent_class = penicillin};
+ ;;
+ evoke:
+ penicillin_order;;
+ logic:
+ if exist(penicillin_allergy)then
+ conclude true;
+ endif;
+ ;;
+ action:
+ write "Caution, the patient has the following allergy to penicillin documented: " || penicillin_allergy;;
+ urgency: 50;;
+end:
View
67 src/arden/tests/x2.4.mlm
@@ -0,0 +1,67 @@
+maintenance:
+ title: Dosing for gentamicin in renal failure;;
+ mlmname: gentamicin_dosing;;
+ arden: ;;
+ version: 1.00;;
+ institution: Columbia-Presbyterian Medical Center;;
+ author: George Hripcsak, M.D.;;
+ specialist: ;;
+ date: 1991-03-18;;
+ validation: testing;;
+library:
+ purpose:
+ Suggest an appropriate gentamicin dose in the setting of renal insufficiency. (This MLM demonstrates a management suggestion.);;
+ explanation:
+ Patients with renal insufficiency require the same loading dose of gentamicin as those with normal renal function, but they require a reduced daily dose. The creatinine clearance is calculated by serum creatinine, age, and weight. If it is less than 30 ml/min, then an appropriate dose is calculated based on the clearance. If the ordered dose differs from the calculated dose by more than 20 %, then an alert is generated.;;
+ keywords: gentamicin; dosing;;
+ citations: ;;
+knowledge:
+ type: data-driven;;
+ data:
+ /* an order for gentamicin evokes this MLM */
+ gentamicin_order := event {medication_order where class = gentamicin} ;
+ /* gentamicin doses */
+ (loading_dose,periodic_dose,periodic_interval) :=
+ read last {medication_order initial dose, periodic dose, interval} ;
+ /* serum creatinine mg/dl */
+ serum_creatinine := read last ({serum_creatinine}
+ where it occurred within past 1 week) ;
+ /* birthdate */
+ birthdate := read last {birthdate} ;
+ /* weight kg */
+ weight := read last ({weight}
+ where it occurred within past 3 months) ;
+ ;;
+evoke:
+ gentamicin_order;;
+logic:
+ age := (now - birthdate)/1 year ;
+ creatinine_clearance := (140 - age) * (weight)/
+ (72 * serum_creatinine) ;
+ /* the algorithm can be adjusted to handle higher clearances */
+ if creatinine_clearance < 30 then
+ calc_loading_dose := 1.7 * weight ;
+ calc_daily_dose := 3 * (0.05 + creatinine_clearance / 100) ;
+ ordered_daily_dose := periodic_dose *
+ periodic_interval/(1 day) ;
+ /* check whether order is appropriate */
+ if (abs(loading_dose - calc_loading_dose)/
+ calc_loading_dose > 0.2)
+ or
+ (abs(ordered_daily_dose - calc_daily_dose)/
+ calc_daily_dose > 0.2)then
+ conclude true ;
+ endif ;
+ endif ;
+ ;;
+ action:
+ write "Due to renal insufficiency, the dose of gentamicin " ||
+ "should be adjusted. The patient's calculated " ||
+ "creatinine clearance is " || creatinine_clearance ||
+ " ml/min. A single loading dose of " ||
+ calc_loading_dose || " mg should be given, followed by " ||
+ calc_daily_dose || " mg daily. Note that dialysis may " ||
+ "necessitate additional loading doses."
+ ;;
+ urgency: 50;;
+end:
View
61 src/arden/tests/x2.5.mlm
@@ -0,0 +1,61 @@
+maintenance:
+ title: Monitor renal function while taking gentamicin;;
+ mlmname: gentamicin_monitoring;;
+ arden: Version 2;;
+ version: 1.00;;
+ institution: Columbia-Presbyterian Medical Center;;
+ author: George Hripcsak, M.D.;;
+ specialist: ;;
+ date: 1991-03-19;;
+ validation: testing;;
+library:
+ purpose:
+ Monitor the patient's renal function when the patient is taking gentamicin. (This MLM demonstrates periodic monitoring.);;
+ explanation:
+ This MLM runs every five days after the patient is placed on gentamicin until the medication is stopped. If the serum creatinine has not been checked recently, then an alert is generated requesting follow-up. If the serum creatinine has been checked, is greater than 2.0, and has risen by more than 20 %, then an alert is generated warning that the patient may be developing renal insufficiency due to gentamicin.;;
+ keywords: gentamicin; renal function;;
+ citations: ;;
+knowledge:
+ type: data-driven;;
+ data:
+ /* an order for gentamicin evokes this MLM */
+ gentamicin_order := event {medication_order where class = gentamicin};
+ /* check whether gentamicin has been discontinued */
+ gentamicin_discontinued :=
+ read exist({medication_cancellation where class = gentamicin}
+ where it occurs after eventtime);
+ /* baseline serum creatinine mg/dl */
+ baseline_creatinine := read last ({serum_creatinine}
+ where it occurred before eventtime);
+ /* followup serum creatinine mg/dl */
+ recent_creatinine := read last ({serum_creatinine}
+ where it occurred within past 3 days);
+ ;;
+ evoke:
+ every 5 days for 10 years starting 5 days after time of
+ gentamicin_order until gentamicin_discontinued;;
+ logic:
+ if recent_creatinine is not present then
+ no_recent_creatinine := true;
+ conclude true;
+ else
+ no_recent_creatinine := false;
+ if % increase of (serum_creatinine,
+ recent_creatinine) > 20 /* % */
+ and recent_creatinine > 2.0 then
+ conclude true;
+ endif;
+ endif;
+ ;;
+action:
+ if no_recent_creatinine then
+ write "Suggest obtaining a serum creatinine to follow up " ||
+ "on renal function in the setting of gentamicin.";
+ else
+ write "Recent serum creatinine (" || recent_creatinine ||
+ " mg/dl) has increased, possibly due to renal " ||
+ "insufficiency related to gentamicin use.";
+ endif;
+ ;;
+ urgency: 50;;
+end:
View
47 src/arden/tests/x2.6.mlm
@@ -0,0 +1,47 @@
+maintenance:
+ title: Granulocytopenia and Trimethoprim/Sulfamethoxazole;;
+ mlmname: anctms;;
+ arden: Version 2;;
+ version: 2.00;;
+ institution: Columbia-Presbyterian Medical Center;;
+ author: George Hripcsak, M.D.;;
+ specialist: ;;
+ date: 1991-05-28;;
+ validation: testing;; library:
+ purpose:
+ Detect granulocytopenia possibly due to trimethoprim/sulfamethoxazole;;
+ explanation:
+ This MLM detects patients that are currently taking trimethoprim/sulfamethoxazole whose absolute neutrophile count is less than 1000 and falling.;;
+ keywords:
+ granulocytopenia; agranulocytosis; trimethoprim; sulfamethoxazole;;
+ citations:
+ 1. Anti-infective drug use in relation to the risk of agranulocytosis and aplastic anemia. A report from the International Agranulocytosis and Aplastic Anemia Study. Archives of Internal Medicine, May 1989, 149(5):1036-40.;;
+ links:
+ OTHER_LINK "CTIM" '.34.56.78';
+ MESH_LINK "MeSH" 'agranulocytosis/ci and sulfamethoxazole/ae';;
+knowledge:
+ type: data-driven;;
+ data:
+ /* capitalized text within curly brackets would be replaced with */
+ /* an institution's own query */
+ let anc_storage be event {STORAGE OF ABSOLUTE_NEUTROPHILE_COUNT};
+ let anc be read last 2 from ({ABSOLUTE_NEUTROPHILE_COUNT}
+ where they occurred within past 1 week);
+ let pt_is_taking_tms be read exist
+ {TRIMETHOPRIM_SULFAMETHOXAZOLE_ORDER};
+ ;;
+evoke: anc_storage;;
+ logic:
+ if pt_is_taking_tms
+ and last anc is less than 1000
+ and last anc is less than first anc
+ /* is anc falling? */
+ then
+ conclude true;
+ else
+ conclude false;
+ endif;;
+ action:
+ write "Caution: patient's relative granulocytopenia may be " ||
+ "exacerbated by trimethoprim/sulfamethoxazole.";;
+end:
View
75 src/arden/tests/x2.7.mlm
@@ -0,0 +1,75 @@
+maintenance:
+ title: Cardiology MLM from CARE, p. 85;;
+ mlmname: care_cardiology_mlm;;
+ arden: Version 2;;
+ version: 1.00;;
+ institution: Regenstrief Institute;;
+ author: Clement J. McDonald, M.D.; George Hripcsak, M.D.;;
+ specialist: ;;
+ date: 1991-05-28;;
+ validation: testing;;
+library:
+ purpose:
+ Recommend higher beta-blocker dosage if it is currently low and the patient is having excessive angina or premature ventricular beats.;;
+ explanation:
+ If the patient is not bradycardic and is taking less than 360 mg of propanolol or less than 200 mg of metoprolol, then if the patient is having more than 4 episodes of angina per month or more than 5 premature ventricular beats per minute, recommend a higher dose.;;
+ keywords:
+ beta-blocker, angina; premature ventricular beats; bradycardia;;
+ citations:
+ 1. "McDonald CJ. Action-oriented decisions in ambulatory medicine. Chicago: Year Book Medical Publishers, 1981, p. 85.";
+ 2. "Prichard NC, Gillam PM. Assessment of propranolol in angina pectoris: clinical dose response curve and effect on electrocardiogram at rest and on exercise. Br Heart J, 33:473-480 (1971).";
+ 3. "Jackson G, Atkinson L, Oram S. Reassessment of failed beta-blocker treatment in angina pectoris by peak exercise heart rate measurements. Br Med J, 3:616-619 (1975).";
+ ;;
+knowledge:
+ type: data-driven;;
+ data:
+ let last_clinic_visit be read last {CLINIC_VISIT};
+ let (beta_meds,beta_doses,beta_statuses) be read
+ {MEDICATION,DOSE,STATUS where the beta_statuses are 'current' and beta_meds are a kind of 'beta_blocker'};
+ let low_dose_beta_use be false;
+ /* if patient is on one beta blocker, check if it is low dose */
+ if count of beta_meds = 1 then
+ if (last beta_meds = "propanolol"
+ and
+ last beta_doses < 360)
+ or (last beta_meds = "metoprolol"
+ and
+ last beta_doses <= 200) then
+ let low_dose_beta_use be true;
+ endif;
+ endif;
+ let cutoff_time be maximum of
+ ((1 month ago),(time of last_clinic_visit),
+ (time of last beta_meds));
+ /* a system-specific query to angina frequency, PVC frequency, */
+ /* and pulse rate would replace capitalized terms */
+ let angina_frequency be read last ({ANGINA_FREQUENCY}
+ where it occurred after cutoff_time);
+ let premature_beat_frequency be read last
+ ({PREMATURE_BEAT_FREQUENCY}
+ where it occurred after cutoff_time);
+ let last_pulse_rate be read last {PULSE_RATE};
+ ;;
+evoke: /* this MLM is called directly */;;
+logic:
+ if last_pulse_rate is greater than 60 and
+ low_dose_beta_use then
+ if angina_frequency is greater than 4 then
+ let message1 be
+ "Increased dose of beta blockers may be "||
+ "needed to control angina.";
+ conclude true;
+ else
+ if premature_beat_frequency is greater than 5 then
+ let message1 be
+ "Increased dose of beta blockers may "||
+ "be needed to control PVC's.";
+ conclude true;
+ endif;
+ endif;
+ endif;
+ conclude false;
+ ;;
+action:
+ write message1;;
+end:
View
63 src/arden/tests/x2.8.mlm
@@ -0,0 +1,63 @@
+maintenance:
+ title: Allergy_test_with_while_loop;;
+ filename: test_for_allergies_while_loop;;
+ version: 0.00;;
+ institution: ;;
+ author: ;;
+ specialist: ;;
+ date: 1997-11-06;;
+ validation: testing;;
+library:
+ purpose:
+ Illustrates the use of a WHILE-LOOP that processes an entire list
+ ;;
+ explanation:
+ ;;
+ keywords:
+ ;;
+knowledge:
+ type: data-driven;;
+ data:
+ /* Receives four arguments from the calling MLM: */
+ (med_orders,
+ med_allergens,
+ patient_allergies,
+ patient_reactions) := ARGUMENT;
+ ;;
+ evoke:
+ ;;
+ logic:
+ /* Initializes variables */
+ a_list:= ();
+ m_list:= ();
+ r_list:= ();
+ num:= 1;
+ /* Checks each allergen in the medications to determine */
+ /* if the patient is allergic to it */
+ while num <= (count med_allergen) do
+ allergen:= last(first num from med_allergens);
+ allergy_found:= (patient_allergies = allergen);
+ reaction:= patient_reactions where allergy_found;
+ medication:= med_orders where (med_allergens = allergen);
+
+ /* Adds the allergen, medication, and reaction to */
+ /* variables that will be returned to the calling MLM */
+ If any allergy_found then
+ a_list:= a_list, allergen;
+ m_list:= m_list, medication;
+ r_list:= r_list, reaction;
+ endif;
+ /* Increments the counter that is used to stop the while-loop */
+ num:= num + 1 ;
+ enddo;
+ /* Concludes true if the patient is allergic to one of */
+ /* the medications */
+ If exist m_list
+ then conclude true;
+ endif;
+ ;;
+ action:
+ /* Returns three lists to the calling MLM */
+ return m_list, a_list, r_list;
+ ;;
+end:
Please sign in to comment.
Something went wrong with that request. Please try again.