Add dictionaries, materials.

This commit is contained in:
Daniel Kraus 2015-06-28 09:44:33 +02:00
parent 24c58a5867
commit 39f63835be
12 changed files with 501 additions and 58 deletions

View File

@ -39,7 +39,7 @@ Die Lauris-Ausgabe wird in folgende Einheiten aufgetrennt:
strukturierter Form zur Verfügung.
## Wörterbücher
## Kanonische Namen, Materialarten, Wörterbücher
Die Bezeichnungen für einzelne Parameter und Einheiten sind bei Lauris
teilweise etwas unglücklich. Beispielsweise wird `glomerul.
@ -57,8 +57,21 @@ wirklichkeitsnähere, typographisch korrekte Einheiten übersetzen:
- `zaaReloaded2.Dictionaries.UnitDictionary`
Beide Wörterbuch-Typen laden zunächst eingebaute Default-Werte aus der
Assembly und suchen dann nach Anpassungen auf Systemebene und auf
Benutzerebene.
Assembly und suchen dann nach Anpassungen auf Benutzerebene.
### Material
Im `ParameterDictionary` wird für jeden Parameter neben dem Kanonischen
Namen auch hinterlegt, aus welchem Material er bestimmt wird. Beim
Parsen der Lauris-Ausgabe wird festgelegt, um welches Material es sich
handelt. Auf diese Weise wird ermöglicht, bei der späteren Ausgabe mit
einfacher Notation z.B. zwischen Serum-Natrium (`S-Na`) und
Urin-Natrium (`U-Na`) bzw. Sammelurin-Natrium (`SU-Na`) zu
unterscheiden.
Die Materialien sind in der Enumeration `zaaReloaded2.Models.Materials`
definiert.
### Textdateien zur Konfiguration
@ -70,8 +83,7 @@ Textdateien verwendet.
- Datensätze in Zeilen
- Felder in durch Leerzeichen getrennten Zeilen
- Leerzeichen in Werten erfordern Anführungstriche (Bsp. s.u.)
- Drei Trennstriche `---` bedeuten, daß ein von Lauris verwendeter
Wert auch für zaaReloaded2 gültig ist (Bsp. s.u.)
- Drei Trennstriche `---` markieren ein leeres Feld.
- Alles nach einer Raute `#` wird ignoriert
- Leere Zeilen werden ignoriert
@ -81,13 +93,18 @@ Textdateien verwendet.
Das `ParameterDictionary` wird aus einer Textdatei folgenden Formats
generiert:
# LAURIS-NAME "KANONISCHER NAME" KATEGORIE "IMMER REFERENZBEREICH"
"Lactat Dehydrogenase" LDH Klinische Chemie
"Cystatin C" --- Nierenfunktion X
"glomerul. Filtrationsr. CKD-EP" "eGFR (CKD-EPI)" Nierenfunktion
# LAURIS-NAME "KANONISCHER NAME" MATERIAL "IMMER REFERENZBEREICH"
"Lactat Dehydrogenase" LDH S
"Cystatin C" --- S X
"glomerul. Filtrationsr. CKD-EP" "eGFR (CKD-EPI)" S
Das Feld `MATERIAL` muß ein Material-Kürzel enthalten (zu Materialien
siehe oben). Die Material-Kürzel sind fest einprogrammiert (s.o.). Wenn
kein Material angegeben ist (in der Spalte also gar nichts steht oder
`---`), wird _Serum_ angenommen, weil das das häufigste ist.
Wenn `IMMER REFERENZBEREICH` leer ist, wird "nein" angenommen. Alles
andere wie z.B. `X` bedeute "ja".
andere wie z.B. `X` bedeutet "ja".
Die drei Trennstriche `---` in der Zeile "Cystacin C" bedeuten, daß
zaaReloaded2 den Lauris-Namen als kanonischen Namen verwenden soll.
@ -105,23 +122,6 @@ Wenn eine Lauris-Einheit nicht in dieser Tabelle enthalten ist, wird sie
so, wie sie ist, für die Ausgabe von zaaReloaded2 verwendet.
## Kategorien
Um die Definition des Ausgabeformats von zaaReloaded2 zu erleichern,
wird jeder Laborparameter beim Parsen des Lauris-Texts einer bestimmten,
fest eingebauten Kategorie zugeordnet, ähnlich wie Lauris selbst es
schon macht, nur besser. Beispielsweise werden die Werte aus
"Urinproteine quantitativ" der Kategorie "Sammelurin" zugeordnet, weil
das praktikabler und intuitiver ist. Anderes Beispiel: Unter der
Lauris-Kategorie "Serumproteine und Tumormarker" sind u.a. der
Eisenstatus, Akutphaseproteine und Sonderbestimmungen wie das Cystatin C
versammelt. Diese werden von zaaReloaded2 in die Kategorien
"Eisenstatus", "Akutphase" und "Nierenfunktion" eingeordnet.
Die Liste der Kategorien wird aus dem
`zaaReloaded2.Dictionaries.ParameterDictionary` kompiliert.
## Referenzbereiche
Wenn bei jedem Laborparameter die Referenzbereiche angegeben werden,

