Wednesday, November 4, 2015

Web Services and Web Resources

We are frequently asked about DRG assignment as a web service or a web resource.

Our standard response is that you could easily make your own DRG assigning web service or web resource using either DRGFilt or one of our embeddable DRG Assignment Engines (DAEs).

We have not ever published such a thing because we assumed that our clients would want control over the details. However we have some proof-of-concept projects which we may be making into projects over the next few months or years.

WEB HELPER
A web helper is an app which provides functionality to a particular CGI script or dynamic web page. We confirmed that DRGFilt works as a helper when we wrapped DRGFilt in a perl script to create our on-line demo, which is accessible here.

WEB RESOURCE
 A web resource is an app which can be accessed by any CGI script or dynamic web page using HTTP; the caller then processes the output as required. We are playing with the following API to access a thin wrapper on DRGFilt, with the output coming back as XML:

http://yourhost/cgi-bin/daeres.cgi?sex=1&age=55&ds=1&exempt=Z&dxs=B5881,I1201&poas=Y,&procs=0210093,02UG3JZ

<drggrouping>
  <grc>0</grc>
  <drg>231</drg>
  <mdc>5</drg>
  <morp>P</morp>
  <desc>CORONARY BYPASS W PTCA W MC</desc>
  <weight>78.0560</weight>
  <gmlos>9.90</gmlos>
  <version>33</version>
</drggrouping>

WEB SERVICE
A web service i a web app which follows input and output standards to ensure interoperability. We are looking at SOAP and company to try out a DRG assigning service and using this tutorial as a guide:

http://www.w3schools.com/xml/xml_services.asp

Friday, October 30, 2015

Support for 32-bit Linux in V33

In the Windows world we ship 32-bit DLLs because we count on "thunking" to allow this code to run in either 64-bit or 32-bit environments. But we do plan on upgrading our Windows development environment to 64-bit in the next four years.

In the Linux world we planned to drop 32-bit support with v33 (Oct-2015) but found that too many people still run 32-bit Linux, so we added 32-bit versions to all of our programmer tools:

  • our PHP module (phpdrgv33_32bit.so)
  • our Perl module (perldrgv33_32bit.so)
  • our C-callable object (libdrgv33_32bit.so)
  • DRGFilt (drgfiltv33_32bit)
We named the 32-bit versions by adding "_32bit" to the end of the file name and therefore before the extension. If you buy any of these modules, you get both the 32-bit and 64-bit versions. If you are in a 32-bit environment, you can either rename the object or call the 32-bit version explicitly.

Wednesday, October 28, 2015

DRGFilt and CGI (Web UI)

With our new DRGFilt control file format it seemed that one could use DRGFilt as a Web page helper app. In other words, we figured it should be easy to call DRGFilt from a CGI script to add DRG assignment to a web page. So we allocated a couple of hours to put that theory to the test and ended up with a fully functional web-based interactive grouper.

We were especially interested in this experiment because we use web-based interactive groupers internally, mostly for debugging specific cases because it is easier for a customer service person to use a web page than to use DRGFilt directly for a single case. We were looking to replace our old CGI-DRG product because we did not want to maintain it in the ICD10 world.

Step 1: we created a simple and lightweight Perl script to provide a basic HTML form and to call DRGFilt which we called "drgui.pl" for "DRG User Interface" and which we eventually made publicly available here.

Step 2: we created a DRGFilt control file group to do CGI, which we cleverly called "cgi":

; this group was added to support drgfilt-as-CGI helper
[cgi]
verbose = 0;
format = csv (^)        ; separator character is in parens
base = 0                ; indices are zero-based
inheaders = 0           ; 1=input column headers, 0=no input column headers
outheaders = 0          ; 1=want column headers, 0=no headers
crlf = 0                ; type of end-of-line: either crlf or lf
blip = 1                ; want something in the log
blipeol = 1             ; 1=newline for progress report, 0=carriage return
batchver = 33
maskdir = /var/www/cgi-bin/drgstuff
log = /tmp/me.out

; input variables: name = index
inid = 0
age =  1
sex = 2
exmp = 3
ds =  4
dx = 5-29
poa = 30-54
surg= 55-79

; these are written out by DRGFilt
rc  = 0
mdc = 1
drg = 2
outver = 3
weight = 4
mean = 5
morp = 6
desc = 7
dflg = 8                ; string of flags for which dx codes were used
sflg = 9                ; string of flags for which pr codes were used
; eof


Step 3: we created some simple plumbing from drgui.pl to DRGFilt (send the input via stdin, read the output via stdout):

my @i = ();
push(@i,0);                     # 0: the record ID
push(@i,$vars{'age'});          # 1: patient age on admission
push(@i,$vars{'sex'});          # 2: patient sex (1=male, 2=female)
push(@i,$vars{'exempt'});       # 3: exempt
push(@i,$vars{'dstat'});        # 4: discharge status (home)
for (my $i = 0; $i < 25; $i++) {# 6-29: ICD DX codes
    my $icd = substr($dx,$i*7,7);
    $icd =~ s/\s+$//;
    push(@i,$icd);
}
for (my $i = 0; $i < 25; $i++) {# 30-54: POA codes
    push(@i,substr($poa,$i,1));
}
for (my $i = 0; $i < 25; $i++) {# 55-79: ICD procedure codes
    my $icd = substr($px,$i*7,7);
    $icd =~ s/\s+$//;
    push(@i,$icd);
}
my $inrec = join('^',@i);

open(PIPE,"/bin/echo \"$inrec\" | $MYDIR/drgfiltv33 -v -l /tmp/me.out $MYDIR/v33.ini cgi|");
my $retval = <PIPE>;
($rc,$mdc,$drg,$ovn,$weight,$mean,$porm,$desc,$dxu,$pru) = split(/\^/,$retval,-1);


