Sunday, October 5, 2008

Validating a DRGFilt Control File

QUESTION

I find the DRGFilt control file format kind of hard to understand. How can I be sure that I got it right?

ANSWER

We hear you: the control file format is showing its age: it was derived from a format that originated on punch cards (!).

We use the following Perl script to validate our control files in-house:

Sample usage
In the examples below, replace "control-file" with the name of the control file you are validating, and "data-file" with the name of the data file you are running against. For extra credit, replace "pt-id" with the patient, claim or record ID you are looking for.

Unix
  • perl chkcntl.pl control-file < data-file | more
  • head -20 data-file | perl chkcntl.pl control-file | more
  • fgrep pt-id data-file | perl chkcntl.pl control-file
Windows
  • perl.exe chkcntl.pl control-file < data-file | more
  • perl.exe chkcntl.pl control-file < data-file > output.txt

Sample Perl Code

# chkcntl.pl - program to check a control file

my($sgl,$dxl,$recLen,%h) = Load(shift(@ARGV));

while (defined(my $l = <>)) {
    $l =~ s/\r|\n//g;
    # pad out input with astericks if too short
    while (length($l) < $recLen) { $l .= '*'; }

    my $output = "";
    foreach my $key (sort (keys %h)) {
    my $ref = $h{$key};
    my($name,$off,$len) = @$ref;

    my $val = substr($l,$off,$len);
    $output .= sprintf("%4.4s@%3d for %2d:",$name,$off,$len);

    if ($name =~ /^(dx|surg)$/i) {
        $output .= AddBar($val, ($name =~ /dx/i)? $dxl : $sgl);
    } else {
        $output .= $val;
    }

    $output .= "\n";
    }
    print $output,"\n";
}

exit(0);
#-----------------------------------------------------------------
sub AddBar {
    my $val = shift;
    my $len = shift;

    my $inLen = length($val);
    my @f = ();

    for (my $i = 0; $i < $inLen; $i += $len) {
    push(@f,substr($val,$i,$len));
    }

    return join('|',@f);
}

