diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7142b24..4df5ee3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,14 +68,16 @@ jobs: copy %P%\Library\bin\mstruct.exe dist\mstruct copy %P%\Library\bin\mstruct_xml.exe dist\mstruct copy %P%\Library\bin\fftw3.dll dist\mstruct - copy %P%\Library\bin\gsl-25.dll dist\mstruct + copy %P%\Library\bin\gsl-*.dll dist\mstruct copy %P%\Library\bin\libcblas.dll dist\mstruct copy %P%\Library\bin\zlib.dll dist\mstruct copy %P%\Library\bin\boost_python311.dll dist\mstruct copy %P%\Library\bin\boost_numpy311.dll dist\mstruct + copy %P%\Library\bin\mkl_rt*.dll dist\mstruct copy %P%\Library\bin\boost_program_options.dll dist\mstruct copy %P%\Library\bin\boost_date_time.dll dist\mstruct copy %P%\Library\bin\libMStruct.dll dist\mstruct\libMStruct.pyd + copy %P%\Library\bin\mkl_intel_thread.2.dll dist\mstruct - name: Archive distribution uses: actions/upload-artifact@v4 with: @@ -84,7 +86,7 @@ jobs: build-and-test-linux: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Checkout repository @@ -125,6 +127,13 @@ jobs: cp $P/bin/mstruct_xml dist/mstruct cp $P/lib/libMStruct.so dist/mstruct cp $P/lib/libObjCryst.so dist/mstruct + cp $P/lib/libfftw3.so.3 dist/mstruct + cp $P/lib/libgsl.so.28 dist/mstruct + cp $P/lib/libcblas.so.3 dist/mstruct + cp $P/lib/libmkl_rt.so.2 dist/mstruct + cp $P/lib/libboost_python311.so.1.78.0 dist/mstruct + cp $P/lib/libboost_numpy311.so.1.78.0 dist/mstruct + cp $P/lib/libboost_program_options.so.1.78.0 dist/mstruct - name: Archive distribution uses: actions/upload-artifact@v4 with: diff --git a/MStruct/libmstruct.cpp b/MStruct/libmstruct.cpp index db9662e..51f1a0a 100755 --- a/MStruct/libmstruct.cpp +++ b/MStruct/libmstruct.cpp @@ -147,7 +147,7 @@ MStruct::ReflectionProfile * _Create_ReflectionProfile(ObjCryst::Crystal* crysta } */ -MStruct::PowderPattern& _gRefinableObjRegistry_GetPowderpattern(const std::string& name) +MStruct::PowderPattern& _gRefinableObjRegistry_GetPowderPattern(const std::string& name) { // Get PowderPattern object ObjCryst::RefinableObj &obj = ObjCryst::gRefinableObjRegistry.GetObj(name, "MStruct::PowderPattern"); @@ -155,6 +155,14 @@ MStruct::PowderPattern& _gRefinableObjRegistry_GetPowderpattern(const std::strin return data; } +ObjCryst::Crystal& _gRefinableObjRegistry_GetCrystal(const std::string& name) +{ + // Get Crystal object + ObjCryst::RefinableObj &obj = ObjCryst::gRefinableObjRegistry.GetObj(name, "Crystal"); + ObjCryst::Crystal &crystal = dynamic_cast(obj); + return crystal; +} + // credit: @vincefn, https://github.com/diffpy/pyobjcryst/blob/main/src/extensions/lsq_ext.cpp /*bool _LSQ_SafeRefine(MStruct::LSQNumObj & lsq, REAL maxChi2factor, int nbCycle, bool useLevenbergMarquardt, @@ -239,8 +247,10 @@ BOOST_PYTHON_MODULE(libMStruct) def("CreateCrystalFromXML", &_XMLLoadCrystal, return_value_policy()); def("XMLCrystFileLoadAllObject", (void (*)(const std::string&)) &MStruct::XMLCrystFileLoadAllObject, (bp::arg("name"))); def("XMLCrystFileSaveGlobal", (void (*)(const std::string&)) &ObjCryst::XMLCrystFileSaveGlobal, (bp::arg("name"))); - def("GetPowderPattern", _gRefinableObjRegistry_GetPowderpattern, return_value_policy()); + def("GetPowderPattern", _gRefinableObjRegistry_GetPowderPattern, return_value_policy()); + def("GetCrystal", _gRefinableObjRegistry_GetCrystal, return_value_policy()); def("GetPar", _GetParExtString, return_value_policy()); + def("CalcUnitCellMass", (REAL (*)(const ObjCryst::Crystal&)) &MStruct::CalcUnitCellMass, (bp::arg("crystal"))); //def("Create_ReflectionProfile", &_Create_ReflectionProfile); class_("Restraint"); @@ -268,12 +278,36 @@ BOOST_PYTHON_MODULE(libMStruct) return_value_policy()) .def("PrepareForRefinement", &ObjCryst::RefinableObj::PrepareForRefinement) .def("Print", &ObjCryst::RefinableObj::Print) - ; - + // Virtual + .def("GetClassName", &ObjCryst::RefinableObj::GetClassName, + &ObjCryst::RefinableObj::GetClassName, + return_value_policy()) + .def("GetName", &ObjCryst::RefinableObj::GetName, + &ObjCryst::RefinableObj::GetName, + return_value_policy()); + + class_, boost::noncopyable>( + "ScatteringData", no_init) + .def("GetCrystal", (ObjCryst::Crystal& (ObjCryst::ScatteringData::*)()) &ObjCryst::ScatteringData::GetCrystal, + return_internal_reference<>()) + .def("HasCrystal", &ObjCryst::ScatteringData::HasCrystal); + + class_, boost::noncopyable> + ("_ObjCryst::PowderPatternComponent", no_init) + .def("GetParentPowderPattern", + (ObjCryst::PowderPattern& (ObjCryst::PowderPatternComponent::*)()) + &ObjCryst::PowderPatternComponent::GetParentPowderPattern, + return_internal_reference<>()); + + class_ >( + "_Obj_Cryst_PowderPatternDiffraction", no_init); + class_ >("PowderPattern") .def(init<>()) .def("SetPowderPatternObs", &_SetPowderPatternObs) .def("SetWeightToUnit", &MStruct::PowderPattern::SetWeightToUnit) + .def("SetSigmaToSqrtIobs", &MStruct::PowderPattern::SetSigmaToSqrtIobs) + .def("SetWeightToInvSigmaSq", &MStruct::PowderPattern::SetWeightToInvSigmaSq) .def("Prepare", &MStruct::PowderPattern::Prepare) .def("SetObsToZero", &_PowderPattern_SetObsToZero) .def("SavePowderPattern", &_SavePowderPattern) @@ -289,13 +323,20 @@ BOOST_PYTHON_MODULE(libMStruct) .def("Print", &MStruct::PowderPattern::Print) .def("AddComponent", &MStruct::PowderPattern::AddPowderPatternComponent) .def("AddComponent", &_AddPowderPatternComponent) - .def("FitScaleFactorForRw", &MStruct::PowderPattern::FitScaleFactorForRw); + .def("GetNbPowderPatternComponent", &ObjCryst::PowderPattern::GetNbPowderPatternComponent) + .def("GetPowderPatternComponent", (ObjCryst::PowderPatternComponent& (ObjCryst::PowderPattern::*) (const int)) + &ObjCryst::PowderPattern::GetPowderPatternComponent, return_internal_reference<>()) + .def("FitScaleFactorForRw", &MStruct::PowderPattern::FitScaleFactorForRw) + .def("GetScaleFactor", (REAL (MStruct::PowderPattern::*) (const int) const) &ObjCryst::PowderPattern::GetScaleFactor) + .def("GetScaleFactor", (REAL (MStruct::PowderPattern::*) (const ObjCryst::PowderPatternComponent&) const) &ObjCryst::PowderPattern::GetScaleFactor) + .def("SetScaleFactor", (void (MStruct::PowderPattern::*) (const int, REAL)) &ObjCryst::PowderPattern::SetScaleFactor); class_("PseudoVoigtBroadeningEffect") .def(init<>()) .def("SetParentProfile", &_SetParentProfile); - class_("Crystal"); + class_ >("Crystal") + .def("GetVolume", (REAL (ObjCryst::Crystal::*) () const) &ObjCryst::Crystal::GetVolume); //class_("ReflectionProfile", no_init); class_("ReflectionProfile", init()) @@ -315,8 +356,8 @@ BOOST_PYTHON_MODULE(libMStruct) class_("Radiation", init()) //.def("GetWavelength", &ObjCryst::Radiation::GetWavelength) .def("Print", &ObjCryst::Radiation::Print); - - class_("PowderPatternDiffraction") + + class_ >("PowderPatternDiffraction") .def(init<>()) .def("SetProfile", &_SetProfile) .def("SetIsIgnoringImagScattFact", &MStruct::PowderPatternDiffraction::SetIsIgnoringImagScattFact) diff --git a/SConscript b/SConscript index 73da1f3..10248a3 100644 --- a/SConscript +++ b/SConscript @@ -47,6 +47,7 @@ if env['PLATFORM'] == 'darwin': env.Append(SHLINKFLAGS=['-install_name', '$TARGET.abspath']) env.AppendUnique(SHLINKFLAGS='-headerpad_max_install_names') env.AppendUnique(SHLINKFLAGS=['-undefined', 'dynamic_lookup']) + env.AppendUnique(LINKFLAGS=['-Wl,-rpath,@loader_path/../lib']) fast_linkflags[:] = [] # Compiler specific options @@ -180,6 +181,14 @@ libms = Alias('libmstruct', [libmstruct,] + env['libmstruct_includes']) #if env['PLATFORM'] != 'win32': # Depends(libmstruct, lib) +# Make sure we have @rpath/libObjCryst.dylib instead of an absolute path on Darwin +if env['PLATFORM'] == 'darwin': + for f in libmstruct: + if f.get_suffix()=='.dylib': + target_name = os.path.normpath( os.path.join('build', env['build']+'-'+env['HOST_ARCH'], f.rstr()) ) + env.AddPostAction(libmstruct, + 'install_name_tool -change `otool -L ' + target_name + ' | grep libObjCryst.dylib | tail -n1 | tr -d "\\t" | cut -f1 -d " "` @rpath/libObjCryst.dylib ' + target_name) + # This builds mstruct binary executable binmstruct = env.Program("mstruct_am", binmstructobjs, LIBS=binMStructlibs, LIBPATH=MStructlibpaths) binms = Alias('mstruct', [binmstruct,] + env['binmstruct_includes']) @@ -188,17 +197,20 @@ binms = Alias('mstruct', [binmstruct,] + env['binmstruct_includes']) binxmlmstruct = env.Program("mstruct_xml", binxmlmstructobjs, LIBS=binMStructlibs, LIBPATH=MStructlibpaths) binms_xml = Alias('mstruct_xml', [binxmlmstruct,] + env['binmstruct_includes']) +# Make sure we have @rpath/libObjCryst.dylib and @rpath/libMStruct.dylib in binaries +if env['PLATFORM'] == 'darwin': + for build_obj, name in zip([binmstruct, binxmlmstruct],['mstruct_am','mstruct_xml']): + target_name = os.path.normpath( os.path.join('build', env['build']+'-'+env['HOST_ARCH'], name) ) + for libname in ['libObjCryst.dylib']: + env.AddPostAction(build_obj, + 'install_name_tool -change `otool -L ' + target_name + ' | grep ' + libname + ' | tail -n1 | tr -d "\\t" | cut -f1 -d " "` @rpath/' + libname + ' ' + target_name) + # Installation targets. prefix = env['prefix'] # install-lib libinstall = env.Install(env['libdir'], libobjcryst) -if env['PLATFORM'] == 'darwin': - # DARWIN_INSTALL_NAME can be pre-set in sconscript.local - env.SetDefault(DARWIN_INSTALL_NAME='$TARGET.abspath') - env.AddPostAction(libinstall, - 'install_name_tool -id $DARWIN_INSTALL_NAME $TARGET') if env['PLATFORM'] == 'posix' and WhereIs('ldconfig'): opts = '' if os.getuid() != 0: opts = '-n' @@ -208,11 +220,6 @@ if env['PLATFORM'] != 'win32': libinstall = env.Install(env['libdir'], libmstruct+libobjcryst) else: libinstall = env.Install(env['libdir'], [f for f in libmstruct if f.get_suffix()=='.lib']) -if env['PLATFORM'] == 'darwin': - # DARWIN_INSTALL_NAME can be pre-set in sconscript.local - env.SetDefault(DARWIN_INSTALL_NAME='$TARGET.abspath') - env.AddPostAction(libinstall, - 'install_name_tool -id $DARWIN_INSTALL_NAME $TARGET') if env['PLATFORM'] == 'posix' and WhereIs('ldconfig'): opts = '' if os.getuid() != 0: opts = '-n' @@ -248,9 +255,14 @@ Alias('install-lib', libinstall + dllinstall) # install-bin if env['PLATFORM'] == 'win32': - bininstall = env.InstallAs(prefix+'/bin/mstruct.exe', binmstruct) + env.InstallAs(prefix+'/bin/mstruct_xml.exe', binxmlmstruct) + bininstall = env.InstallAs(prefix+'/bin/mstruct.exe', binmstruct) + env.InstallAs(prefix+'/bin/mstruct_xml.exe', binxmlmstruct) else: - bininstall = env.InstallAs(prefix+'/bin/mstruct', binmstruct) + env.InstallAs(prefix+'/bin/mstruct_xml', binxmlmstruct) + bininstall = env.InstallAs(prefix+'/bin/mstruct', binmstruct) + env.InstallAs(prefix+'/bin/mstruct_xml', binxmlmstruct) +if env['PLATFORM'] == 'darwin': + # DARWIN_INSTALL_NAME can be pre-set in sconscript.local + env.SetDefault(DARWIN_INSTALL_NAME='$TARGET.abspath') + env.AddPostAction(bininstall, + 'install_name_tool -id $DARWIN_INSTALL_NAME $TARGET') Alias('install-bin', bininstall) # install-python diff --git a/doc/source/index.md b/doc/source/index.md index 887481e..6a60246 100644 --- a/doc/source/index.md +++ b/doc/source/index.md @@ -10,30 +10,30 @@ MStruct projects provides two main components: - **mstruct** program for powder diffraction data refinement - **python module** for either interactive or automated powder diffraction analysis -Windows, MacOS and Linux are all supported. However the level of intagration is varying. +Windows, macOS and Linux are all supported. However the level of intagration is varying. See the table below for a quick overview. | | Windows | macOS | Linux | |:--------------- |:-------------:|:---------:|:---------:| -| native binaries | available | - | - | -| native source | ask authors | - | available | +| native binaries | available | - | available | +| native source | depricated | - | available | | Anaconda | available | available | available | In short: -- **Windows binaries** are small (few MBs), easy to download and run but you will - miss the Python module. Maybe you do not care. +- **Windows binaries** are small (few MBs), easy to download and run. - **Anaconda** is the most universal. You will get all MStruct features without limitations but you need to have Anaconda enviroment. Anaconda occupies around 2-3 GBs. However you may use it also for something else. You will need to compile MStruct yourself, short instructions are provided, we tested it but some issues are hard to exluclude with any effort (just try it). + There is a less demanding **Miniconda** alternative. - **Linux native compilation** will give you all features and will not use much space. Compilation process is similar to Anaconda. Use of Anaconda is still adviced mainly in order to protect your system against dirty MStruct features :-) @@ -83,7 +83,7 @@ git clone https://github.com/xray-group/mstruct.git ##### Installing Anaconda [Anaconda](https://www.anaconda.com) is a popular Python data science platform and -scientific software for personal computers with Windows, MacOS or Linux. +scientific software for personal computers with Windows, macOS or Linux. The most straighforward way is to get a graphical [installer](https://www.anaconda.com/download/) - no need to sign (web download) @@ -117,7 +117,7 @@ For Windows **Python3 (x64) is strongly adviced!** # add 'conda-forge' channel conda config --add channels conda-forge # install required packages -conda install python=3.11 boost=1.78 lapack fftw gsl scons bzip2 git blas=*=*mkl +conda install python=3.11 boost=1.78 lapack fftw gsl scons bzip2 git blas=*=*mkl gcc gxx # git clone or download ZIP # git clone https://github.com/xray-group/mstruct.git @@ -262,18 +262,18 @@ tricks from Honza ```bash # (optional) gls, fftw3, lapack, python and scons are required -sudo apt-get install libgsl-dev fftw3-dev liblapack-dev python-dev scons +sudo apt-get install libgsl-dev libfftw3-dev liblapack-dev libpython3.11-dev scons # (optional) boost>=1.63 is required, we may want to use a specific one -export B=~/sw/boost_1_67_0 -export CPPPATH=$B/include:$CPPPATH/ +export B=~/sw/boost_1_78_0 +export CPPPATH=$B/include:$CPPPATH export LIBRARY_PATH=$B/lib:$LIBRARY_PATH export LD_LIBRARY_PATH=$B/lib:$LD_LIBRARY_PATH # (optional) prepare user env for installation (define prefix) export P=~/.local # (optional) make sure we have place for python modules -mkdir -p $P/lib/python2.7/site-packages +mkdir -p $P/lib/python3.11/site-packages # build library scons -j4 libmstruct @@ -286,7 +286,7 @@ scons -j4 install prefix=$P # (optional) we may want to activate the installation export PATH=$P/bin:$PATH -export PYTHONPATH=$P/lib/python2.7/site-packages:$PYTHONATH +export PYTHONPATH=$P/lib/python3.11/site-packages:$PYTHONATH export LD_LIBRARY_PATH=$P/lib:$LD_LIBRARY_PATH ``` @@ -313,7 +313,7 @@ links to plotting tools ### Instructions You should have `mstruct` binary running on your laptop. It should be pretty straighforward -for Windows, unfortunately for MacOS or Linux you need to compile the source. *No stress in +for Windows, unfortunately for macOS or Linux you need to compile the source. *No stress in case you fail, we will make it working at the beginning of the course.* ### Time plan diff --git a/libmstruct/SConstruct b/libmstruct/SConstruct index 4d392b7..d87a11a 100644 --- a/libmstruct/SConstruct +++ b/libmstruct/SConstruct @@ -42,7 +42,7 @@ env = DefaultEnvironment().Clone() # Variables definitions below work only with 0.98.1 or later. env.EnsureSConsVersion(0, 98, 1) -env['version_str'] = "0.15.8" +env['version_str'] = "0.15.10" #Adds option for selecting desired python version AddOption('--python-version', dest='python_version', type='string', help="Python version to build libmstruct against."\