Step 4: pick a test case from the CMS data set and try it out:

[       2]-------------------------------------------
   Age: 055   
   Sex: M   
  Disp: 01

  Exem: Z (Exempt-from-HAC indicator)

   DRG: 231    
   MDC: 05    
   GRC: 00

  DX's| Code    |POA indicator
 -----+--------------
  DX01| B5881   |Y
  DX02| I2101   |

Proc's| Code
 -----+---------------------
  SG01| 0210093
  SG02| 02UG3JZ


Step 5: declare success and decide to put this out on the web so that our customers can debug issues with their own installations.

Tuesday, October 27, 2015

DAE Return Codes (Error reporting)

It has come to our attention that the Grouper Return Code (GRC) documentation did not survive the transition to the new web site, so we will include it here (where it probably should have been all along).

Code Description Code Description
1Bad principal diagnosis 6Unspecified DRG error
2Bad prin dx for MDC 7Invalid prin diagnosis
3Invalid age 8No DRG file this version
4Invalid sex 9HAC violation
5Invalid discharge status 10Error in DRG file

GRC Explanations
  • Error 1 means EITHER that there were no diagnosis codes given or that the given principal dx code does not have an MDC (ie is not valid as a principal dx).
  • Error 2 means no DRG could be found to match MDC and principal dx.
  • Error 3 means that the given age was not between 0-124.
  • Error 4 means that the given sex was not 1=male or 2=female
  • Error 5 is no longer used; Discharge Status is defaulted depending on various factors (disposition status coding system, eg)
  • Error 6 depends on various factors; for example, for some DRG versions this means that birthweight was not between 200 and 9000 grammes.
  • Error 7 means that the principal dx code was not a valid choice as a primary diagnosis; the code may be valid, but it is not an allowed starting point for assigning a DRG.
  • Error 8 means that the DRG masks file could not be found or initialized by the run-time environment.
  • Error 9 means that the given case requires HAC processing but has a problem (invalid or missing POA data)
  • Error 10 means that the DRG masks file has internal structural errors.
If you want access to descriptions for your errors, you can call either errdesc() in the C world or mherrdesc() in the VB world.

NOTE: at least in v33, CMS sometimes calls the Grouper with an invalid exempt flag value (2) to intentionally generate GRC=9

In addition, starting with version 33, the VB-callable DLL returns pre-grouping errors which are < 0 to let you know that they are not from the DAE:
  • -2 Age parameter is missing 
  • -3 Version parameter is missing
  • -4 Version parameter not support by this DLL
  • -5 Masks directory parameter is missing
  • -6 Version could not be initialized (missing, unreadable or invalid masks file?)
  • -7 Version could be be initialized, call errdesc() or mherrdesc() as appropriate
  • -8 Sex parameter is missing

Thursday, October 22, 2015

New DRGFilt Control File

Now that our validation is over, we are publishing the DRGFilt control file we used with the CMS test data set so you can see a real world example of all the new features in action:

; new format DRGFilt control file, with different groups for different purposes

;---------------
; this group is to process the standard fixed-width input file from CMS
;---------------
[fixed]
format = fixed          ; input file format
verbose = 0             ; no debugging information
blip = 1000             ; give progress report every 1,000 records
batchver = 33           ; assign version 33 DRGs to this batch
maskdir = .             ; directory in which to find drgmasks.v33

; fixed-width input variables: name = length@offset
age =   3@0
sex = 1@3
ds =  2@4
dxl=8           ; dx length does not require an offset
poa= 7
dx = 200@23
sgl=7@0         ; pr length, offset is optional & ignored
surg= 175@223
exmp = 1@6
; -----
; these are already present from the CMS grouper:
; you could overwrite the incoming values if you wanted to
; drg = 3@603
; mdc = 2@600
; rc = 2@598
; -----

; these are written out by DRGFilt
rc  = 2@1760
mdc = 2@1762
drg = 3@1764

;---------------
; this group is to validate date-handling of a CSV
;---------------
[csv-adt]
format = csv (,)        ; separator character is in parens
base = 0                ; field indices are zero-based, as opposed to 1-based, etc
inheaders = 1           ; 1=input column headers, 0=no input column headers
outheaders = 1          ; 1=want column headers, 0=no column headers
crlf = 0                ; type of end-of-line: 0=crlf (DOS), 1=lf (Unix)
blip = 1000             ; give progress report every 1,000 records
maskdir = .             ; directory in which to find drgmasks.v33
batchver = 33           ; the DRG version to apply to this entire batch
infile = adt.csv        ; input file name
outfile = x.csv         ; output file name
;outfile = blank file.csv
verbose = 1             ; give debugging output
; input variables: name = index
inid = 0
bdt =  1
sex = 2
exmp = 3
ds =  4
; these there keywords are allowed to have lists as parameters.
; lists can contain single entries, ranges, or both. for example
; 1,2,7-22,50
dx = 5-29
poa = 30-54
surg= 55-79
adt = 80
; calcver gives the index of a field to be used as the date from which
; we calculate the appropriate DRG version. If any record's calculated
; DRG version does not match the batchver, we skip that record
calcver = 80            ; NOTE: same index as "adt" because we are using the same field

; these are written out by DRGFilt
outid = 0               ; patient ID from input, whatever inid pointed to
rc  = 1
mdc = 2
drg = 3
desc = 4
weight = 5
morp = 6
outver = 7

;---------------
; this group is to process the CSV we created from the standard fixed-width input file from CMS
;---------------
[csv]
format = csv (,) ; separator character is in parens
base = 0 ; indices are zero-based
;base = 1 ; indices are one-based
inheaders = 1           ; 1=input column headers, 0=no input column headers
outheaders = 1 ; 1=want column headers, 0=no headers
crlf = 0 ; type of end-of-line: either crlf or lf
blip = 1000
batchver = 33
maskdir = .
infile = testdbv33.csv
outfile = testdb.out.csv

