你已经派生过 gprMax
镜像自地址
https://gitee.com/sunhf/gprMax.git
已同步 2025-08-06 04:26:52 +08:00
310 行
12 KiB
Python
310 行
12 KiB
Python
# Copyright (C) 2015-2025: The University of Edinburgh, United Kingdom
|
|
# Authors: Craig Warren, Antonis Giannopoulos, and John Hartley
|
|
#
|
|
# This file is part of gprMax.
|
|
#
|
|
# gprMax is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# gprMax is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import glob
|
|
import os
|
|
import platform
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
from Cython.Build import cythonize
|
|
from jinja2 import Environment, FileSystemLoader
|
|
from setuptools import Extension, find_packages, setup
|
|
|
|
# Check Python version
|
|
MIN_PYTHON_VERSION = (3, 7)
|
|
if sys.version_info[:2] < MIN_PYTHON_VERSION:
|
|
sys.exit(
|
|
"\nExited: Requires Python {MIN_PYTHON_VERSION[0]}.{MIN_PYTHON_VERSION[1]} or newer!\n"
|
|
)
|
|
|
|
# Importing gprMax _version__.py before building can cause issues.
|
|
with open("gprMax/_version.py", "r") as fd:
|
|
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE)[1]
|
|
|
|
|
|
def build_dispersive_material_templates():
|
|
"""Function to generate Cython .pyx file for dispersive media update.
|
|
Jinja2 templates are used to render the various dispersive update
|
|
functions.
|
|
"""
|
|
|
|
iswin = sys.platform == "win32"
|
|
|
|
env = Environment(
|
|
loader=FileSystemLoader(os.path.join("gprMax", "cython")),
|
|
)
|
|
|
|
template = env.get_template("fields_updates_dispersive_template.jinja")
|
|
|
|
# Render dispersive template for different types
|
|
r = template.render(
|
|
functions=[
|
|
# templates for Double precision and dispersive materials with
|
|
# real susceptibility functions
|
|
{
|
|
"name_a": "update_electric_dispersive_multipole_A_double_real",
|
|
"name_b": "update_electric_dispersive_multipole_B_double_real",
|
|
"name_a_1": "update_electric_dispersive_1pole_A_double_real",
|
|
"name_b_1": "update_electric_dispersive_1pole_B_double_real",
|
|
"field_type": "double",
|
|
"dispersive_type": "double",
|
|
"iswin": iswin,
|
|
},
|
|
# templates for Float precision and dispersive materials with
|
|
# real susceptibility functions
|
|
{
|
|
"name_a": "update_electric_dispersive_multipole_A_float_real",
|
|
"name_b": "update_electric_dispersive_multipole_B_float_real",
|
|
"name_a_1": "update_electric_dispersive_1pole_A_float_real",
|
|
"name_b_1": "update_electric_dispersive_1pole_B_float_real",
|
|
"field_type": "float",
|
|
"dispersive_type": "float",
|
|
"iswin": iswin,
|
|
},
|
|
# templates for Double precision and dispersive materials with
|
|
# complex susceptibility functions
|
|
{
|
|
"name_a": "update_electric_dispersive_multipole_A_double_complex",
|
|
"name_b": "update_electric_dispersive_multipole_B_double_complex",
|
|
"name_a_1": "update_electric_dispersive_1pole_A_double_complex",
|
|
"name_b_1": "update_electric_dispersive_1pole_B_double_complex",
|
|
"field_type": "double",
|
|
"dispersive_type": "double complex",
|
|
# c function to take real part of complex double type
|
|
"real_part": "creal",
|
|
"iswin": iswin,
|
|
},
|
|
# templates for Float precision and dispersive materials with
|
|
# complex susceptibility functions
|
|
{
|
|
"name_a": "update_electric_dispersive_multipole_A_float_complex",
|
|
"name_b": "update_electric_dispersive_multipole_B_float_complex",
|
|
"name_a_1": "update_electric_dispersive_1pole_A_float_complex",
|
|
"name_b_1": "update_electric_dispersive_1pole_B_float_complex",
|
|
"field_type": "float",
|
|
"dispersive_type": "float complex",
|
|
# c function to take real part of complex double type
|
|
"real_part": "crealf",
|
|
"iswin": iswin,
|
|
},
|
|
]
|
|
)
|
|
|
|
with open(os.path.join("gprMax", "cython", "fields_updates_dispersive.pyx"), "w") as f:
|
|
f.write(r)
|
|
|
|
|
|
# Generate Cython file for dispersive materials update functions
|
|
cython_disp_file = os.path.join("gprMax", "cython", "fields_updates_dispersive.pyx")
|
|
if not os.path.isfile(cython_disp_file):
|
|
build_dispersive_material_templates()
|
|
|
|
# Process 'build' command line argument
|
|
if "build" in sys.argv:
|
|
print("Running 'build_ext --inplace'")
|
|
sys.argv.remove("build")
|
|
sys.argv.append("build_ext")
|
|
sys.argv.append("--inplace")
|
|
|
|
# Build a list of all the files that need to be Cythonized looking in gprMax
|
|
# directory
|
|
cythonfiles = []
|
|
for root, dirs, files in os.walk(os.path.join(os.getcwd(), "gprMax"), topdown=True):
|
|
for file in files:
|
|
if file.endswith(".pyx"):
|
|
cythonfiles.append(os.path.relpath(os.path.join(root, file)))
|
|
|
|
# Process 'cleanall' command line argument
|
|
if "cleanall" in sys.argv:
|
|
for file in cythonfiles:
|
|
filebase = os.path.splitext(file)[0]
|
|
# Remove Cython C files
|
|
if os.path.isfile(f"{filebase}.c"):
|
|
try:
|
|
os.remove(f"{filebase}.c")
|
|
print(f"Removed: {filebase}.c")
|
|
except OSError:
|
|
print(f"Could not remove: {filebase}.c")
|
|
# Remove compiled Cython modules
|
|
libfile = glob.glob(
|
|
os.path.join(os.getcwd(), os.path.splitext(file)[0]) + "*.pyd"
|
|
) + glob.glob(os.path.join(os.getcwd(), os.path.splitext(file)[0]) + "*.so")
|
|
if libfile:
|
|
libfile = libfile[0]
|
|
try:
|
|
os.remove(libfile)
|
|
print(f"Removed: {os.path.abspath(libfile)}")
|
|
except OSError:
|
|
print(f"Could not remove: {os.path.abspath(libfile)}")
|
|
|
|
# Remove build, dist, egg and __pycache__ directories
|
|
shutil.rmtree(Path.cwd().joinpath("build"), ignore_errors=True)
|
|
shutil.rmtree(Path.cwd().joinpath("dist"), ignore_errors=True)
|
|
shutil.rmtree(Path.cwd().joinpath("gprMax.egg-info"), ignore_errors=True)
|
|
for p in Path.cwd().rglob("__pycache__"):
|
|
shutil.rmtree(p, ignore_errors=True)
|
|
print(f"Removed: {p}")
|
|
|
|
# Remove 'gprMax/cython/fields_updates_dispersive.jinja' if its there
|
|
if os.path.isfile(cython_disp_file):
|
|
os.remove(cython_disp_file)
|
|
|
|
# Now do a normal clean
|
|
sys.argv[1] = "clean" # this is what distutils understands
|
|
|
|
else:
|
|
# Compiler options - Windows
|
|
if sys.platform == "win32":
|
|
# No static linking as no static version of OpenMP library;
|
|
# /w disables warnings
|
|
compile_args = ["/O2", "/openmp", "/w"]
|
|
linker_args = []
|
|
libraries = []
|
|
|
|
elif sys.platform == "darwin":
|
|
# Check for Intel or Apple M series CPU
|
|
cpuID = (
|
|
subprocess.check_output(
|
|
"sysctl -n machdep.cpu.brand_string",
|
|
shell=True,
|
|
stderr=subprocess.STDOUT,
|
|
)
|
|
.decode("utf-8")
|
|
.strip()
|
|
)
|
|
cpuID = " ".join(cpuID.split())
|
|
if "Apple" in cpuID:
|
|
gccbasepath = "/opt/homebrew/bin/"
|
|
else:
|
|
gccbasepath = "/usr/local/bin/"
|
|
gccpath = glob.glob(gccbasepath + "gcc-[0-9][0-9]")
|
|
if gccpath:
|
|
# Use newest gcc found
|
|
os.environ["CC"] = gccpath[-1].split(os.sep)[-1]
|
|
if "Apple" in cpuID:
|
|
rpath = "/opt/homebrew/opt/gcc/lib/gcc/" + gccpath[-1].split(os.sep)[-1][-1] + "/"
|
|
else:
|
|
raise (
|
|
f"Cannot find gcc in {gccbasepath}. gprMax requires gcc "
|
|
+ "to be installed - easily done through the Homebrew package "
|
|
+ "manager (http://brew.sh). Note: gcc with OpenMP support "
|
|
+ "is required."
|
|
)
|
|
|
|
# Set minimum supported macOS deployment target to installed macOS version
|
|
MIN_MACOS_VERSION = platform.mac_ver()[0]
|
|
try:
|
|
os.environ["MACOSX_DEPLOYMENT_TARGET"]
|
|
del os.environ["MACOSX_DEPLOYMENT_TARGET"]
|
|
except:
|
|
pass
|
|
os.environ["MIN_SUPPORTED_MACOSX_DEPLOYMENT_TARGET"] = MIN_MACOS_VERSION
|
|
# Sometimes worth testing with '-fstrict-aliasing', '-fno-common'
|
|
compile_args = [
|
|
"-O3",
|
|
"-w",
|
|
"-fopenmp",
|
|
"-march=native",
|
|
f"-mmacosx-version-min={MIN_MACOS_VERSION}",
|
|
]
|
|
linker_args = ["-fopenmp", f"-mmacosx-version-min={MIN_MACOS_VERSION}"]
|
|
libraries = ["gomp"]
|
|
|
|
elif sys.platform == "linux":
|
|
compile_args = ["-O3", "-w", "-fopenmp", "-march=native"]
|
|
linker_args = ["-fopenmp"]
|
|
libraries = []
|
|
|
|
# Build list of all the extensions - Cython source files
|
|
extensions = []
|
|
for file in cythonfiles:
|
|
tmp = os.path.splitext(file)
|
|
extension = Extension(
|
|
tmp[0].replace(os.sep, "."),
|
|
[tmp[0] + tmp[1]],
|
|
language="c",
|
|
include_dirs=[np.get_include()],
|
|
extra_compile_args=compile_args,
|
|
extra_link_args=linker_args,
|
|
libraries=libraries,
|
|
)
|
|
extensions.append(extension)
|
|
|
|
# Cythonize - build .c files
|
|
extensions = cythonize(
|
|
extensions,
|
|
compiler_directives={
|
|
"boundscheck": False,
|
|
"wraparound": False,
|
|
"initializedcheck": False,
|
|
"embedsignature": True,
|
|
"language_level": 3,
|
|
},
|
|
nthreads=None,
|
|
annotate=False,
|
|
)
|
|
|
|
# Parse long_description from README.rst file.
|
|
with open("README.rst", "r", encoding="utf-8") as fd:
|
|
long_description = fd.read()
|
|
|
|
setup(
|
|
name="gprMax",
|
|
version=version,
|
|
author="Craig Warren, Antonis Giannopoulos, and John Hartley",
|
|
url="http://www.gprmax.com",
|
|
description="Electromagnetic Modelling Software based on the "
|
|
+ "Finite-Difference Time-Domain (FDTD) method",
|
|
long_description=long_description,
|
|
long_description_content_type="text/x-rst",
|
|
license="GPLv3+",
|
|
python_requires=f">{str(MIN_PYTHON_VERSION[0])}.{str(MIN_PYTHON_VERSION[1])}",
|
|
install_requires=[
|
|
"colorama",
|
|
"cython",
|
|
"h5py",
|
|
"jinja2",
|
|
"matplotlib",
|
|
"numpy",
|
|
"psutil",
|
|
"scipy",
|
|
"terminaltables",
|
|
"tqdm",
|
|
],
|
|
ext_modules=extensions,
|
|
packages=find_packages(),
|
|
include_package_data=True,
|
|
include_dirs=[np.get_include()],
|
|
zip_safe=False,
|
|
classifiers=[
|
|
"Environment :: Console",
|
|
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
|
"Operating System :: MacOS",
|
|
"Operating System :: Microsoft :: Windows",
|
|
"Operating System :: POSIX :: Linux",
|
|
"Programming Language :: Cython",
|
|
"Programming Language :: Python :: 3",
|
|
"Topic :: Scientific/Engineering",
|
|
],
|
|
)
|