diff --git a/Applications/shapeworks/Commands.cpp b/Applications/shapeworks/Commands.cpp index 768d654a52b..d70df188204 100644 --- a/Applications/shapeworks/Commands.cpp +++ b/Applications/shapeworks/Commands.cpp @@ -592,6 +592,12 @@ bool DeepSSMCommand::execute(const optparse::Values& options, SharedCommandData& ProjectHandle project = std::make_shared(); project->load(project_file); + std::string unsupported = PythonWorker::deepssm_unsupported_reason(); + if (!unsupported.empty()) { + std::cerr << "Error: " << unsupported << "\n"; + return false; + } + // Check if PyTorch is available; install if needed if (!PythonWorker::is_torch_available()) { std::cout << "PyTorch is not installed. Installing via light-the-torch...\n"; diff --git a/Applications/shapeworks/shapeworks.cpp b/Applications/shapeworks/shapeworks.cpp index ea12ab45297..7d03f9d4504 100644 --- a/Applications/shapeworks/shapeworks.cpp +++ b/Applications/shapeworks/shapeworks.cpp @@ -3,6 +3,7 @@ */ #include +#include #include "Executable.h" #include "Commands.h" #include @@ -12,6 +13,12 @@ using namespace shapeworks; int main(int argc, char *argv[]) { + std::string os_error = ShapeWorksUtils::check_minimum_os_version(); + if (!os_error.empty()) { + std::cerr << os_error << "\n"; + return 1; + } + ShapeWorksUtils::initialize_path_handling(); Executable shapeworks; diff --git a/Examples/Python/RunUseCase.py b/Examples/Python/RunUseCase.py index aa1a175f509..1393b426081 100644 --- a/Examples/Python/RunUseCase.py +++ b/Examples/Python/RunUseCase.py @@ -6,7 +6,7 @@ binaries. This step should be common for any use of a function in ShapeWorks. __This requires the full ShapeWorks to be correctly built/downloaded!__' -For users: Please make sure you have run "source install_shapeworks.sh" (once) and "conda activate shapeworks" (each time). +For users: Run this script with the swpython that ships with ShapeWorks, e.g. "swpython RunUseCase.py ellipsoid". For developers: Please make sure you have run "source ./devenv.sh " """ @@ -42,8 +42,7 @@ except ImportError as error: print("\nError: Unable to import ShapeWorks executables, Python module, or dependencies\n") - print( - "Users: Please make sure you have run \"source install_shapeworks.sh\" (once) and \"conda activate shapeworks\" (each time)") + print("Users: Please run this script with the swpython that ships with ShapeWorks, e.g. \"swpython RunUseCase.py ellipsoid\"") print("\tSee http://sciinstitute.github.io/ShapeWorks/users/install.html for more information") print("\nDevelopers: Please make sure you have run \"source ./devenv.sh \"") diff --git a/Libs/Application/Job/PythonWorker.cpp b/Libs/Application/Job/PythonWorker.cpp index 66bb6530b39..1a944424e43 100644 --- a/Libs/Application/Job/PythonWorker.cpp +++ b/Libs/Application/Job/PythonWorker.cpp @@ -15,6 +15,7 @@ using namespace pybind11::literals; // to bring in the `_a` literal #include #include #include +#include #include #include @@ -488,7 +489,18 @@ std::string PythonWorker::get_user_site_packages() { } //--------------------------------------------------------------------------- -bool PythonWorker::is_torch_available() { +std::string PythonWorker::deepssm_unsupported_reason() { +#if defined(__APPLE__) && defined(__x86_64__) + // The last Intel macOS torch (2.2) was built against numpy 1.x and can't + // exchange arrays with the bundled numpy 2.x, so DeepSSM would fail later. + return "DeepSSM is not supported on Intel Macs: PyTorch no longer publishes Intel macOS builds that work with ShapeWorks' bundled Python. Please use an Apple Silicon Mac, Windows, or Linux for DeepSSM."; +#else + return ""; +#endif +} + +//--------------------------------------------------------------------------- +bool PythonWorker::is_torch_available(int timeout_ms) { #ifdef SHAPEWORKS_BUNDLED_PYTHON std::string python_home = find_bundled_python_home(); if (python_home.empty()) { @@ -530,7 +542,7 @@ bool PythonWorker::is_torch_available() { #endif proc.setProcessEnvironment(env); proc.start(python_exe, {"-c", "import torch"}); - proc.waitForFinished(10000); + proc.waitForFinished(timeout_ms); return proc.exitCode() == 0; #else return true; // conda workflow — assume torch is available @@ -539,6 +551,12 @@ bool PythonWorker::is_torch_available() { //--------------------------------------------------------------------------- bool PythonWorker::install_torch(std::function output_callback) { + std::string unsupported = deepssm_unsupported_reason(); + if (!unsupported.empty()) { + if (output_callback) output_callback("Error: " + unsupported); + return false; + } + #ifdef SHAPEWORKS_BUNDLED_PYTHON std::string python_home = find_bundled_python_home(); if (python_home.empty()) { @@ -564,9 +582,23 @@ bool PythonWorker::install_torch(std::function output_callbac output_callback("This may take several minutes..."); } + // pip unpacks the whole install (~7 GB with CUDA) into TMPDIR before moving it + // into --target, which overflows a small /tmp. Use a temp dir next to the + // target instead, so it's on the same disk. + QTemporaryDir pip_tmp(QFileInfo(QString::fromStdString(user_sp)).absolutePath() + "/pip-tmp-XXXXXX"); + if (!pip_tmp.isValid()) { + if (output_callback) output_callback("Error: could not create temp directory: " + pip_tmp.errorString().toStdString()); + return false; + } + // Use light-the-torch to install the correct PyTorch variant QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("TMPDIR", pip_tmp.path()); + env.insert("TEMP", pip_tmp.path()); + env.insert("TMP", pip_tmp.path()); + proc.setProcessEnvironment(env); // Connect output to callback if (output_callback) { @@ -597,6 +629,13 @@ bool PythonWorker::install_torch(std::function output_callbac return false; } + // light-the-torch can exit 0 even when pip fails (e.g. disk full), so check + // that torch actually imports. A first import of a fresh install can be slow. + if (!is_torch_available(120000)) { + if (output_callback) output_callback("Error: PyTorch installation failed; see the pip output above."); + return false; + } + if (output_callback) output_callback("PyTorch installed successfully."); return true; #else diff --git a/Libs/Application/Job/PythonWorker.h b/Libs/Application/Job/PythonWorker.h index 475e0dee900..e1b1742882d 100644 --- a/Libs/Application/Job/PythonWorker.h +++ b/Libs/Application/Job/PythonWorker.h @@ -40,9 +40,12 @@ class PythonWorker : public QObject { void abort_job(); + //! Returns why DeepSSM can't run on this platform, or "" if it can. + static std::string deepssm_unsupported_reason(); + //! Check if PyTorch is available in the bundled Python. //! Returns true if torch can be imported successfully. - static bool is_torch_available(); + static bool is_torch_available(int timeout_ms = 10000); //! Install PyTorch via light-the-torch into the user site-packages directory. //! The output_callback receives lines of output from the install process. diff --git a/Libs/Common/ShapeworksUtils.cpp b/Libs/Common/ShapeworksUtils.cpp index 99799c8cfab..a5a677e300e 100644 --- a/Libs/Common/ShapeworksUtils.cpp +++ b/Libs/Common/ShapeworksUtils.cpp @@ -15,6 +15,11 @@ #include #include +#ifdef __APPLE__ +#include +#include +#endif + namespace shapeworks { unsigned ShapeWorksUtils::rng_seed_ = std::chrono::system_clock::now().time_since_epoch().count(); @@ -27,6 +32,25 @@ void ShapeWorksUtils::set_rng_seed(const unsigned seed) { mt_.seed(rng_seed_); } +//----------------------------------------------------------------------------- +std::string ShapeWorksUtils::check_minimum_os_version() { +#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) + // e.g. 140000 for a build targeting macOS 14.0 + const int required_major = __MAC_OS_X_VERSION_MIN_REQUIRED / 10000; + char version[32] = {}; + size_t size = sizeof(version); + if (sysctlbyname("kern.osproductversion", version, &size, nullptr, 0) != 0) { + return ""; // can't tell, so don't block + } + int major = std::atoi(version); + if (major > 0 && major < required_major) { + return "ShapeWorks requires macOS " + std::to_string(required_major) + " or later. This Mac is running macOS " + + std::string(version) + "."; + } +#endif + return ""; +} + //----------------------------------------------------------------------------- void ShapeWorksUtils::initialize_path_handling() { // boost::filesystem stores a path in the character type the OS API uses: char on POSIX, but @@ -34,8 +58,11 @@ void ShapeWorksUtils::initialize_path_handling() { // into boost::filesystem::path, which by default comes from the global locale rather than being // UTF-8. The rest of ShapeWorks (Qt, VTK, ITK) speaks UTF-8, so without this a path holding // non-ASCII characters is mangled on the way in and no longer resolves. On POSIX no conversion - // takes place and this only affects the wide-string accessors. + // takes place, so skip it there: imbue() first builds boost's default locale from the + // environment, which throws (and aborts at startup) when LANG names a locale that isn't installed. +#ifdef _WIN32 boost::filesystem::path::imbue(std::locale(std::locale(), new boost::nowide::utf8_codecvt)); +#endif } //----------------------------------------------------------------------------- diff --git a/Libs/Common/ShapeworksUtils.h b/Libs/Common/ShapeworksUtils.h index d4f5cf3a72f..330b18a10c3 100644 --- a/Libs/Common/ShapeworksUtils.h +++ b/Libs/Common/ShapeworksUtils.h @@ -31,6 +31,10 @@ class ShapeWorksUtils { /// generates random number static unsigned get_random_number() { return mt_(); } + //! Returns an error message if this OS is older than ShapeWorks supports, or "" if it's fine. + //! On macOS the floor is the deployment target the build was compiled for. + static std::string check_minimum_os_version(); + //! Configure process-wide filesystem path handling. Call this once at startup, before any path //! is constructed from a narrow string. static void initialize_path_handling(); diff --git a/Python/shapeworks/shapeworks/torch_install.py b/Python/shapeworks/shapeworks/torch_install.py index 6081743121b..249b4d1ee4e 100644 --- a/Python/shapeworks/shapeworks/torch_install.py +++ b/Python/shapeworks/shapeworks/torch_install.py @@ -10,8 +10,10 @@ import importlib import os import platform +import shutil import subprocess import sys +import tempfile # Must match PythonWorker::python_api_version in Libs/Application/Job/PythonWorker.h. # Bump alongside SW_MAJOR_VERSION / SW_MINOR_VERSION per docs/dev/release-checklist. @@ -36,6 +38,15 @@ def _add_user_site_to_path(): sys.path.insert(0, user_site) +_INTEL_MAC_MESSAGE = ( + "DeepSSM is not supported on Intel Macs: PyTorch no longer publishes Intel macOS builds that work with ShapeWorks' bundled Python. Please use an Apple Silicon Mac, Windows, or Linux for DeepSSM." +) + + +def _is_intel_mac(): + return platform.system() == "Darwin" and platform.machine() == "x86_64" + + def is_torch_available(): """Return True if torch can be imported (after adding the user-site path).""" _add_user_site_to_path() @@ -53,6 +64,11 @@ def ensure_torch(): ShapeWorks Studio and `shapeworks deepssm` use, via light-the-torch (which selects the correct CUDA/CPU wheel for the host). """ + # The last Intel macOS torch (2.2) was built against numpy 1.x and can't + # exchange arrays with the bundled numpy 2.x, so DeepSSM would fail later. + if _is_intel_mac(): + raise RuntimeError(_INTEL_MAC_MESSAGE) + if is_torch_available(): return @@ -62,10 +78,18 @@ def ensure_torch(): print(f"Installing PyTorch to {user_site}") print("This may take several minutes...") - subprocess.check_call([ - sys.executable, "-m", "light_the_torch", "install", - "--target", user_site, "torch", - ]) + # pip unpacks the whole install (~7 GB with CUDA) into TMPDIR before moving + # it into --target, which overflows a small /tmp. Use a temp dir next to + # the target instead, so it's on the same disk. + pip_tmp = tempfile.mkdtemp(prefix="pip-tmp-", dir=os.path.dirname(user_site)) + env = dict(os.environ, TMPDIR=pip_tmp, TEMP=pip_tmp, TMP=pip_tmp) + try: + subprocess.check_call([ + sys.executable, "-m", "light_the_torch", "install", + "--target", user_site, "torch", + ], env=env) + finally: + shutil.rmtree(pip_tmp, ignore_errors=True) importlib.invalidate_caches() if user_site not in sys.path: @@ -75,6 +99,7 @@ def ensure_torch(): import torch # noqa: F401 print("PyTorch installed successfully.") except ImportError as e: + # light-the-torch can exit 0 even when pip fails (e.g. disk full) raise RuntimeError( - f"PyTorch install completed but cannot be imported: {e}" + f"PyTorch installation failed; see the pip output above. ({e})" ) from e diff --git a/Studio/CMakeLists.txt b/Studio/CMakeLists.txt index 6a5e028210c..7072a1ba56f 100644 --- a/Studio/CMakeLists.txt +++ b/Studio/CMakeLists.txt @@ -288,6 +288,12 @@ IF(APPLE) # set the version ($SHAPEWORKS_VERSION) SET(MACOSX_BUNDLE_SHORT_VERSION_STRING ${SHAPEWORKS_VERSION}) SET(MACOSX_BUNDLE_VERSION_STRING_STRING ${SHAPEWORKS_VERSION}) + # oldest macOS the app will launch on (LSMinimumSystemVersion) + IF(CMAKE_OSX_DEPLOYMENT_TARGET) + SET(MACOSX_BUNDLE_MINIMUM_SYSTEM_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET}) + ELSE() + SET(MACOSX_BUNDLE_MINIMUM_SYSTEM_VERSION 14.0) + ENDIF() # set where in the bundle to put the icns file SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/Resources/ShapeWorksStudio.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) diff --git a/Studio/DeepSSM/DeepSSMTool.cpp b/Studio/DeepSSM/DeepSSMTool.cpp index c5a5c3f3cc1..56b5795269c 100644 --- a/Studio/DeepSSM/DeepSSMTool.cpp +++ b/Studio/DeepSSM/DeepSSMTool.cpp @@ -875,6 +875,12 @@ void DeepSSMTool::restore_defaults() { //--------------------------------------------------------------------------- void DeepSSMTool::run_tool(DeepSSMJob::JobType job_type) { + std::string unsupported = PythonWorker::deepssm_unsupported_reason(); + if (!unsupported.empty()) { + QMessageBox::warning(this, "DeepSSM Not Supported", QString::fromStdString(unsupported)); + return; + } + // Check if PyTorch is available; if not, offer to install it if (!PythonWorker::is_torch_available()) { auto reply = QMessageBox::question(this, "PyTorch Required", diff --git a/Studio/Resources/Info.plist.in b/Studio/Resources/Info.plist.in index e01a7fb5090..9496c0c12a8 100644 --- a/Studio/Resources/Info.plist.in +++ b/Studio/Resources/Info.plist.in @@ -30,6 +30,8 @@ ${MACOSX_BUNDLE_BUNDLE_VERSION} CSResourcesFileMapped + LSMinimumSystemVersion + ${MACOSX_BUNDLE_MINIMUM_SYSTEM_VERSION} LSRequiresCarbon NSHumanReadableCopyright diff --git a/Studio/main.cpp b/Studio/main.cpp index 50175efd46d..46cbadf23e2 100644 --- a/Studio/main.cpp +++ b/Studio/main.cpp @@ -112,6 +112,13 @@ int main(int argc, char** argv) { SW_LOG("ShapeWorks Studio " SHAPEWORKS_VERSION " initializing..."); OverrideQApplication app(argc, argv); + + std::string os_error = ShapeWorksUtils::check_minimum_os_version(); + if (!os_error.empty()) { + SW_ERROR("{}", os_error); + QMessageBox::critical(nullptr, "ShapeWorks Studio", QString::fromStdString(os_error)); + return 1; + } if (PlatformUtils::is_windows()) { app.setStyle(QStyleFactory::create("Fusion")); } diff --git a/Support/osx_distribution.xml b/Support/osx_distribution.xml new file mode 100644 index 00000000000..d0dc80d497d --- /dev/null +++ b/Support/osx_distribution.xml @@ -0,0 +1,30 @@ + + + + ShapeWorks + + + + + + + + + + + + + ShapeWorks-component.pkg + diff --git a/Support/package.sh b/Support/package.sh index da5a166e431..934592b0547 100755 --- a/Support/package.sh +++ b/Support/package.sh @@ -237,7 +237,21 @@ if [[ "$OSTYPE" == "darwin"* ]]; then cp ${ROOT}/docs/users/Mac_README.txt ${VERSION}/README.txt pkgbuild --quiet --analyze --root ${VERSION} ShapeWorks.plist plutil -replace BundleIsRelocatable -bool NO ShapeWorks.plist - pkgbuild --component-plist ShapeWorks.plist --install-location /Applications/ShapeWorks --root ${VERSION} --identifier edu.utah.sci.shapeworks ${ROOT}/artifacts/${VERSION}.pkg --scripts ${ROOT}/Support/osxscripts + PKG_TMP=$(mktemp -d) + pkgbuild --component-plist ShapeWorks.plist --install-location /Applications/ShapeWorks --root ${VERSION} --identifier edu.utah.sci.shapeworks ${PKG_TMP}/ShapeWorks-component.pkg --scripts ${ROOT}/Support/osxscripts || exit 1 + + # Wrap it in a distribution package so the Installer refuses older macOS + # with a clear message instead of installing something that won't run. + MIN_MACOS=${MACOSX_DEPLOYMENT_TARGET:-14.0} + if [[ "$(uname -m)" == "arm64" ]]; then + HOST_ARCHS="arm64" + else + HOST_ARCHS="x86_64,arm64" + fi + sed -e "s/MIN_MACOS/${MIN_MACOS}/g" -e "s/HOST_ARCHS/${HOST_ARCHS}/g" \ + ${ROOT}/Support/osx_distribution.xml > ${PKG_TMP}/distribution.xml + productbuild --distribution ${PKG_TMP}/distribution.xml --package-path ${PKG_TMP} ${ROOT}/artifacts/${VERSION}.pkg || exit 1 + rm -rf ${PKG_TMP} fi cd $ROOT diff --git a/Support/shapeworks.nsi b/Support/shapeworks.nsi index 2a07c9e41d7..bed2dfa1a44 100644 --- a/Support/shapeworks.nsi +++ b/Support/shapeworks.nsi @@ -121,7 +121,7 @@ Section "Uninstall" ; Remove shortcuts, if any Delete "$SMPROGRAMS\ShapeWorks\*.*" - ${unregisterExtension} ".swprojc" "ShapeWorks Project" + ${unregisterExtension} ".swproj" "ShapeWorks Project" ; Remove directories used RMDir "$SMPROGRAMS\ShapeWorks" @@ -137,3 +137,11 @@ Function .onInit SetRegView 64 ${EndIf} FunctionEnd + +; The installer writes its registry keys in the 64-bit view, so the +; uninstaller must use the same view to remove them. +Function un.onInit + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} +FunctionEnd diff --git a/Testing/DeepSSMTests/DeepSSMTests.cpp b/Testing/DeepSSMTests/DeepSSMTests.cpp index 6783e325b90..44ae7b8ddff 100644 --- a/Testing/DeepSSMTests/DeepSSMTests.cpp +++ b/Testing/DeepSSMTests/DeepSSMTests.cpp @@ -4,6 +4,10 @@ using namespace shapeworks; //--------------------------------------------------------------------------- void run_deepssm_test(const std::string& name) { +#if defined(__APPLE__) && defined(__x86_64__) + // DeepSSM is unsupported on Intel Macs (see PythonWorker::deepssm_unsupported_reason) + GTEST_SKIP() << "DeepSSM is not supported on Intel Macs"; +#endif setupenv(std::string(TEST_DATA_DIR) + "/../DeepSSMTests"); std::string command = "bash " + name; diff --git a/Testing/UseCaseTests/UseCaseTests.cpp b/Testing/UseCaseTests/UseCaseTests.cpp index ca8ee646dca..92b1332eba0 100644 --- a/Testing/UseCaseTests/UseCaseTests.cpp +++ b/Testing/UseCaseTests/UseCaseTests.cpp @@ -60,7 +60,13 @@ TEST(UseCaseTests, left_atrium) { run_test("left_atrium"); } TEST(UseCaseTests, femur_cut) { run_test("femur_cut"); } //--------------------------------------------------------------------------- -TEST(UseCaseTests, deep_ssm) { run_test("deep_ssm"); } +TEST(UseCaseTests, deep_ssm) { +#if defined(__APPLE__) && defined(__x86_64__) + // DeepSSM is unsupported on Intel Macs (see PythonWorker::deepssm_unsupported_reason) + GTEST_SKIP() << "DeepSSM is not supported on Intel Macs"; +#endif + run_test("deep_ssm"); +} //--------------------------------------------------------------------------- TEST(UseCaseTests, supershapes_1mode_contour) { run_test("supershapes_1mode_contour"); } diff --git a/cmake/InstallBundledPython.cmake b/cmake/InstallBundledPython.cmake index bccf19baadc..a8ff9b030fd 100644 --- a/cmake/InstallBundledPython.cmake +++ b/cmake/InstallBundledPython.cmake @@ -491,6 +491,14 @@ file(MAKE_DIRECTORY "${_swpython_dir}") if(APPLE) file(WRITE "${_swpython_dir}/swpython" [=[#!/bin/bash +# Keep in sync with CMAKE_OSX_DEPLOYMENT_TARGET: older macOS fails with cryptic +# symbol errors (e.g. numpy's Accelerate build) instead of a clear message. +SW_MIN_MACOS=14 +_sw_os="$(sw_vers -productVersion 2>/dev/null)" +if [ -n "${_sw_os}" ] && [ "${_sw_os%%.*}" -lt "${SW_MIN_MACOS}" ]; then + echo "ShapeWorks requires macOS ${SW_MIN_MACOS} or later. This Mac is running macOS ${_sw_os}." >&2 + exit 1 +fi LOC="`dirname "$0"`" PYTHONHOME="${LOC}/ShapeWorksStudio.app/Contents/Resources/Python" PATH="${LOC}:${PATH}" diff --git a/docs/about/release-notes.md b/docs/about/release-notes.md index bab1bb8da88..1594ceeb6b0 100644 --- a/docs/about/release-notes.md +++ b/docs/about/release-notes.md @@ -12,6 +12,10 @@ * New `swpython` and `swpip` wrappers run scripts against the bundled Python and install additional packages into a persistent per-user site-packages directory. Windows installs add a **ShapeWorks Prompt** Start Menu shortcut that puts these on `PATH`. * PyTorch installs on demand the first time DeepSSM runs (~3 GB, one-time) via `light-the-torch`, into a per-user directory that survives reinstalls. + * **Platform support** + * macOS 14 (Sonoma) or later is now required (6.7 supported macOS 12). The installer, Studio, the `shapeworks` CLI and `swpython` refuse older macOS with a clear message. + * DeepSSM is not supported on Intel Macs: PyTorch no longer publishes Intel macOS builds compatible with the bundled Python. Studio, the CLI and `ensure_torch()` say so instead of failing partway through. + * **ShapeWorks Back-end** * Registration-based particle initialization as an alternative to particle splitting: particles are spread over a single reference shape and carried onto every other shape by deformable registration (rigid → affine → SyN over distance transforms), so each shape starts optimization already holding a full set of corresponding particles (#2374) * New `correspondence-quality` command and Python API that scores each subject by reconstructing its surface from its local particles and measuring distance back to the groomed mesh, normalized by bounding-box diagonal for comparison across anatomies (#2612) diff --git a/docs/deep-learning/deep-ssm.md b/docs/deep-learning/deep-ssm.md index 387ab655f9a..4bc65a3e6f2 100644 --- a/docs/deep-learning/deep-ssm.md +++ b/docs/deep-learning/deep-ssm.md @@ -7,6 +7,8 @@ DeepSSM is a deep learning framework that estimates statistical representations - Riddhish Bhalodia, Shireen Elhabian, Ladislav Kavan, and Ross Whitaker. DeepSSM: a deep learning framework for statistical shape modeling from raw images. In MICCAI-ShapeMI, pp. 244-257. Springer, Cham, 2018. - Riddhish Bhalodia, Anupama Goparaju, Tim Sodergren, Alan Morris, Evgueni Kholmovski, Nassir Marrouche, Joshua Cates, Ross Whitaker, Shireen Elhabian. Deep Learning for End-to-End Atrial Fibrillation Recurrence Estimation. Computing in Cardiology (CinC), 2018. +!!! warning "Not supported on Intel Macs" + PyTorch no longer publishes Intel macOS builds that work with ShapeWorks, so DeepSSM runs on Apple Silicon Macs, Windows, and Linux only. ## What is DeepSSM? diff --git a/docs/users/Mac_README.txt b/docs/users/Mac_README.txt index aba5d388d6f..4bf38ec183e 100644 --- a/docs/users/Mac_README.txt +++ b/docs/users/Mac_README.txt @@ -20,6 +20,8 @@ Welcome to ShapeWorks! ShapeWorks 6.8 ships with a complete Python environment built in. There is no conda environment to set up. +ShapeWorks requires macOS 14 (Sonoma) or later. + 1. Install the ShapeWorks .pkg file by double-clicking on the file. It installs into /Applications/ShapeWorks/. diff --git a/docs/users/install.md b/docs/users/install.md index 455f9ee74f9..72f4698bd54 100644 --- a/docs/users/install.md +++ b/docs/users/install.md @@ -111,6 +111,15 @@ This installs to your per-user ShapeWorks site-packages and persists across sess ## Installing ShapeWorks on Mac +!!! important "Requires macOS 14 (Sonoma) or later" + ShapeWorks 6.8 supports macOS 14 or later on both Apple Silicon and Intel + Macs. The installer will not install on older versions of macOS. To check + your version, choose **Apple menu > About This Mac**. + + DeepSSM is not supported on Intel Macs, because PyTorch no longer + publishes Intel macOS builds that work with ShapeWorks. Everything else + works on Intel Macs. Use an Apple Silicon Mac, Windows, or Linux for DeepSSM. + Please make sure that you download the [latest ShapeWorks binary release](https://github.com/SCIInstitute/ShapeWorks/releases/latest), or up-to-date development builds from the master branch for [Mac](https://github.com/SCIInstitute/ShapeWorks/releases/tag/dev-mac) *(remember these are in-progress development builds, not official releases).* 1. Install the ShapeWorks `.pkg` file by double-clicking it. It installs into