; input variables: name = index
inid = 0
age =  1
sex = 2
exmp = 3
ds =  4
dx = 5-29
poa = 30-54
surg= 55-79

; these are written out by DRGFilt
outid = 0 ; patient ID from input
rc  = 1
mdc = 2
drg = 3
desc = 4
weight = 5
morp = 6
outver = 7

;---------------
; this group is to process the CSV we created from the standard fixed-width input file from CMS
;---------------
[csv-validate]
format = csv (,) ; separator character is in parens
base = 0 ; indices are zero-based
;base = 1 ; indices are one-based
inheaders = 1           ; 1=input column headers, 0=no input column headers
outheaders = 0 ; 1=want column headers, 0=no headers
crlf = 0 ; type of end-of-line: either crlf or lf
blip = 1000
blipeol = 0 ; 1=newline for progress report, 0=carriage return
maskdir = .
batchver = 33
inheaders = 1           ; 1=input column headers, 0=no input column headers
outheaders = 0 ; 1=want column headers, 0=no headers
crlf = 0 ; type of end-of-line: either crlf or lf
blip = 1000
blipeol = 0 ; 1=newline for progress report, 0=carriage return
maskdir = .
batchver = 33
infile = testdbv33.csv
outfile = testdb.validate.csv
verbose = 1

; input variables: name = index
inid = 0
age =  1
sex = 2
exmp = 3
ds =  4
dx = 5-29
poa = 30-54
surg= 55-79

; these are written out by DRGFilt
outid = 0 ; patient ID from input
drg = 1

; eof




We hope this answers any questions about how to use the new control file features.

V33 DRGFilt for AIX

We just validated our DRGFilt for AIX so we are good to go for Big Endian environments with our new code base.

You can buy DRGFiltv33 for AIX in our on-line store at drggroupers.nethttp://drggroupers.net

Wednesday, October 21, 2015

Norton Flagging Our Windows Installers

We create installers for our windows products because that makes life easier for our customers.

Over the years, we have found that Norton Anti-Virus has become more and more aggressive in its suspicion of installers which do not come from large companies.

Specifically, Norton is prone to throw a "WS.Reputation.1" error, which basically means "Norton does not specially know about this installer, so Norton cannot say that it is OK." See this Norton link for details: http://community.norton.com/forums/clarification-wsreputation1-detection

We try to maintain a variety of "common" Windows installations in-house. On some of our validation machines we run Norton AV ourselves, so our in-house testers have reported this issue as well. But our in-house testers only had to respond to a dialogue box from Norton AV in order to allow our installers to finish. Customer Service declared this to be irritating, but not a deal-breaker.

Then one of our customers claimed that Norton simply deleted the file and would not allow them to run the installer at all. Since they are a programming shop, they did not really need the installer, so we sent them the component files and they installed them by hand. So in that case the situation was merely annoying, but we realize that other shops might not be so comfortable installing software by themselves.

This issue is not unique to us: here is another frustrated small vendor's rant about this: https://www.codeandweb.com/blog/2012/06/23/how-symantec-ruins-independent-developers

While we are generally big fans of firewall and anti-virus software, and understand why our customers might be unhappy to have our installer quarantined by Norton, we are not happy that Norton is willing to be so aggressive with so little data. And it is not clear what we can do differently: the DRG market is a niche market and we will never have the volume numbers required to get Norton's attention.

So for now we feel that the best we can do is to happily provide the component files and installation instructions as an alternative if you cannot run our installer on your system. Just send us email at our tech support email box.

PS We use Nullsoft to build our installers. For more information on them, visit their wiki here: http://nsis.sourceforge.net/Main_Page

New VB-Callable API (Windows Only)

The new VB DLL API is very similar to the old one, but we will document the entire API so that this is the only reference you need.

If you have a working pre-V33 program, here is all you need to change:

The call to mhdrg()
  • the name of the DLL in your function delcarations to "vbdrgv33.dll"
  • the name of the DRG assigner from mhdrg() to mhdrg1()
  • add the POA flag: "y" means "have POA" and "n" means "no POAs"
  • add the exempt flag: "y" means "this case is exempt from HAC" and "no" means "not exempt"
  • the DX and Proc buffers both need to be bigger: 256, not 80
The call to mhinfo()
  • the declaration should have this as a Sub not a Function
  • the first argument is now ByVal, not ByRef
Below is the Visual Basics for Applications (VBA) code we use to call vbdrgv33.dll from Excel in order to run Excel-DRG:

Option Explicit

Private Declare Function mhdllver Lib "vbdrgv33.dll" (ByVal Buf As String, _
    ByVal BufLen As Integer) As Integer
Private Declare Function mhdrg1 Lib "vbdrgv33.dll" (drg As Integer, _
    ByVal DRGVersion As String, ByVal MasksPath As String, ByVal DischStat As String, _
    ByVal PtAge As String, ByVal PtGender As String, ByVal DXList As String, _
    ByVal ProcList As String, ByVal POAPresent As String, ByVal ExemptFlag As String) As Integer
Private Declare Sub mhinfo Lib "vbdrgv33.dll" (ByVal drg As Integer, _
    ByVal DRGVersion As String, ByVal MasksPath As String, ByRef mdc As Integer, _
    weight As Double, los As Double, ByVal Desc As String, ByVal DescLen As Integer)
Private Declare Function mhdrgver Lib "vbdrgv33.dll" (ByVal MPath As String, _
    ByVal Buf As String, ByVal BufLen As Integer) As Integer