View File

@ -30,5 +30,10 @@ namespace Tests.Dictionaries
{
return Assembly.GetExecutingAssembly().GetManifestResourceStream("Tests.Dictionaries.test_dictionary.txt");
}
protected override string GetUserFileName()
{
return String.Empty;
}
}
}

View File

@ -1,2 +1,5 @@
# This is a test file to test dictionaries
"Field 1" "Field 2"
Hämoglobin Hb E
Natrium Na
Kalium --- S

View File

@ -1,5 +1,117 @@
# LAURIS-NAME "KANONISCHER NAME" KATEGORIE "IMMER REFERENZBEREICH"
# =========== ================== ========= =======================
"Lactat Dehydrogenase" LDH Klinische Chemie
"Cystatin C" --- Nierenfunktion X
"glomerul. Filtrationsr. CKD-EP" "eGFR (CKD-EPI)" Nierenfunktion
# LAURIS-NAME "KANONISCHER NAME" MATERIAL "IMMER REFERENZBEREICH"
# =========== ================== ======== =======================
"Lactat Dehydrogenase" LDH S
"Cystatin C" --- S X
"glomerul. Filtrationsr. CKD-EP" "eGFR (CKD-EPI)" S
Übergangsepithelien (U) --- U
a1-Microglobulin (SU) --- SU
a1-Microglobulin (SU)/die --- SU
aktuelles Bicarbonat --- BGA
Albumin (PU) --- U
Albumin (SU) --- SU
Albumin (SU)/die --- SU
Albumin --- S
Albumin/Creatinin (PU) --- U
Alk. Phosphatase --- S
Amylase --- S
anorg. Phosphat --- S
Bakterien (U) --- U
Basenabweichung --- BGA
Basophile --- E
Bilirubin (U) --- U
C-reaktives Protein --- S
Calcium (SU) --- SU
Calcium (SU)/die --- SU
Calcium --- S
Calcium-Phosphat-Produkt --- S
Cholesterin --- S
CK gesamt --- S
CK MB --- S
Creatinin (PU) --- U
Creatinin (SU) --- SU
Creatinin --- S
Creatinin-Clearance (SU)/min --- SU
Cyclosporin-A vor Gabe --- S
Cystatin C (N Latex) --- S
Eisen --- S
Eosinophile --- E
Erythrozyten (U) --- U
Erythrozyten --- E
Ferritin --- S
Gesamt-Bilirubin --- S
Gesamt-Eiweiss (PU) --- U
Gesamt-Eiweiss (SU) --- SU
Gesamt-Eiweiss (SU)/die --- SU
Gesamt-Eiweiss --- S
Gesamt-Eiweiss/Creatinin (PU) --- U
GGT --- S
glomeruläre Filtrationsrate --- SU
glomerul. Filtrationsr. (MDRD) --- S
glomerul. Filtrationsr. CKD-EP --- S
Glucose (U) --- U
Glucose --- S
GOT (ASAT) --- S
GPT (ALAT) --- S
Hämatokrit --- E
Hämoglobin --- E
Haptoglobin --- S
Harnsäure --- S
Harnstoff (SU) --- SU
Harnstoff (SU)/die --- SU
Harnstoff --- S
Harnstoff-Clearance (SU)/min --- SU
HbA1c (NGSP) --- E
HDL - Cholesterin --- S
hyaline Zylinder (U) --- U
Kalium (SU) --- U
Kalium (SU)/die --- SU
Kalium --- S
Ketonkörper (U) --- U
Lactat Dehydrogenase --- S
LDL - Cholesterin --- S
Leukozyten (U) --- U
Leukozyten --- E
Lymphozyten --- E
MCH (HbE) --- E
MCHC --- E
MCV --- E
Mittleres Plättchenvolumen --- E
Monozyten --- E
Natrium (SU) --- SU
Natrium (SU)/die --- SU
Natrium --- S
Neutrophile --- E
Nitrit (U) --- U
NT-proBNP --- S
PCO2 (art.) --- BGA
pH (U) --- U
pH --- BGA
Plattenepithelien (U) --- U
PO2 (art.) --- BGA
Protein (U) --- U
Sammelmenge (U) --- SU
Sammelzeit (U) --- SU
Sauerstoffsättigung (art.) --- BGA
Sirolimus --- S
spezifisches Gewicht (U) --- U
Standard Bicarbonat --- BGA
Tacrolimus (FK506) --- S
Thrombozyten --- E
Transferrin --- S
Transferrinsättigung --- S
Triglyceride --- S
Troponin T (high sensitive) --- S
Unreife Granulozyten --- E
Urobilinogen (U) --- U
Niedermol. Heparin (Anti-Xa) --- Z
Thromboplastinzeit n. Quick --- Z
PTT --- Z
Ratio int. norm. --- Z
Komplementfaktor C3c --- S
Komplementfaktor C4 --- S
Anti-DNAse B --- S
Anti-Streptolysin --- S
PTH intakt --- S
TSH --- S
HAPTOGLOBIN --- S
FRAGMENTOZYTEN --- E

