Stianpr20 / MaXrd

Symmetry data and utilities related to crystallography and X-ray scattering
MIT License
24 stars 3 forks source link

$CrystalData warning when wrapping MaXrd into another package, then evaluating on Wolfram Client Library for Python #5

Open sgbaird opened 3 years ago

sgbaird commented 3 years ago

There seems to be some issue with using the Global variable $CrystalData (I realize this is kind of a nested problem - wrapped in package then called in a Wolfram client without a Front End). Here's a MWE:

BeginPackage["DependencyTest`", "MaXrd`"];
context = Evaluate[Context[] <> "*"];
privateContext = Evaluate[Context[] <> "Private`*"];
Unprotect @@ Names[context];
Unprotect[context];
ClearAll @@ Names[context];
ClearAll[privateContext];

AccessCrystalData::usage = "wrap around $CrystalData"

Begin["`Private`"];
AccessCrystalData[mpid_, n_] := Module[{crystalData},
ImportCrystalData[mpid<>".cif",mpid,"OverwriteWarning"->False];
ExpandCrystal[mpid,{n,n,n},"NewLabel"->mpid<>"_2","StoreTemporarily"->False];
crystalData = $CrystalData[[mpid<>"_2"]]
]

End[];
Protect@@Names[context];
Protect[context];
EndPackage[];

When called using Wolfram Client Library for Python:

from wolframclient.evaluation import WolframLanguageSession
from wolframclient.language import wl, wlexpr
with WolframLanguageSession() as s:
    s.evaluate(wl.Get('DependencyTest`'))
    s.evaluate(wl.SetDirectory('C:/Users/sterg/Documents/')) # assumes that 'mp-134.cif' is in Documents folder
    crystalData = s.evaluate(wl.DependencyTest.AccessCrystalData('mp-134', 1))
    print(crystalData)

I get the following warning :warning:

The symbol $CrystalData at position 1 should have an immediate value defined.

However, the output seems to be OK, except for the space group which seems to just output some unicode characters in place of 3-bar: image

Doesn't seem to affect me a ton, but kind of strange.

Upon further inspection, taking it out of the wrapper package also gives the warning:

with WolframLanguageSession() as s:
    s.evaluate(wl.Get('MaXrd`'))
    s.evaluate(wl.SetDirectory('C:/Users/sterg/Documents/')) # assumes that 'mp-134.cif' is in Documents folder
    mpid = 'mp-134'
    n = 1
    s.evaluate(wl.MaXrd.ImportCrystalData(mpid+'.cif',mpid,OverwriteWarning=False))
    s.evaluate(wl.MaXrd.ExpandCrystal(mpid,[n,n,n],NewLabel=mpid+'_2',StoreTemporarily=False))
    crystalData = s.evaluate(
        wlexpr(
            '''
            $CrystalData[["mp-134_2"]]
            '''
        )
    )
    print(crystalData)

mp-134 cif file

sgbaird commented 3 years ago

Use of $CrystalData actually seems to be causing a lot of issues for me when I'm trying to run things without a FrontEnd. Is there a way to use ImportCrystalData and ExpandCrystal without relying on $CrystalData? E.g. by outputting the association directly from ImportCrystalData and using the association as input to ExpandCrystal, etc.?

Stianpr20 commented 3 years ago

Yes, it is probably due to the way $CrystalData is defined:

$CrystalData := $CrystalData = Import[
    FileNameJoin[{$MaXrdPath, "UserData", "CrystalData.m"}], 
    "Package"];

I think it may be more orderly to redefine $CrystalData to be a String instead of an Association (or maybe create a new symbol for this: $CrystalDataFile), which can point to a default structure data file. $CrystalData could then be a computed property or we could make a simple function, e.g. CrystalData[], whose task is to import $CrystalDataFile.

The dependent functions will have to be updated, but I think it will be better this way.

In the meantime, the functions ImportCrystalData and ExpandCrystal do have a "DataFile" option. Also, you may have luck just defining $CrystalData to be an empty association early in your terminal session.