Private Declare Sub mherrdesc Lib "vbdrgv33.dll" (ByVal errBuffer As String, ByVal errLength As Integer)

Public Function AssignDRG()

On Error GoTo Err_Group

    Dim ReturnCode As Integer
    Dim drg As Integer, mdc As Integer
    Dim Desc As String * 80
    Dim weight As Double, los As Double
    Dim masksdir As String
    Dim myver As String, mydstat As String, myage As String, mysex As String, myexempt As String, mypoa As String
    Dim mydxbuf As String * 256
    Dim mypxbuf As String * 256
    Dim tempStr As String
    Dim N As Integer, needcomma As Integer
    Dim Val As String
    Dim NumRecords As Long, NumErrors As Long
    Dim LastRow As Long
    Dim MyID As Long                                    'user's record number
    Dim myWS As Object
        
    Application.ScreenUpdating = False
    Application.Cursor = xlWait
    'start in first row, DRG column
    Range("CE2").Select
    NumRecords = 0
    NumErrors = 0
    
    'get the path to the masks directory out of the registry, if you can
    masksdir = "C:\Program Files\MandH\Masks\"          'default
    Set myWS = CreateObject("WScript.Shell")
    tempStr = myWS.RegRead("HKLM\Software\MandH\BaseDir")
    If Len(tempStr) > 0 Then
        masksdir = tempStr & "\Masks\"
    End If
    
    'loop through records making sure DRG info is blank
    'first, find last row
    Do Until IsEmpty(ActiveCell.Offset(0, -81).Range("A1").Value) = True
        ActiveCell.Offset(1, 0).Range("A1").Select
    Loop
    
    'select DRG columns and all populated rows
    LastRow = ActiveCell.Row
    LastRow = LastRow - 1
    Range("CE2:CJ" & LastRow).Select
    
    'clear selection
    Selection.ClearContents
    
    Range("CE2").Select
    'loop through records assigning drg info
    Do Until IsEmpty(ActiveCell.Offset(0, -82).Range("A1").Value) = True
        myver = ActiveCell.Offset(0, -2).Range("A1").Value
        MyID = ActiveCell.Offset(0, -82).Value
    
        'abort if version is blank
        If myver = "" Then
            MyID = ActiveCell.Offset(0, -82).Value
            MsgBox "Version is empty for record # " & MyID & ". Cannot group.", vbOKOnly, "Missing Version"
            NumErrors = NumErrors + 1
            GoTo NextOne
        End If
        
        myexempt = ActiveCell.Offset(0, -79).Range("A1").Value
        mydstat = ActiveCell.Offset(0, -78).Range("A1").Value
        mysex = ActiveCell.Offset(0, -80).Range("A1").Value
        myage = ActiveCell.Offset(0, -81).Range("A1").Value
        mypoa = ActiveCell.Offset(0, -1).Range("A1").Value
        
        'Loop through controls, getting their current values
    
        'make string out of the diagnosis codes
        tempStr = ""
        needcomma = 0
        For N = -77 To -53
            Val = ActiveCell.Offset(0, N).Range("A1").Value
            If Len(Val) > 0 Then
                'append POA flag, if present
                If ActiveCell.Offset(0, N + 25).Value <> "" Then
                    Val = Val & "~" & ActiveCell.Offset(0, N + 25).Range("A1").Value
                End If
                If needcomma <> 0 Then
                    tempStr = tempStr & ","
                End If
                needcomma = 1
                tempStr = tempStr & Val
            End If
        Next N
        mydxbuf = tempStr & "^" ' explicit end-of-data marker
        
        'make string out of the procedure codes
        tempStr = ""
        needcomma = 0
        For N = -27 To -3
            Val = ActiveCell.Offset(0, N).Range("A1").Value
            If Len(Val) > 0 Then
                If needcomma <> 0 Then
                    tempStr = tempStr & ","
                End If
                needcomma = 1
                tempStr = tempStr & Val
            End If
        Next N
        mypxbuf = tempStr & "^" ' explicit end-of-data marker
        
        'call the M+H grouper with what you got
        ReturnCode = mhdrg1(drg, myver, masksdir, mydstat, myage, mysex, mydxbuf, mypxbuf, mypoa, myexempt)
        ActiveCell.Offset(0, 2).Range("A1").Value = ReturnCode
    
        If ReturnCode <> 0 Then          'drg assignment failed, alas!
            Call mherrdesc(Desc, 80)
            ActiveCell.Offset(0, 0).Range("A1").Value = drg
            ActiveCell.Offset(0, 1).Range("A1").Value = Desc
            NumErrors = NumErrors + 1
        Else                            'drg assignment worked, hurray!
            'get the particulars of this DRG from M+H dll
            Call mhinfo(drg, myver, masksdir, mdc, weight, los, Desc, 80)
            ActiveCell.Offset(0, 0).Range("A1").Value = drg
            ActiveCell.Offset(0, 1).Range("A1").Value = Desc
            ActiveCell.Offset(0, 3).Range("A1").Value = mdc
            ActiveCell.Offset(0, 4).Range("A1").Value = weight
            ActiveCell.Offset(0, 5).Range("A1").Value = los
        End If
NextOne:
        ActiveCell.Offset(1, 0).Range("A1").Select
        NumRecords = NumRecords + 1
    Loop
    Application.ScreenUpdating = True
    Application.Cursor = xlDefault
    Range("CE2").Select
    
    Beep
    MsgBox NumRecords & " records were grouped with " & NumErrors & " error(s)."

Exit_Group:
   Exit Function
   
Err_Group:
    Application.Cursor = xlDefault
    MsgBox Err.Number & "-" & Err.Description
    Range("CE2").Select
    Resume Exit_Group

End Function