View File

@ -1,3 +1,6 @@
# LAURIS-EINHEIT "KANONISCHE EINHEIT"
# ============== ====================
# WICHTIG: Nur direkt austauschbare Einheiten verwenden,
# weil (bislang) keine Umrechnung der Werte vorgesehen ist!
"ml/min/ 1,73qm" "ml/min/1,73 m²"
ng/ml µg/l

View File

@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace zaaReloaded2.Dictionaries
{
@ -32,16 +33,42 @@ namespace zaaReloaded2.Dictionaries
{
#region Public properties
/// <summary>
/// Gets a sorted dictionary of records. The records are sorted by the
/// first field, and each record contains the entire set of fields,
/// including the first field.
/// </summary>
public SortedDictionary<string, string[]> Records { get; protected set; }
#endregion
#region Constructor
/// <summary>
/// Constructs a new dictionary, loading default data from a built-in
/// resource, and user data from a custom file.
/// </summary>
public DictionaryBase()
{
Records = new SortedDictionary<string, string[]>();
LoadDefaultValues();
LoadUserValues();
}
#endregion
#region Public methods
/// <summary>
/// Returns true if the dictionary contains a record for
/// <paramref name="key"/>.
/// </summary>
/// <param name="key">Dictionary key to look up.</param>
/// <returns>True if a record for <paramref name="key"/>
/// exist, false if not.</returns>
public bool HasRecord(string key)
{
return Records.ContainsKey(key);
}
#endregion
@ -53,6 +80,13 @@ namespace zaaReloaded2.Dictionaries
/// </summary>
abstract protected Stream GetDefaultStream();
/// <summary>
/// Returns the file name of the text file that contains user-defined
/// values.
/// </summary>
/// <returns>File name.</returns>
abstract protected string GetUserFileName();
#endregion
#region Protected methods
@ -96,19 +130,120 @@ namespace zaaReloaded2.Dictionaries
ReadFile(sr);
}
#endregion
#region Private methods
/// <summary>
/// Loads default dictionary values from a text file that is built
/// into the assembly as an embbedded resource.
/// </summary>
private void LoadDefaultValues()
protected virtual void LoadDefaultValues()
{
ReadFile(GetDefaultStream());
}
/// <summary>
/// Attempts to load additional values from a user file whose path
/// is provided by <see cref="GetUserFileName()"/>.
/// </summary>
protected virtual void LoadUserValues()
{
try
{
FileStream fs = new FileStream(GetUserFileName(), FileMode.Open, FileAccess.Read);
ReadFile(fs);
}
catch { }
}
/// <summary>
/// Looks up a dictionary key and returns the value from the requested field,
/// or a default value if the field is empty or contains only dashes.
/// </summary>
/// <param name="key">Key to look up.</param>
/// <param name="fieldNum">Zero-based index of the field to look up
/// (note that field 0 is the key itself).</param>
/// <param name="defaultValue">Default value that will be returned
/// if the field is empty or contains only dashes.</param>
/// <returns>Value of the requested field, or <paramref name="defaultValue"/>
/// if the field is empty or contains only dashes.</returns>
/// <exception cref="System.IndexOutOfRangeException">if fieldNum is negative.</exception>
protected string LookUpValue(string key, int fieldNum, string defaultValue)
{
string[] record;
if (Records.TryGetValue(key, out record))
{
if (fieldNum >= record.Length) return defaultValue;
string value = record[fieldNum];
if (string.IsNullOrWhiteSpace(value) || _dashes.IsMatch(value))
{
return defaultValue;
}
else
{
return value;
}
}
else
{
return defaultValue;
}
}
/// <summary>
/// Looks up a dictionary key and returns the value from the requested field,
/// or an empty string if the field is empty or contains only dashes.
/// </summary>
/// <param name="key">Key to look up.</param>
/// <param name="fieldNum">Zero-based index of the field to look up
/// (note that field 0 is the key itself).</param>
/// <returns>Value of the requested field, or <see cref="String.Empty"/>
/// if the field is empty or contains only dashes.</returns>
/// <exception cref="System.IndexOutOfRangeException">if fieldNum is negative.</exception>
protected string LookUpValue(string key, int fieldNum)
{
return LookUpValue(key, fieldNum, String.Empty);
}
/// <summary>
/// Looks up a dictionary key and returns a boolean value from the requested field,
/// or a default value if the field is empty or contains only dashes.
/// </summary>
/// <remarks>
/// The following case-insensitive text values are evaluated as "true": X, Y, J, +,
/// 1, JA, TRUE, WAHR.
/// </remarks>
/// <param name="key">Key to look up.</param>
/// <param name="fieldNum">Zero-based index of the field to look up
/// (note that field 0 is the key itself).</param>
/// <param name="defaultValue">Default value that will be returned
/// if the field is empty or contains only dashes.</param>
/// <returns>Value of the requested field, or <paramref name="defaultValue"/>
/// if the field is empty or contains only dashes.</returns>
/// <exception cref="System.IndexOutOfRangeException">if fieldNum is negative.</exception>
protected bool LookUpValue(string key, int fieldNum, bool defaultValue)
{
string textValue = LookUpValue(key, fieldNum, String.Empty);
switch (textValue.ToUpper())
{
case "X":
case "Y":
case "J":
case "+":
case "1":
case "JA":
case "YES":
case "TRUE":
case "WAHR":
return true;
default:
return defaultValue;
}
}
#endregion
#region Fields
private static readonly Regex _dashes = new Regex("-+");
#endregion
}
}

