NONMEM as a dll
From: "Sale, Mark " <ms93267@glaxowellcome.com>
Subject: NONMEM as a dll
Date: Fri, 4 Dec 1998 11:00:31 -0500
Dear users,
A good number of nonmem users seem to be increasingly interested in applying "numerically intensive" methods to these analysis (as if they weren't numerically intensive enough). These include bootstrap, jackknife, Monte Carlo simulation, sensitivity analysis and others. We have had a little experience with this at GlaxoWellcome, and I'd like to share some experiences, and hope for some help as well. We've found that the most effective way to do this (on a pc) is to compile NONMEM as a dll (dynamic link library) that can be called from another application. For example, for a bootstrap, on might use an application (SAS, Splus, Excel, Matlab) to sample the data, generate a data set, run NONMEM, and compile the results for 1000 runs. Users on a PC who do this with a system escape (e.g., shell() in Visual basic and Visual basic for applications and the bang (!) operator in Matlab) will find that a new process is created for each run. The problem is that this basically disables you computer, since that new process (a command/DOS window) will have the focus, so, as you are typing you latest report/grant in Word you suddently switch over to this command window. Very inconvenient. In some applications the child process will not inheirate the priority of the parent process, so even if you do set the priority of Excel to low the NONMEM run will be at normal priority anyway, markedly reducing the responsiveness of your computer. (To set the priorty to low on NT hit ctrl-alt-delete, click task master, select the processes tab, click on the CPU header, right mouse button over the process name (nonmem.exe), select Set priority and then Low.)
We have worked out a partial solution to this. This solution is specific to Matlab, but I'm hoping that someone more familiar than I with Windows API can make it more general.
For a NONMEM bootstrap analysis, we compile NONMEM as a dll, generate the data set and run NONMEM. We compile the output (THETA, OMEGA, SIGMA etc) with a call from INFN, writing the values to a file, then reading them into Matlab. To do this (compile NONMEM as a dll) some changes are required in the source code. There are two major issues and one minor issue.
1. There is a lot of output to the console/standard output in NONMEM (MONITERING OF SEARCH etc). There is not standard output for a dll, there is no DOS window to write to. This will cause an immediate crash of the calling application. (dlls are very unforgiving).
2. NONMEM terminates from CFILES with a STOP command. This will terminate not only NONMEM, but the calling application.
Minor issue.
The data file size will usually change between runs. NMTRAN writes the number of data records to FCON, which is read by NONMEM. Fortunately in version 5, this can be set to 0 (and in fact is by NMTRAN if the number of records is > 9999). Alternatively, you can just run NMTRAN (without compiling) for each run, takes only about a second if the data set is small.
You'll need to run NMTRAN if you aren't writing formatted data anyway.
Changes to NONMEM source code to compile as dll:
nonmem.for - Make NONMEM a subroutine rather than a program
line 10 change PROGRAM NONMEM to SUBROUTINE NONMEM
BLKDAT.for - Make standard output/console output to 'nul'
line 26 change 'con' to 'nul' to read:
DATA FNSTP,FNINT,FNERR,FNINTR,FNULL
1/'nul','nul','PRDERR','INTER','nul'/
cfiles.for Make sure that FCON (unit 5) and OUTPUT files (unit 6) get closed.
line 28 add close (5)
line 29 uncomment close (6)
and finally the part specific to Matlab cfiles. Can't use STOP command.
line 64 change STOP to CALL mexErrMsgTxt('ending nonmem')
mexErrMsgTxt is a routine in Matlab that returns an error code, and returns control to Matlab.
My question is (for those who have made it this far) is:
Is there a Windows API call the is similar to mexErrMsgTxt, i.e., that returns control to the calling application from a dll. Note that the "usual" way to do this is to return to the "entry point" subroutine in the dll, and get to a RETURN and END. Looking at the code (and discussing with Stu) this is not practical in NONMEM as it is currently written, CFILES is called from dozens of places, often many calls deep from the entry subroutine (which is NONMEM.for). To do this would be a monumental rewrite. Any help is appreciated, and I'd be happy to supply code for the required gateway routine in Matlab to anyone interested.
Mark
Mark Sale M.D.
5 Moore Drive 17.2219
PO Box 13398
RTP NC 27709
ms93267@glaxowellcome.com
919-483-1808