Please check this blog for other entries about the VB callable DLL to answer other questions.

Tuesday, October 20, 2015

POA Logic Indicator (Exempt Flag)

With the introduction of the Present On Admission concept came three distinct data elements:
  • POA Logic Indicator / Exempt flag: an official grouper parameter which is a record-level flag which tells the grouper whether  or not POA logic (including the Hospital Acquired Condition rules, or HAC);
  • POA Flag: an official grouper parameter which is a diagnosis-level flag which tells the group how to process this code against the HAC rules
  • Have POA Flag: a DRGGroupers software parameters which, when part of our API, tells our software whether or not to look for POA flags
(Since POA comes up in so many contexts, we prefer to call the "POA Logic Indicator" something else: "the exempt-from-HAC flag" or simply "the exempt flag." Be advised that this is not how CMS refers to this data element.)

There are only two legal values for this flag:


X - Exempt from POA reporting
Z - Requires POA reporting

Note that "2" seems to be used by the grouper folks to means "throw me an error if there is HAC rule processing to do."

Present On Admission (POA) Flags

Starting with version 33 and ICD10 support, diagnosis codes are supposed to have Present On Admission (POA) flags.

(Unless the institution or patient encounter is "exempt" which would be indicated by the POA Logic Indicator which we call "the exempt flag." The POA Logic Indicator gets its own post to keep confusion to a minimum.)

Here are the CMS definitions of the legal values for this single character flag:

 Flag Meaning
YYes, present at the time of inpatient admission
NNo, not present at the time of inpatient admission
UInsufficient documentation to determine if present on admission
WClinically unable to determine if present at time of admission
1Code is exempt from POA reporting (Used on 4010 form)
BlankCode is exempt from POA reporting (Used on 5010 form, effective 01/01/2011)

Many of our APIs have a "Have POA" flag which is something different: the "Have POA" flag is a record-level indication of whether or not there are POA flags in the submitted diagnosis data. The "Have POA" flag is either "y" for yes or "n" for no.

The POA flags are single-character fields at the individual diagnosis code level. There are up to 25 diagnosis codes accepted for DRG assignment and if you are using POA flags, every code should have one.

In their test data set,CMS passes the POA flag to its grouper as the last character of a fixed-width field. We support that methodology in our DRGFilt product's fixed-with mode and in our C-callable DLL as these are environments in which appending an indicator is relatively easy.

We also support passing in separate POA flag fields in our DRGFilt product's CSV mode and in our VB-callable DLL as there environments generally have better support for separate fields than for character manipulation.

Monday, October 19, 2015

New C-Callable API (both Windows DLL and Linux SO)

In keeping with our philosophy that working code is the most trust-worthy documentation, here is the new mhdrg1() call from our validation C program which we compile and run under either Windows 7 or Linux:


 #define DRGVER "v33"
 
// expected = "DRG: 614        MDC: 10         GRC: 00";

/* call the grouper, store results in retval */
retval = mhdrg1(
    DRGVER,                 /* which DRG version you want */
    "/drbd/mnh/src/SWIG",   /* path to masks files */
    "1",                    /* discharge status */
    "55",                   /* patient age on admission */
    "1",                    /* patient sex (1=male, 2=female) */
    /* ICD DX codes */
    "D352   YE2740  NN390   YE871   NF05    NR630   NR110   YR0602  YD649    ",
    /* ICD procedure codes */
    "0GB00ZZ0YUY47Z02HR30Z0L8S3ZZ0P5N0ZZ0RJP0ZZ",
    8,                      /* length of each ICD DX code */
    7,                      /* len of each ICD procedure code */
    "y",                    /* are there POA indicators? */
    "X"                     /* is this case exempt from HAC? */
    );


This is an actual case from the CMS test data set. This is an actual call to mhdrg1(), which replaces mhdrg() as the entry point in the DLL.

We changed the name to make it possible to have a single program call either the ICD9-based version or the new ICD10-based version.

The API is only slightly different: there are two new arguments at the end of the argument list:
  • The POA indicator: are there POA flags appended to the DX codes? This argument is always a character pointer (char *) but can be either "1" (yes there are) or "0" (no there are not), or "y" (yes there are) or "n" (no there are not).
  • The POA Logic indicator: this is also a character pointer and represents the HAC exempt status of the patient encounter:
    • NULL means there is no exempt flag or encounter is not exempt
    • "X" or "1" means that this encounter is exempt
    • "Z" means that this encounter is not exempt
    • any other value is not allowed and will result in throwing an HAC error if there is a dx code with a CC exclusion of either kind.

Friday, October 16, 2015

I10 Progress Report #10: VB Support Validated

We are delighted to announce that our Excel-DRG validation is done, which means that:
  • we have a CSV version of the CMS test data set
  • we have an API to a VB-callable DLL to assign DRGs which supports:
    • age
    • sex
    • discharge disposition
    • ICD10 diagnosis list with optional POA flags
    • ICD10 procedure list
    • POA indicator (are you sending POA flags?)
    • Exempt flag (is this case exempt?)
  • we have VB for Apps code to use the DLL to:
    • call mhdrg1() and get a DRG
    • call mhinfo() and get the description, weight, MDC, LOS
    • call mherrdesc() when there are errors
  • we have updated Excel-DRG to use this code
  • we have run the test data through Excel-DRG and confirmed that it works
We are done building products, the rest is sales and marketing and support.

We are going to start filling standing orders today and we hope to be ready to take new orders on-line by the end of next week.

Friday, October 9, 2015

V33 C-Callable DLL Validated

We have just finished validation of our new C-callable DLL for Windows, which we are calling cdrgv33.dll. It should be available for purchase next week.

Linux V33 Products Validated

