diff --git a/devtools/container/build.py b/devtools/container/build.py index f575a767a..d0af2a7a4 100644 --- a/devtools/container/build.py +++ b/devtools/container/build.py @@ -51,8 +51,10 @@ log.info(f'installing Nutils from {wheel}') else: log.info(f'building wheel for commit {commit}') - run(sys.executable, 'setup.py', 'bdist_wheel', cwd=str(src.path), env=dict(SOURCE_DATE_EPOCH=str(src.get_commit_timestamp('HEAD')))) - wheel, = (src.path / 'dist').glob('nutils-*.whl') + dist_dir = src.path / 'dist' + dist_dir.mkdir() + run(sys.executable, '-m', 'pip', 'wheel', '--no-deps', str(src.path), cwd=str(src.path / 'dist'), env=dict(SOURCE_DATE_EPOCH=str(src.get_commit_timestamp('HEAD')))) + wheel, = dist_dir.glob('nutils-*.whl') if args.examples: examples = Path(args.examples) @@ -66,7 +68,7 @@ container = stack.enter_context(Container.new_from(base, mounts=[Mount(src=wheel, dst=f'/{wheel.name}')])) - container.run('pip', 'install', '--no-cache-dir', f'/{wheel.name}[export_mpl,import_gmsh,matrix_scipy]', env=dict(PYTHONHASHSEED='0')) + container.run('pip', 'install', '--break-system-packages', '--no-cache-dir', f'/{wheel.name}[export_mpl,import_gmsh,matrix_scipy]', env=dict(PYTHONHASHSEED='0')) container.add_label('org.opencontainers.image.url', 'https://github.com/evalf/nutils') container.add_label('org.opencontainers.image.source', 'https://github.com/evalf/nutils') container.add_label('org.opencontainers.image.authors', 'Evalf') diff --git a/devtools/container/build_base.py b/devtools/container/build_base.py index e1a42a81d..176da2d4b 100644 --- a/devtools/container/build_base.py +++ b/devtools/container/build_base.py @@ -14,12 +14,13 @@ log.info(f'building container base image with name `{image_name}`') -with Container.new_from('debian:bullseye', network='host') as container: - container.run('sed', '-i', 's/ main$/ main contrib non-free/', '/etc/apt/sources.list') +with Container.new_from('debian:bookworm', network='host') as container: + container.run('sed', '-i', 's/^Components: .*$/Components: main contrib non-free/', '/etc/apt/sources.list.d/debian.sources') container.run('apt', 'update') - # Package `libtbb2` is required when using Intel MKL with environment + # Package `libtbb12` is required when using Intel MKL with environment # variable `MKL_THREADING_LAYER` set to `TBB`, which is nowadays the default. - container.run('apt', 'install', '-y', '--no-install-recommends', 'python3', 'python3-pip', 'python3-wheel', 'python3-ipython', 'python3-numpy', 'python3-scipy', 'python3-matplotlib', 'python3-pil', 'libmkl-rt', 'libomp-dev', 'libtbb2', 'python3-gmsh', env=dict(DEBIAN_FRONTEND='noninteractive')) + container.run('apt', 'install', '-y', '--no-install-recommends', 'python3', 'python3-pip', 'python3-wheel', 'python3-ipython', 'python3-numpy', 'python3-scipy', 'python3-matplotlib', 'python3-pil', 'libmkl-rt', 'libomp-dev', 'libtbb12', 'python3-gmsh', env=dict(DEBIAN_FRONTEND='noninteractive')) + container.run('apt', 'clean') container.add_label('org.opencontainers.image.url', 'https://github.com/evalf/nutils') container.add_label('org.opencontainers.image.source', 'https://github.com/evalf/nutils') container.add_label('org.opencontainers.image.authors', 'Evalf') diff --git a/examples/platewithhole.py b/examples/platewithhole.py index 48d777650..2d0973dfd 100644 --- a/examples/platewithhole.py +++ b/examples/platewithhole.py @@ -80,7 +80,7 @@ def generate(self, radius): return topo.withboundary(hole='left', sym='top,bottom', far='right'), geom, nurbsbasis, 5 -def main(mode: Union[FCM, NURBS] = NURBS, +def main(mode: Union[FCM, NURBS] = NURBS(), radius: float = .5, traction: float = .1, poisson: float = .3): diff --git a/nutils/__init__.py b/nutils/__init__.py index b7c01351c..a2881db04 100644 --- a/nutils/__init__.py +++ b/nutils/__init__.py @@ -1,4 +1,4 @@ 'Numerical Utilities for Finite Element Analysis' -__version__ = version = '9a2' +__version__ = version = '9a3' version_name = 'jook-sing' diff --git a/nutils/points.py b/nutils/points.py index d84ee6117..9391b9429 100644 --- a/nutils/points.py +++ b/nutils/points.py @@ -288,7 +288,7 @@ class ConcatPoints(Points): triggering deduplication and resulting in a smaller total point count. ''' - def __init__(self, allpoints: Tuple[Points,...], duplicates: FrozenSet[Tuple[Tuple[Integral,Integral],...]]): + def __init__(self, allpoints: Tuple[Points,...], duplicates: FrozenSet[Tuple[Tuple[Integral,Integral],...]] = frozenset()): assert isinstance(allpoints, tuple) and all(isinstance(p, Points) for p in allpoints), 'allpoints={allpoints!r}' assert isinstance(duplicates, frozenset) and all(isinstance(d, tuple) and all(isinstance(n, tuple) and len(n) == 2 and all(isinstance(ni, Integral) for ni in n) for n in d) for d in duplicates), f'duplicates={duplicates!r}' self.allpoints = allpoints diff --git a/nutils/topology.py b/nutils/topology.py index f918a18f0..105e8dfe5 100644 --- a/nutils/topology.py +++ b/nutils/topology.py @@ -2654,7 +2654,7 @@ def locate(self, geom, coords, *, eps=0, skip_missing=False, **kwargs): if not mymissing: # no points are missing -> keep existing points object newpoints.append(points_) elif len(mymissing) < points_.npoints: # some points are missing -> create new CoordsPoints object - newpoints.append(points.CoordsPoints(points_.coords[~numeric.asboolean(mymissing, points_.npoints)])) + newpoints.append(points.CoordsPoints(types.arraydata(points_.coords[~numeric.asboolean(mymissing, points_.npoints)]))) else: # all points are missing -> remove element from return sample selection[isampleelem] = False del missing[:len(mymissing)] diff --git a/tests/test_topology.py b/tests/test_topology.py index 7f8dba317..5d1308edf 100644 --- a/tests/test_topology.py +++ b/tests/test_topology.py @@ -943,8 +943,12 @@ def test_invalidargs(self): self.domain.locate(self.geom, target, eps=1e-15, tol=1e-12, arguments=dict(scale=.123)) def test_invalidpoint(self): - target = numpy.array([(.3, 1), (.2, .3), (.1, .9), (0, 1), (.1, .3)]) - # the first point is outside the domain, but inside basetopo for mode==trimmed + target = numpy.array([(.3, .3), (.21, 1), (.2, 1), (.1, .9), (0, 1), (.1, .3), (.3, .3)]) + # The first two points are outside the domain, but inside basetopo for + # mode==trimmed, triggering a post-processing by SubsetTopology.locate. + # Moreover, the second point is in the same basetopo element as the + # third, which requires the formation of a new CoordsPoints, whereas + # the element of the first point can be dropped altogether. with self.subTest('skip_missing=False'), self.assertRaises(topology.LocateError): self.domain.locate(self.geom, target, eps=1e-15, tol=1e-12, arguments=dict(scale=.123)) with self.subTest('skip_missing=True'):