Source code for mpas_tools.mesh.creation.jigsaw_driver

import argparse
import os
import platform
import shutil
import subprocess
import time
from importlib.resources import files as imp_res_files
from pathlib import Path

import numpy

from mpas_tools.logging import check_call


[docs] def jigsaw_driver( cellWidth, x, y, on_sphere=True, earth_radius=6371.0e3, geom_points=None, geom_edges=None, logger=None, ): """ A function for building a jigsaw mesh Parameters ---------- cellWidth : ndarray The size of each cell in the resulting mesh as a function of space x, y : ndarray The x and y coordinates of each point in the cellWidth array (lon and lat for spherical mesh) on_sphere : logical, optional Whether this mesh is spherical or planar earth_radius : float, optional Earth radius in meters geom_points : ndarray, optional list of point coordinates for bounding polygon for planar mesh geom_edges : ndarray, optional list of edges between points in geom_points that define the bounding polygon logger : logging.Logger, optional A logger for the output if not stdout """ try: import jigsawpy from jigsawpy.savejig import savejig except ImportError as err: raise ImportError( 'JIGSAW and/or jigsaw-python is not installed. ' 'Please install them in the conda environment.' ) from err # Authors # ------- # Mark Petersen, Phillip Wolfram, Xylar Asay-Davis # setup files for JIGSAW opts = jigsawpy.jigsaw_jig_t() opts.geom_file = 'mesh.msh' opts.jcfg_file = 'mesh.jig' opts.mesh_file = 'mesh-MESH.msh' opts.hfun_file = 'mesh-HFUN.msh' # save HFUN data to file hmat = jigsawpy.jigsaw_msh_t() if on_sphere: hmat.mshID = 'ELLIPSOID-GRID' hmat.xgrid = numpy.radians(x) hmat.ygrid = numpy.radians(y) else: hmat.mshID = 'EUCLIDEAN-GRID' hmat.xgrid = x hmat.ygrid = y hmat.value = cellWidth jigsawpy.savemsh(opts.hfun_file, hmat) # define JIGSAW geometry geom = jigsawpy.jigsaw_msh_t() if on_sphere: geom.mshID = 'ELLIPSOID-MESH' geom.radii = earth_radius * 1e-3 * numpy.ones(3, float) else: geom.mshID = 'EUCLIDEAN-MESH' geom.vert2 = geom_points geom.edge2 = geom_edges jigsawpy.savemsh(opts.geom_file, geom) # build mesh via JIGSAW! opts.hfun_scal = 'absolute' opts.hfun_hmax = float('inf') opts.hfun_hmin = 0.0 opts.mesh_dims = +2 # 2-dim. simplexes opts.optm_qlim = 0.9375 opts.verbosity = +1 savejig(opts.jcfg_file, opts) check_call(['jigsaw', opts.jcfg_file], logger=logger)
[docs] def build_jigsaw(logger=None, clone=False, subdir='jigsaw-python', hash=None): """ Build the JIGSAW and JIGSAW-Python tools using conda-forge compilers Parameters ---------- logger : logging.Logger, optional A logger for the output if not stdout clone : bool, optional If True, clone the jigsaw-python repository from github and build it. If False, just build the existing repository. subdir : str, optional The subdirectory where the jigsaw-python repository is located or will be cloned. Default is 'jigsaw-python'. hash : str, optional A git hash to checkout after cloning the repository. Ignored if `clone` is False. If None and `clone` is True, the latest version will be used. """ conda_env_path = os.getenv('CONDA_PREFIX') if conda_env_path is None: raise EnvironmentError( 'The CONDA_PREFIX environment variable is not defined. ' 'Please activate a conda environment where you want to install ' 'jigsaw and jigsawpy before running this function.' ) conda_exe = os.getenv('CONDA_EXE') if conda_exe is None: raise EnvironmentError( 'The CONDA_EXE environment variable is not defined. ' 'Please ensure conda is installed and accessible.' ) conda_base = os.path.dirname(os.path.dirname(conda_exe)) conda_sh_path = os.path.join(conda_base, 'etc', 'profile.d', 'conda.sh') activate_env = ( f'source {conda_sh_path} && conda activate {conda_env_path} && ' ) # remove conda jigsaw and jigsaw-python t0 = time.time() commands = ( f'{activate_env}' f'pip uninstall -y jigsawpy; ' f'conda remove -y --force-remove jigsaw jigsawpy' ) try: check_call(commands, logger=logger, executable='/bin/bash', shell=True) except subprocess.CalledProcessError: # ignore errors if not installed pass if clone: url = 'https://github.com/dengwirda/jigsaw-python.git' commands = f'{activate_env}rm -rf {subdir} && git clone {url} {subdir}' if hash is not None: commands += ( f' && cd {subdir} && ' f'git -c advice.detachedHead=false checkout {hash}' ) check_call(commands, logger=logger, executable='/bin/bash', shell=True) # add build tools to deployment env, not polaris env jigsaw_build_deps = 'cmake make libnetcdf setuptools numpy scipy' if platform.system() == 'Linux': jigsaw_build_deps = ( f'{jigsaw_build_deps} sysroot_linux-64=2.17 gxx=14 openmp' ) elif platform.system() == 'Darwin': jigsaw_build_deps = ( f'{jigsaw_build_deps} ' f'macosx_deployment_target_osx-64=10.13 ' f'clangxx=19 ' f'llvm-openmp=19' ) print('Install dependencies\n') # Install dependencies commands = f'{activate_env}conda install -y {jigsaw_build_deps}' check_call(commands, logger=logger, executable='/bin/bash', shell=True) res = imp_res_files('mpas_tools.mesh.creation') / 'conda-toolchain.cmake' if not os.path.exists(str(res)): raise FileNotFoundError( f'The conda toolchain file does not exist: {res}' ) build_dir = Path(os.path.abspath(subdir)) / 'external' / 'jigsaw' / 'tmp' if os.path.exists(build_dir): shutil.rmtree(build_dir) build_dir.mkdir(parents=True) toolchain_path = build_dir / 'conda-toolchain.cmake' with res.open('rb') as src, open(toolchain_path, 'wb') as dst: shutil.copyfileobj(src, dst) conda_toolchain = str(toolchain_path) cmake_args = ( f'-DCMAKE_BUILD_TYPE=Release ' f'-DCMAKE_TOOLCHAIN_FILE="{conda_toolchain}"' ) print('Building JIGSAW\n') # Build JIGSAW commands = ( f'{activate_env}' f'cd {subdir}/external/jigsaw/tmp && ' f'cmake .. {cmake_args} && ' f'cmake --build . --config Release --target install --parallel 4' ) check_call(commands, logger=logger, executable='/bin/bash', shell=True) print('Installing JIGSAW into JIGSAW-Python\n') # Set up JIGSAW-Python commands = ( f'{activate_env}' f'cd {subdir} && ' f'rm -rf jigsawpy/_bin jigsawpy/_lib && ' f'cp -r external/jigsaw/bin/ jigsawpy/_bin && ' f'cp -r external/jigsaw/lib/ jigsawpy/_lib' ) check_call(commands, logger=logger, executable='/bin/bash', shell=True) print('Installing JIGSAW-Python\n') commands = ( f'{activate_env}' f'cd {subdir} && ' f'python -m pip install --no-deps --no-build-isolation -e . && ' f'cp jigsawpy/_bin/* ${{CONDA_PREFIX}}/bin' ) check_call(commands, logger=logger, executable='/bin/bash', shell=True) t1 = time.time() total = int(t1 - t0 + 0.5) minutes, seconds = divmod(total, 60) message = f'JIGSAW install took {minutes} min {seconds} s.' if logger is None: print(message) else: logger.info(message)
def main_build_jigsaw(): """ Entry point for building JIGSAW and JIGSAW-Python tools. """ parser = argparse.ArgumentParser( description='Build JIGSAW and JIGSAW-Python tools.' ) parser.add_argument( '--clone', dest='clone', action='store_true', help=( 'Clone the jigsaw-python repository into the directory specified ' 'with --subdir for you. If --clone is not specified, you must ' 'already have cloned it.' ), ) parser.add_argument( '--subdir', dest='subdir', default='jigsaw-python', help=( 'A subdirectory of the current work directory where the ' 'jigsaw-python repository is located or will be cloned. Default ' 'is "jigsaw-python".' ), ) parser.add_argument( '--hash', dest='hash', help=( 'A git hash to checkout after cloning the repository. ' 'Ignored if --clone is not provided. If --clone is provided and ' '--hash is not, the latest version will be used.' ), ) args = parser.parse_args() build_jigsaw(clone=args.clone, subdir=args.subdir, hash=args.hash)