We have completed wrapping our DRG Assignment Engine in the following Linux products:
  • DRGFiltv33
  • The C object module
  • The Perl-callable module
  • The PHP-callable module
In response to customer suggestsion, we are developing a straight Web service for assigning DRGs but we will not be releasing the service until after the standard products are available.

Work on the Windows products has already begun and should be complete very soon.

Thursday, October 8, 2015

I10 Progress Report #9: Windows Version Validated

We have used the new DRGFilt10 to validate our DRG Assignment Engine (DAE) under windows (our reference platform is Windows 7 in order to avoid leading edge syndrome).

So we are hard at work putting together our Windows products for v33; we expect them to be available by mid-October at the latest.

This also gave us more experience with the new control file format, which we love. As part of the port to Windows, we added a feature to  DRGFilt10:  if you do not specify the "crlf" parameter, which controls the end of line (EOL) format, then DRGFilt10 does the environment-specific usual thing (Unix EOL under Unix, Windows EOL under Windows).

In other words, leaving the "crlf" parameter out of the control file means that output lines end with just line feed (LF) under Unix and carriage return (CR) + LF under Windows.

If you need to force CRLF under both environment, set crlf=1.

If you need to force LF under both environments, set crlf=0.

Wednesday, October 7, 2015

DRGFilt10 New Control File Format, part 3

Today we validated group handling in our new DRGFilt Control File; the group name is given in square brackets and every configuration item until the next group is part of the current group.

DRGFilt10 now only processes the configuration information in the active group. The default active group is "drgfilt".  You can either specify an active group on the command line or let the default active group be used.

Therefore the new DRGFilt10 syntax is this:

drgfilt10 {ini-file-name} [group-name]

For example, we are validating with a control file called "v33.ini". That control file defines several jobs:
  • "fixed" defines the job to process the standard CMS test data set
  • "csv" defines the job to process the CSV we created from the CMS file
  • "csv-validate" defines the job which creates output for our validator
When we want to run the job to process the standard CMS test data set, we run this command:

drgfilt10 v33.ini fixed < TESTDB > output.fixed 

We choose to use the Unix-style filter feature of DRGFilt, but the new control file allows us to specify an input file, an output file, or both or neither.

Here is a sample DRGFilt control file which documents all the currently supported features:

; new format DRGFilt control file, with different groups for different purposes

;---------------
; this group is to process the standard fixed-width input file from CMS
;---------------
[fixed]
format = fixed          ; input file format
verbose = 0             ; no debugging information
blip = 1000             ; give progress report every 1,000 records
batchver = 33           ; assign version 33 DRGs to this batch
maskdir = .             ; directory in which to find drgmasks.v33

; fixed-width input variables: name = length@offset
age =   3@0
sex = 1@3
ds =  2@4
dxl=8           ; dx length does not require an offset
poa= 7
dx = 200@23
sgl=7@0         ; pr length, offset is optional & ignored
surg= 175@223
exmp = 1@6
; -----
; these are already present from the CMS grouper:
; you could overwrite the incoming values if you wanted to
; drg = 3@603
; mdc = 2@600

; rc = 2@598
; -----

; these are written out by DRGFilt
rc  = 2@1760
mdc = 2@1762
drg = 3@1764

;---------------
; this group is to validate date-handling of a CSV
;---------------
[csv-adt]
format = csv (,)        ; separator character is in parens
base = 0                ; field indices are zero-based, as opposed to 1-based, etc
headers = 1             ; 1=want column headers, 0=no headers
crlf = 0                ; type of end-of-line: 0=crlf (DOS), 1=lf (Unix)
blip = 1000             ; give progress report every 1,000 records
maskdir = .             ; directory in which to find drgmasks.v33
batchver = 33           ; the DRG version to apply to this entire batch
infile = adt.csv        ; input file name
outfile = x.csv         ; output file name
;outfile = blank file.csv
verbose = 1             ; give debugging output

; input variables: name = index
inid = 0
bdt =  1
sex = 2
exmp = 3
ds =  4
; these there keywords are allowed to have lists as parameters.
; lists can contain single entries, ranges, or both. for example
; 1,2,7-22,50
dx = 5-29
poa = 30-54
surg= 55-79
adt = 80
; calcver gives the index of a field to be used as the date from which
; we calculate the appropriate DRG version. If any record's calculated
; DRG version does not match the batchver, we skip that record
calcver = 80            ; NOTE: same index as "adt" because we are using the same field

; these are written out by DRGFilt
outid = 0               ; patient ID from input, whatever inid pointed to
rc  = 1
mdc = 2
drg = 3
desc = 4
weight = 5
morp = 6
outver = 7

;---------------
; this group is to process the CSV we created from the standard fixed-width input file from CMS

;---------------
[csv]
format = csv (,) ; separator character is in parens
base = 0 ; indices are zero-based
;base = 1 ; indices are one-based
headers = 1 ; 1=want column headers, 0=no headers
crlf = 0 ; type of end-of-line: either crlf or lf
blip = 1000
batchver = 33
maskdir = .
infile = testdbv33.csv
outfile = testdb.out.csv

; input variables: name = index
inid = 0
age =  1
sex = 2
exmp = 3
ds =  4
dx = 5-29
poa = 30-54
surg= 55-79

; these are written out by DRGFilt
outid = 0 ; patient ID from input
rc  = 1
mdc = 2
drg = 3
desc = 4
weight = 5
morp = 6
outver = 7

;---------------
; this group is to process the CSV we created from the standard fixed-width input file from CMS
;---------------
[csv-validate]
format = csv (,) ; separator character is in parens
base = 0 ; indices are zero-based
;base = 1 ; indices are one-based
headers = 0 ; 1=want column headers, 0=no headers
crlf = 0 ; type of end-of-line: either crlf or lf
blip = 1000
maskdir = .
batchver = 33
infile = testdbv33.csv
outfile = testdb.validate.csv
verbose = 1