sub Load {
    my $fname = shift;

    my %h;  # keyed by offset, value is name
    my($dxl,$sgl) = (5,4);
    my $recLen = 0;
    my($poa,$exempt);

    open(FILE,$fname) || die "Could not open '$fname': $!";
    while (defined(my $l = <FILE>)) {
    next unless ($l =~ /^[a-zA-Z]/);
        #age  000 03
    my($name,$offset,$length) = unpack("a4xa3xa2",$l);

    if ($name =~ /sgl/i) {
        $sgl = $length;
        next;
    }
    if ($name =~ /dxl/i) {
        $dxl = $length;
        next;
    }
    if ($name =~ /poa/i) {
        $poa = $length;
        next;
    }
    if ($name =~ /exmp/i) {
        $exempt = $length;
        next;
    }

    my $key = sprintf("%03d",$offset);
    my $ref = [ $name, $offset, $length ];
    foreach my $el (@$ref) { $el =~ s/^\s+|\s+$//g; }
    $h{$key} = $ref;

    }
    close(FILE);

    # figure out end of record: max offset + length
    my ($max) = (reverse (sort keys %h));
    my $ref = $h{$max};
    my $recLen = $$ref[1] + $$ref[2];

    return ($sgl,$dxl,$recLen,%h);
}
# eof

Friday, October 3, 2008

F26 Released

Our support for version 26 of the US Federal DRG assignment algorithm, active as of October 1st 2008, has just been released.

F26 DRGFilt Control File

New this year: "poa", "exmp".


age  000 03
sex  003 01
ds   004 02
dxl  000 08
poa  000 07
dx   023 96
sgl  000 07
surg 223 98
exmp 006 01
# these are written out by us
drg  607 03
mdc  610 02
rc   612 02

Thursday, January 24, 2008

PHP Shared Object

QUESTION

Hello,
We recently purchased the PHP shared object from you guys and are having problems getting it running. We are using PHP 5.2.5 on Red Hat Linux 9, and are getting the following error when we try to dynamically link your mhdrg.so library:

Warning: dl(): unable to load dynamic library './mhdrg.so' - mhdrg.so:
undefined symbol: zend_list_find

Any ideas? Let me know if you need more info or if I need to be addressing this question to RTR. Also, if we can't get this to work fairly easily, would we have the option of "trading" this PHP .so for your C callable object?


ANSWER

As I understand it, things are supposed to work like this:

 - you put mhdrg.so in a place in your file system that is both
   - readable by your web server
   - not accessible by the world or the world can steal it

 - you use the dl() primative in PHP to load the extension, like so:

    if (!extension_loaded('mhdrg')) {
        if (!dl('mhdrg.so')) {  // this should be in a protected directory
            exit;
        }
    }
When I deliberately move mhdrg.so on our test system, I get the following error:

Warning: Unable to load dynamic library './mhdrg.so' - ./mhdrg.so: cannot open shared object file: No such file or directory in /home/mnh/public_html/PHP/tryit.php on line 5

So I am guessing that wherever you have put mhdrg.so is not readable by the user your web server runs as. Have you put mhdrg.so in the same document directory as your document? If not, you could trying putting tryit.php and mhdrg.so in the same document directory and confirming that tryit.php works on your systems.

That said, we would be happy to exchange your PHP shared object for a C-callable object if that works better for you.

Friday, November 16, 2007

Working with SAS

An email we received:
 
I've presented at a couple of SAS conferences about how well your
product works with SAS.  

A representative of SAS Institute suggested that you might want to
mention that your product can be called from a SAS program and put a
link to my paper on your website.  Here is one:

http://www.scsug.org/SCSUGProceedings/2007/papers/report/Report-Loren.pdf

I'm also happy to serve as a reference if anyone wants to know more
about it.

I really appreciate your help, and have been very happy with your
product.

Wednesday, November 14, 2007

Common Data Formatting Issues

QUESTION

As a test I'm regrouping some claims from the Medicare Inpatient SAF (LDS), and about 10% of the time, the results from the grouper do not match CMS's results. (Specifically, for around 1.2M claims, out of about 10M).

Some details:
  • We're using the newest grouper executable.
  • Mask version: 21 
  • Claim Through Dates: 2003-Q4 through 2004-Q3
The return codes are almost always 0 but the results often do not match. Sometimes it's b/c we don't have exact ages (everyone under 65 is just listed as 65; we don't have better info than that in the LDS SAF).

The biggest example, for each quarters:
  • Your grouper's result: 518
  • CMS-assigned DRG: 527
We have checked & rechecked the input files, control files etc. Everything looks right. The grouper return codes are good, and totaling the PFLAGs and DFLAGs shows no inconsistencies.

ANSWER

We test against the CMS grouper all the time, so this is baffling.

To really see, we would need an example or two (scrubbed of identifiers, preferably). While it is possible that our grouper has a bug in it, we are pleased to report that this is exceedingly rare. Typically, the issues we see are data handling or trivial-seeming formatting issues:
  • stripping leading zeroes from ICD9 codes
  • leading whitespace on ICD9 codes
  • non-contiguous ICD9 codes 
  • discharge disposition coding
But why guess? Send us a few records--10? 100?--and we will see what we see.

Wednesday, October 3, 2007

Running DRGFilt Under Windows

QUESTION

How do I run DRGFilt under windows?

ANSWER

You run DRGFilt from a command line, like so:

   - click on the Windows Start menu
   - click on the Run menu item
   - type "cmd" in the box
   - hit enter; you will get a "DOS box" with a prompt; let's say the prompt is ">"
   - type "cd \your-directory-name" and hit enter (replace "your-directory-name" with the name of the directory you are using)
   - type "drgfilt f25 drgmasks.f25 control.fil < input > output" and hit enter (replace "control.fil" with the name of your control file, "input" with the name of your input file and "output" with the name of your output file)

For detailed instructions, please refer to the DRGFilt chapter in the manual.