View File

@ -20,6 +20,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.IO;
using zaaReloaded2.Models;
namespace zaaReloaded2.Dictionaries
{
@ -30,9 +32,74 @@ namespace zaaReloaded2.Dictionaries
/// </summary>
class ParameterDictionary : DictionaryBase
{
#region Public methods
/// <summary>
/// Looks up the canonical name for a given <paramref name="laurisName"/>.
/// </summary>
/// <param name="laurisName">Lauris item name to look up.</param>
/// <returns>Canonical name, or original Lauris name if no canonical name
/// is defined for this item.</returns>
public string GetCanonicalName(string laurisName)
{
return LookUpValue(laurisName, 1, laurisName);
}
/// <summary>
/// Looks up the material for a given <paramref name="laurisName"/>.
/// </summary>
/// <param name="laurisName">Lauris item name to look up.</param>
/// <returns><see cref="zaaReloaded2.Models.Materials"/> enum; if no material is
/// found in the dictionary, the default material "S" (serum) is returned.</returns>
public Materials GetMaterial(string laurisName)
{
string textValue = LookUpValue(laurisName, 2);
try
{
Materials m = (Materials)Enum.Parse(typeof(Materials), textValue, true);
return m;
}
catch
{
return Materials.S;
}
}
/// <summary>
/// Returns whether or not reference limits shall always
/// be displayed for a given item, regardless whether it
/// is normal or not.
/// </summary>
/// <param name="key">Laboratory item to look up; this must
/// be an original Lauris string.</param>
/// <returns></returns>
public bool GetForceReferenceDisplay(string laurisName)
{
return LookUpValue(laurisName, 3, false);
}
#endregion
#region Overrides
/// <summary>
/// Returns the resource stream for Defaults\parameters.txt.
/// </summary>
protected override System.IO.Stream GetDefaultStream()
{
return Assembly.GetExecutingAssembly().GetManifestResourceStream("");
}
return Assembly.GetExecutingAssembly().GetManifestResourceStream(
"zaaReloaded2.Defaults.parameters.txt");
}
/// <summary>
/// Returns a path to a file parameters.txt in the addin directory
/// as provided by <see cref="ThisAddin.Subdir"/>.
/// </summary>
protected override string GetUserFileName()
{
return Path.Combine(ThisAddIn.Subdir, "parameters.txt");
}
#endregion
}
}