; input variables: name = index
inid = 0
age =  1
sex = 2
exmp = 3
ds =  4
dx = 5-29
poa = 30-54
surg= 55-79

; these are written out by DRGFilt
outid = 0 ; patient ID from input
drg = 1

; eof

Thursday, October 1, 2015

DRGFilt10 New Control File Format, part 2

We have completed and validated CSV support for both input and output for DRGFilt10, the ICD10-based version of DRGFilt. The CSV version of the control file looks like this:

; control file for new DRG filt -- CSV version
[drgfilt]
format = csv (,) ; separator character is in parens
base = 0 ; indices are zero-based
;base = 1 ; indices are one-based
headers = 1 ; 1=want column headers, 0=no headers
crlf = 0 ; type of end-of-line: either crlf or lf
blip = 1000

; input variables: name = index
inid = 0
age =  1
sex = 2
exmp = 3
ds =  4
dx = 5-29
poa = 30-54
surg= 55-79

; these are written out by DRGFilt
outid = 0 ; patient ID from input
rc  = 1
mdc = 2
drg = 3
desc = 4
weight = 5
morp = 6


We hope that this upgrade fills many of the requests we have gotten over the years for extensions to the control file format.

Tuesday, September 29, 2015

I10 Progress Report #8: V33 Support Validated

Hurray, our DRG Assignment Engine (DAE) correctly handles the CMS test set with ICD10 codes and v33 code attributes and logic.

Now we just have to roll out the DAE into our pared-down product catalog and overhaul our web sit and on-line store and we will be all set.

Next stop: CSV support for the new DRGFilt.

Monday, September 28, 2015

I10 Progress Report #8: Masks File Has Been Built

We have built and validated the v33 masks file, so we are ready for integrated testing as soon as the logic module has been updated. We expect the logic upgrade to be done by midday tomorrow.

I10 Progress eport #7: So Far, So Good

We have finished our assessment of the v33 upgrade and we have started the work:
  • the attributes seem to be only minor different between v32 and v33
  • the logic seems somewhat different between v32 and v33
We expect to have have masks file built first thing tomorrow, so that when the software update is done mid-day tomorrow, validation can begin.

Currently, our goal is to have our DRG Assignment Engine (DAE) will be upgraded to support v33 by end the of the day on October 1, 2015.

I10 Progress Report #6: on to V33

We are hard at work on support for v33, which currently is moving along three different tracks:

DRGFilt Upgrade
We are upgrading DRGFilt to handle CSVs as well as fixed-width input. (We may also get to adding support for the very simple equation format: one line per column, each line of the form "col_name=value")

V33 Masks File
To support v33, we need to support logic and the ICD10 code attributes, which we call "the masks" and some people call "the tables." We encode the logice in our software and we create a database of attributes which we call "the masks file." We are hard at work creating the masks file.

V33 Logic Support
Of course we are upgrading our logic module to match the v33 logic module so that our software can work in conjunction with the v33 attributes to assign v33 DRGs.

Saturday, September 26, 2015

DRGFilt10 New Control File Format

The version of DRGFilt which supports ICD10-based DRG assignment is called DRGFilt10. Since we are overhauling our product line, we decided to knock a very long-standing item off the list: the DRGFilt control file format.

The control file tells DRGFilt how to parse the incoming data records to pick out the data elements needed to assign a DRG:
  1. patient age
  2. patient sex
  3. patient discharge status
  4. list of diagnoses
  5. list of procedures
The control file also tells DRGFilt where to put its output:
  1. Grouper Return Code (GRC) -- what, if anything, went wrong
  2. Major Diagnostic Category (MDC)
  3. Diagnosis Related Group (DRG)
The original control file format was based on the old IBM punch cards (!) so it was definitely time to ditch the 1960s. For our first upgrade, we decided to move on up to the 1990s by supporting a .INI-like format.

Our first step along the moderization path is Specifically, this is the control file we are using to validate the new DRGFilt against the CMS test data set:

; control file for new DRG filt
[drgfilt]
format = fixed
; fixed-width input variables: name = length@offset
age =    3@0
sex = 1@3
ds =  2@4
dxl=8        ; dx length does not require an offset
poa= 7
dx = 200@23
sgl=7@0     ; pr length, offset is optional & ignored
surg= 175@223
exmp = 1@6
; -----
; these are already present from the CMS grouper:
; you could overwrite the incomin values if you wanted to
; drg = 3@603
; mdc = 2@600
; rc = 2@598
; -----

; these are written out by DRGFilt
rc  = 2@1760
mdc = 2@1762
drg = 3@1764

; eof


We hope to roll out the long-awaited CSV support very soon.

Thursday, September 24, 2015

I10 Progress Report #5: Success

At last, x32 has been validated, confirming that our new ICD10-based development path is working:

Processing version X32...ICD10 config
9187 records read with 0 errors.
All done.


So we are immediately starting work on v33, which will be our first production version for ICD10.

We are also changing our DRGFilt control file from its very 1980s fixed-width format to a very 1990s .INI file. (We hope to have support for a very 2000s XML format very soon.)

Thursday, September 17, 2015

I10 Progress Report #4

Yesterday we finished porting the attributes handling subsystem to our new development environment. We validated x32 against the CMS test data and x32 matches 97% of the time.

We are chasing that 3% but since I10 v32 was not an official release, we think that some of the discrepancy is due to last-minute changes. We are looking into running the official Grouper software so we can confirm their results.

We expect to be done with x32 no later than the end of the week and to start v33 Monday.

Tuesday, September 15, 2015

I10 Product Catalog

