metrumresearchgroup / mrgsolve

Simulate from ODE-based population PK/PD and QSP models in R
https://mrgsolve.org
GNU General Public License v2.0
131 stars 36 forks source link

mread() can't find project directory when working on a mapped network drive #1100

Open marianklose opened 1 year ago

marianklose commented 1 year ago

Hi, thanks a lot for the great work! 👍

I am having trouble with reading in model files when working on a mapped network drive. When working remotely we usually connect to the university network (e.g. \\campus.fu-berlin.de\daten...) via mapping it to a network drive (G://). It's hard to provide a reproducible example but here is the behaviour in a nutshell.

To make sure that we are already in the model directory I run:

setwd("G:/Projekte/xxx/models")

getwd()
[1] "G:/Projekte/xxx/models"

Now there is a file in our working directory called goti2018.cpp which is accessible via e.g., readLines()

readLines("goti2018.cpp")
  [1] "$PROB "                                                                                                      
  [2] " - Goti 2018 Model"                                                                                          
  [3] " - DOI: 10.1097/FTD.0000000000000490"                                                                        
  [4] " - Structure: two compartment"   

However, mread() throws an error:

mread("goti2018")
Error: project directory 'G:/Projekte/xxx/models' must exist and be readable.

This is the traceback:

> traceback()
3: stop("project directory '", project, "' must exist and be readable.", 
       call. = FALSE)
2: new_build(file = file, model = model, project = project, soloc = soloc, 
       code = code, preclean = preclean, udll = udll, recover = recover)
1: mread("goti2018")

Inside new_build() which gets called by mread we have

if (!file_readable(project)) {
  stop("project directory '", project, "' must exist and be readable.", 
    call. = FALSE)
}

which apparently causes the error. The project argument should be the default argument from mread which is project = getOption("mrgsolve.project", getwd()) and which is in our case "G:/Projekte/xxx/models". The definition of file_readable() from utils.R is

file_readable <- function(x) {
 file.access(x,4)==0 
}

Since file_readable isn't being exported I directly use file.access to check the behaviour:

> file.access("G:/Projekte/xxx/models", 4) == 0
G:/Projekte/xxx/models 
 FALSE 

The project is existent as file.access("G:/Projekte/xxx/models", 0) is TRUE. If I copy the full folder over to my Desktop both mread() and file access work without problems.

> file.access("C:/Users/Admin/Desktop/models", 4) == 0
C:/Users/Admin/Desktop/models 
 TRUE 

I wonder why file.access() indicates that there are no read permissions on the mapped network drive altough the directory is clearly readable. Would it be possible to maybe include an option in mread whether to check for read permissions or to skip that check? I am sure that in my case there wouldn't be any read issues and that the error is related to some misbehaviour of file.access().

Thank you!

kyleam commented 1 year ago

Thanks for the detailed bug report.

I wonder why file.access() indicates that there are no read permissions on the mapped network drive altough the directory is clearly readable.

I don't have an answer for "why", but it seems it's a known issue that file.access() can be unreliable. For example:

Would it be possible to maybe include an option in mread whether to check for read permissions or to skip that check?

Another approach for consideration: rework the code to just go ahead and access the directory, catching errors to give more helpful or tailored messages where needed. What do you think @kylebaron?

marianklose commented 1 year ago

Thank you for your answer @kyleam.

Indeed, it seems that I am not the only one having issues with file.access() on windows. If the function is unreliable I don't think it is justified to force a stop inside new_build(). I agree that another parameter in mread might not be the best solution and that it might be sufficient to just replace the stop() with a detailed warning() inside new_build().

Just to prove that this would be a valid solution I have modified

if (!file_readable(project)) {
  stop("project directory '", project, "' must exist and be readable.", 
    call. = FALSE)
}

and replaced the stop with a warning. Now I am able to read in the model file also from mapped / mounted network drives:

> mread("goti2018")
Building goti2018 ... done.

---------------  source: goti2018.cpp  ---------------

  project: G:/Projekte/xxx/models
  shared object: goti2018-so-4690154177c9 

  time:          start: 0 end: 24 delta: 1
                 add: <none>

  compartments:  CENT PERI [2]
  parameters:    TVCL TVVC TVVP TVQ TH_CRCL_CL
                 TH_DIAL_CL TH_DIAL_VC CRCL DIAL WT [10]
  captures:      PRED_wo PRED_wRUV TVCL TVVC TVVP TVQ
                 CRCL DIAL CL VC VP Q TH_CRCL_CL
                 TH_DIAL_CL TH_DIAL_VC [15]
  omega:         3x3 
  sigma:         2x2 

  solver:        atol: 1e-08 rtol: 1e-08 maxsteps: 20k
------------------------------------------------------
Warning message:
The file.access function indicates that project directory 'G:/Projekte/xxx/models' might not exist
or is not readable. However, file.access is unreliable on Windows. Thus, existance and readability
of the project directory should be ensured by the user.  

In my opinion such a warning message would be sufficient to give a hint to user where to look in case the directory is actually non-existent or non-readable. I have created a pull-request #1101 in case you think this solution is sufficient.

kylebaron commented 1 year ago

Hi -

I'm happy to work on this with you but please note:

  1. We've had trouble in the past when users are working on networked drives which is why we recommend against working that way, preferring to work on a local disk.
  2. We haven't had this report yet after years of using file.access() so I don't think this is general to people working on Windows; you'd see something about portability in the file.access() file file and we'd have CRAN after us by now if that were the case.

I think we can write a Windows-mapped-network-drive safe version of file access following the pattern in the R source. @marianklose When this is ready to go, can you please test it for us?

Thanks, Kyle

marianklose commented 1 year ago

Hi @kylebaron,

thank you for your insights. To reply to your discussion points:

  1. I agree in general, however we unfortunately do not have other options than to work on a networked drive due to university restrictions. And creating a local copy is not always feasible, especially when dealing with sensible data or with large-sized projects.
  2. Interesting that I am the first one with this issue. At least there are several threads about file.access() failing for windows users working on network drives. But you are right, this won't apply in general to people working on Windows.

I have checked it on 2 other machines with networked drives to our university network and was able to reproduce the issue.

I think we can write a Windows-mapped-network-drive safe version of file access following the pattern in the R source. @marianklose When this is ready to go, can you please test it for us?

Sure, I am happy to test it!

Thanks for your help, Marian