View File

@ -19,6 +19,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
namespace zaaReloaded2.Dictionaries
{
@ -28,9 +30,43 @@ namespace zaaReloaded2.Dictionaries
/// </summary>
class UnitDictionary : DictionaryBase
{
#region Public methods
/// <summary>
/// Translates a Lauris unit into a zaaReloaded2 canonical unit.
/// If there is no canonical unit, this function returns the
/// Lauris unit as-is.
/// </summary>
/// <param name="laurisUnit">Lauris unit to translate.</param>
/// <returns>Canonical unit, or Lauris unit if no canonical
/// unit was found.</returns>
public string TranslateLaurisUnit(string laurisUnit)
{
return LookUpValue(laurisUnit, 1, laurisUnit);
}
#endregion
#region Overrides
/// <summary>
/// Returns the resource stream for Defaults\parameters.txt.
/// </summary>
protected override System.IO.Stream GetDefaultStream()
{
throw new NotImplementedException();
}
return Assembly.GetExecutingAssembly().GetManifestResourceStream(
"zaaReloaded2.Defaults.units.txt");
}
/// <summary>
/// Returns a path to a file parameters.txt in the addin directory
/// as provided by <see cref="ThisAddin.Subdir"/>.
/// </summary>
protected override string GetUserFileName()
{
return Path.Combine(ThisAddIn.Subdir, "units.txt");
}
#endregion
}
}

View File

@ -170,20 +170,11 @@ namespace zaaReloaded2.Models
/// The canonical name of this item, or the Lauris <see cref="Name"/>
/// of the item if no canonical name is known.
/// </summary>
public string CanonicalName
{
get
{
if (!string.IsNullOrEmpty(_canonicalName))
{
return _canonicalName;
}
else
{
return Name;
}
}
}
public string CanonicalName { get; private set; }
public bool AlwaysPrintLimits { get; private set; }
public Materials Material { get; private set; }
#endregion
@ -205,6 +196,24 @@ namespace zaaReloaded2.Models
ParseLauris();
}
/// <summary>
/// Creates a LabItem object from a given Lauris output, using
/// a <see cref="ParameterDictionary"/> too look up additional
/// properties (canonical name, material type, whether or not
/// to always print the reference interval).
/// </summary>
/// <param name="laurisString">Lauris output to parse.</param>
/// <param name="dictionary">ParameterDictionary that is used
/// to look up the canonical name, material type, and whether or
/// not to always print the reference interval</param>
public LabItem(string laurisString, Dictionaries.ParameterDictionary dictionary)
: this(laurisString)
{
CanonicalName = dictionary.GetCanonicalName(Name);
AlwaysPrintLimits = dictionary.GetForceReferenceDisplay(Name);
Material = dictionary.GetMaterial(Name);
}
#endregion
#region Private methods
@ -289,7 +298,6 @@ namespace zaaReloaded2.Models
#region Fields
string _canonicalName;
double _numericalValue;
double _lowerLimit;
double _upperLimit;

View File

@ -0,0 +1,59 @@
/* Materials.cs
* part of zaaReloaded2
*
* Copyright 2015 Daniel Kraus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace zaaReloaded2.Models
{
/// <summary>
/// Enumerates the known materials.
/// </summary>
enum Materials
{
[Description("Serum")]
/// Serum
S,
[Description("Plasma")]
/// Plasma
P,
[Description("EDTA-Blut")]
/// EDTA-Blut
E,
[Description("BGA")]
/// BGA
BGA,
[Description("Zitrat")]
/// Zitrat-Blut
Z,
[Description("Laktat")]
/// Laktat-Blut
L,
[Description("Urin")]
/// Urin (Spoturin)
U,
[Description("Sammelurin")]
/// Sammelurin
SU,
[Description("Sondermaterial")]
/// Sondermaterial
X
}
}

View File

@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Word;
@ -28,6 +29,19 @@ namespace zaaReloaded2
{
public partial class ThisAddIn
{
/// <summary>
/// Gets the subdirectory for addin data in the user profile directory.
/// </summary>
public static string Subdir
{
get
{
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"zaaReloaded2");
}
}
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
}

View File

@ -165,6 +165,7 @@
<Compile Include="Dictionaries\ParameterDictionary.cs" />
<Compile Include="Dictionaries\UnitDictionary.cs" />
<Compile Include="Models\LabItem.cs" />
<Compile Include="Models\Materials.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>