We are overhauling our operations as part of the switch from ICD9cm to ICD10 and one of the areas we are overhauling is our product catalogue.

Many of our products are holdovers from when our customers were mostly information system developers who wanted software development tools, such as shared objects and hash table look-ups.

In recent years we find that fewer and fewer of our customers are programmers and more and more of our customers are analysts or end-users.

We plan to continue to support developers, but on a custom and case-by-case basis: there is no longer any need to clutter our catalogue with estoteric items.

Our ICD9cm catalogue had 30 items and we wanted to get down to 10 items. We think that we have done it; here is our proposed catalogue so we can get your feedback before we make the final decisions.

Items We Plan to Keep

SKUDescriptionStatus
AIXFILTDRGFilt for AIXy
CDLLVisual C-callable DLLy
DASJUMBODRG Assignment Jumbo Data set"y
DASLARGEDRG Assignment Large Data set"y
DASMEDIUMDRG Assignment Medium Data set"y
LINUXFILT6464 bit Linux DRGFilty
MASKSDRG Masksy
VBDLLVB-callable grouper DLLy
WINFILTDRGFilt for 32 bit Windowsy
WMASKSWin32 DRG Masksy
 

Items We Plan to Retire

SKUDescriptionStatus
CICDICD9 Name-finding C-callable DLLn
COBJ32SO32 bit C-callable shared objectn
DASSMALLDRG Assignment Small Data set"n
ICDTABICD9cm short filen
ICLUPICL Run-time Environment Upgraden
LINUX32CGIDRG32 bit Linux CGI DRG Assignern
LINUXFILT3232 bit Linux DRGFiltn
PERL32SO32 bit Perl-callable shared objectn
PERL64SOPerl-callable shared objectn
PHP32SO32 bit PHP-callable shared objectn
PHP64SO64 bit PHP-callable shared objectn
SPARCFILTDRGFilt for Sun SPARCn
VBICDICD9cm Name VB-callable DLLn
W32CGIDRG32 bit Windows CGI DRG Assignern
WICDTABWin32 ICD9cm short filen
XLDRGMS-Excel DRG Assigning spreadsheetn

Items We Are Considering Keeping

SKUDescriptionStatus
ACCESSDRG03MS-Access?
ACCESSDRG07MS-Access?
COBJ64SO64 bit C-callable shared object?
LINUX64CGIDRG64 bit Linux CGI DRG Assigner?

I10 Progress Report #3

We almost got the code attribute data file building process ported from our old environment to our new one.

We are grateful to have our out-going guru's help today and we are confident that he will be able to get us over the final hump: if not today, then tomorrow.

Monday, September 14, 2015

I10 Progress Report #2

We did not quite meet our goal of building x32 yesterday; we completed the logic part but not the code attribute part (which we call "the masks" and which many other organizations call "the tables").

We expect to finish the basic x32 DRG Assignment Engine (DAE) today, build DRGFilt x32 on top of the DAE and then start on v33.

Sunday, September 13, 2015

I10 Progress Report #1

Many of you have enquired about the status of our support for the upcoming grouper release. This post is intended to answer those questions.

This coming October 1st we are due to release v33, which will be the first version which is only ICD10 (i10). Starting with v33, we will no longer provide ICD9-based (i9-based) grouping support, so v33 is our first non-experimental release which is i10-based.

Up to now, our versions have all been i9-based except for the experimental i10-based products. We designated the experimental versions with an 'x' instead of a 'v', so v31 was the i9-based grouper and x31 was the i10-based grouper.

Last year's grouper was the last grouper with both, so v32 is the last i9-based grouper and x32 is the last time that i10-based grouping is considered 'experimental.'

On top of the very large shift from i9-based to i10-based grouping, our in-house grouper guru retired, which forced us to revamp our development process.

This is our plan to migrate us from the i9-based to i10-based development:
  1. Technology turn over from departing guru to new team
  2. Re-create x31 with the new process and new team
  3. Create x32 with the new process and new team
  4. Create v33 with the new process and new team
We are happy to report the step (1) was completed in early June and that step (2) was completed yesterday.

We expect to complete step (3) today and have an x32 DRGFilt available for evaluation by first thing Monday morning.

Currently, we feel that we are on track to be ready to provide our DRG Assignment Service for v33 on October 1st.

We are currently reviewing our product line to see which products we want to port from i9 to i10. As soon as we can we will put up an on-line survey to allow our customers to weigh in on which products to keep and which to leave behind.

Wednesday, June 3, 2015

ICD10 Support in 2015

2015 should be a banner year for DRG Groupers; we are taking advantage of the impending shift to ICD10 to knock some items off of our to-do list:

  • We are going to change our web site to improve the on-line shopping experience.
  • We changed our URL to DRGGroupers.net to go with our web site overhaul.

  • We are going to try to streamline our upload and download pathways for our DRG Assignment Service (DAS).
  • We are going to review our product definitions to make sure that we are offering what people want to buy.
  • We are trying out a streamlined development process by creating an ICD10 version of v32 DRGs--and we are looking for beta testers.
This is an ambitious slate to get done by the end of the year, but so far we are on track and appreciate your patience with any issues that arise.

Tuesday, June 2, 2015

New URL: DRGGroupers.net

It is official: we have changed over to DRGGroupers.net as our Internet domain name. This is part of our overhaul for 2015 as we clean house and tidy up as we prepare to support ICD10 with version 33 this coming autumn.

Friday, April 17, 2015

F32: Access-DRG Issue

Friday, April 17, 2015 we received a bug report about Access-DRG crashing. We traced the problem to the call to our VB-Callable DLL. We had failed to propagate an update to our servers. We responded with a patch that day.

Please let us know if you are having trouble with Access-DRG so we can diagnose the problem and send you an update if appropriate.