Skip to content
Merged

Units #935

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 22 additions & 14 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Move nutils directory
run: mv nutils _nutils
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
Expand Down Expand Up @@ -153,25 +151,37 @@ jobs:
run: python -um devtools.gha.delete_coverage_artifacts
test-examples:
needs: build-python-package
name: 'Test examples ${{ matrix.os }}'
name: 'Test ${{ matrix.example }} on ${{ matrix.os }}'
runs-on: ${{ matrix.os }}-latest
strategy:
matrix:
example:
- adaptivity
- burgers
- cahnhilliard
- coil
- cylinderflow
- drivencavity
- elasticity
- finitestrain
- laplace
- platewithhole
- poisson
- torsion
- turek
os: [ubuntu, macos, windows]
fail-fast: false
env:
_wheel: ${{ needs.build-python-package.outputs.wheel }}
NUTILS_MATRIX: scipy
NUTILS_NPROCS: 1
NUTILS_DEBUG: all
OMP_NUM_THREADS: 1
VECLIB_MAXIMUM_THREADS: 1
PYTHONHASHSEED: 0
PYTHONUTF8: 1 # pending https://github.com/pypa/pip/pull/13862
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Move nutils directory
run: mv nutils _nutils
- name: Set up Python
uses: actions/setup-python@v5
with:
Expand All @@ -182,19 +192,17 @@ jobs:
name: python-package
path: dist/
- name: Install Gmsh
# install gmsh via pip on windows and macos and via apt on linux, as
# the latter version is dynamically linked and requires libgl etc.
run: |
${{ matrix.os == 'ubuntu' && 'sudo apt install gmsh' || 'python -um pip install gmsh' }}
echo "NUTILS_TESTING_REQUIRES=$NUTILS_TESTING_REQUIRES app:gmsh" >> $GITHUB_ENV
if: ${{ matrix.os == 'ubuntu' }}
# install gmsh dependencies on ubuntu as the pip package is dynamically linked
run: sudo apt install libglu1-mesa
- name: Install Nutils and dependencies
id: install
run: |
python -um pip install --upgrade --upgrade-strategy eager wheel
python -um pip install --upgrade --upgrade-strategy eager pip
# Install Nutils from `dist` dir created in job `build-python-package`.
python -um pip install "$_wheel[import-gmsh,matrix-scipy,export-mpl]"
python -um pip install "$_wheel" --requirements-from-script examples/${{ matrix.example }}.py
- name: Test
run: python -um unittest discover -b -q -t . -s examples
run: python -um unittest -bv examples.${{ matrix.example }}
test-sphinx:
name: Test building docs
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion devtools/container/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@

container = stack.enter_context(Container.new_from(base, mounts=[Mount(src=wheel, dst=f'/{wheel.name}')]))

container.run('pip', 'install', '--break-system-packages', '--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]', 'nutils-units', 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')
Expand Down
5 changes: 5 additions & 0 deletions examples/adaptivity.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing
from nutils.solver import System
from nutils.expression_v2 import Namespace
Expand Down
5 changes: 5 additions & 0 deletions examples/burgers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing
from nutils.solver import System
from nutils.expression_v2 import Namespace
Expand Down
40 changes: 27 additions & 13 deletions examples/cahnhilliard.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=10a6", "nutils-units>=0.2", "matplotlib>=3"]
# ///

from nutils import mesh, function, numeric, export, testing
from nutils.solver import System
from nutils.expression_v2 import Namespace
from nutils.SI import Length, Time, Density, Tension, Energy, Pressure, Velocity, parse
try:
from nutils.units.typing import Length, Time, Density, Tension, Energy, Pressure, Velocity
except ModuleNotFoundError as e:
if hasattr(e, 'add_note'):
e.add_note("Consider installing the units package via: pip install nutils-units")
raise
import numpy
import treelog as log


def main(size: Length = parse('10cm'),
epsilon: Length = parse('1mm'),
mobility: Time/Density = parse('1mL*s/kg'),
stens: Tension = parse('50mN/m'),
wtensn: Tension = parse('30mN/m'),
wtensp: Tension = parse('20mN/m'),
Mobility = Time / Density
LED = Energy / Length # linear energy density


def main(size: Length = Length('10cm'),
epsilon: Length = Length('1mm'),
mobility: Mobility = Mobility('1mL*s/kg'),
stens: Tension = Tension('50mN/m'),
wtensn: Tension = Tension('30mN/m'),
wtensp: Tension = Tension('20mN/m'),
nelems: int = 0,
etype: str = 'rectilinear',
degree: int = 1,
timestep: Time = parse('.1s'),
tol: Energy/Length = parse('1nJ/m'),
endtime: Time = parse('1min'),
timestep: Time = Time('.1s'),
tol: LED = LED('1nJ/m'),
endtime: Time = Time('1min'),
seed: int = 0,
circle: bool = True,
stable: bool = False,
Expand Down Expand Up @@ -207,14 +221,14 @@ def main(size: Length = parse('10cm'),
class test(testing.TestCase):

def test_initial(self):
args = main(epsilon=parse('5cm'), mobility=parse('1μL*s/kg'), nelems=3, degree=2, timestep=parse('1h'), endtime=parse('1h'), circle=False)
args = main(epsilon=Length('5cm'), mobility=Mobility('1μL*s/kg'), nelems=3, degree=2, timestep=Time('1h'), endtime=Time('1h'), circle=False)
with self.subTest('concentration'):
self.assertAlmostEqual64(args['φ0'], '''
eNoBYgCd/xM3LjTtNYs3MDcUyt41uc14zjo0LzKzNm812jFhNNMzwDYgzbMzV8o0yCM1rzWeypE3Tcnx
L07NzTa4NlMyETREyrPIGMxYMl82VDbjy1/M8clZyf3IRjday6XLmMl6NRnJMF4tqQ==''')

def test_square(self):
args = main(epsilon=parse('5cm'), mobility=parse('1μL*s/kg'), nelems=3, degree=2, timestep=parse('1h'), endtime=parse('2h'), circle=False)
args = main(epsilon=Length('5cm'), mobility=Mobility('1μL*s/kg'), nelems=3, degree=2, timestep=Time('1h'), endtime=Time('2h'), circle=False)
with self.subTest('concentration'):
self.assertAlmostEqual64(args['φ'], '''
eNoBYgCd/y41EjX2NZ829DXcMxUz0jTANL41ajaNNZox/9EoNRY1LDUkNZAw1cqnysI1njWdNNkxMMuk
Expand All @@ -225,7 +239,7 @@ def test_square(self):
xlrGoziaOEA3os8VyJLHk8hlyTw2sDZXydPISMoPy5zGe8i7yzfIncgAzGLKwgYwXw==''')

def test_multipatchcircle(self):
args = main(epsilon=parse('5cm'), mobility=parse('1μL*s/kg'), nelems=3, etype='multipatch', degree=2, timestep=parse('1h'), endtime=parse('2h'))
args = main(epsilon=Length('5cm'), mobility=Mobility('1μL*s/kg'), nelems=3, etype='multipatch', degree=2, timestep=Time('1h'), endtime=Time('2h'))
with self.subTest('concentration'):
self.assertAlmostEqual64(args['φ'], '''
eNoNz01IlFEUBmByEcVsWkiBoKHYoh9nvnvPOa5GcCE1gqNjDZOBBUM1iSYYEf2JEGZE0SoIokWMCCYk
Expand Down
5 changes: 5 additions & 0 deletions examples/coil.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import export, function, mesh, testing
from nutils.solver import System
from nutils.expression_v2 import Namespace
Expand Down
5 changes: 5 additions & 0 deletions examples/cylinderflow.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing, numeric
from nutils.solver import System
from nutils.expression_v2 import Namespace
Expand Down
5 changes: 5 additions & 0 deletions examples/drivencavity.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing
from nutils.solver import System, LinesearchNewton
from nutils.expression_v2 import Namespace
Expand Down
5 changes: 5 additions & 0 deletions examples/elasticity.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing
from nutils.solver import System
from nutils.expression_v2 import Namespace
Expand Down
5 changes: 5 additions & 0 deletions examples/finitestrain.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing
from nutils.solver import System, Minimize
from nutils.expression_v2 import Namespace
Expand Down
5 changes: 5 additions & 0 deletions examples/laplace.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing
from nutils.solver import System
from nutils.expression_v2 import Namespace
Expand Down
5 changes: 5 additions & 0 deletions examples/platewithhole.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing
from nutils.solver import System
from nutils.expression_v2 import Namespace
Expand Down
5 changes: 5 additions & 0 deletions examples/poisson.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing
from nutils.solver import System

Expand Down
5 changes: 5 additions & 0 deletions examples/torsion.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=9", "matplotlib>=3"]
# ///

from nutils import mesh, function, export, testing
from nutils.solver import System, Minimize
from nutils.expression_v2 import Namespace
Expand Down
20 changes: 15 additions & 5 deletions examples/turek.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["nutils>=10a6", "nutils-units>=0.2", "gmsh>=4", "meshio>=5", "matplotlib>=3"]
# ///

from nutils import cli, export, function, testing
from nutils.mesh import gmsh
from nutils.solver import System
from nutils.SI import Length, Density, Viscosity, Velocity, Time, Pressure, Acceleration
try:
from nutils.units.typing import Length, Density, Viscosity, Velocity, Time, Pressure, Acceleration
except ModuleNotFoundError as e:
if hasattr(e, 'add_note'):
e.add_note("Consider installing the units package via: pip install nutils-units")
raise
from nutils.expression_v2 import Namespace
from collections import defaultdict, deque
from dataclasses import dataclass
Expand Down Expand Up @@ -221,7 +231,7 @@ def main(domain: Domain = Domain(), solid: Optional[Solid] = Solid(), fluid: Opt
if dynamic:
ns.v, ns.a = dynamic.newmark_defo(ns.d)
else:
ns.a = Acceleration.wrap(function.zeros((2,)))
ns.a = numpy.repeat(Acceleration.zero, 2)

# Deformed geometry
ns.x_i = 'xref_i + d_i'
Expand Down Expand Up @@ -260,8 +270,8 @@ def main(domain: Domain = Domain(), solid: Optional[Solid] = Solid(), fluid: Opt
else: # fully rigid solid

ns.x = ns.xref
ns.v = Velocity.wrap(function.zeros((2,)))
ns.a = Acceleration.wrap(function.zeros((2,)))
ns.v = numpy.repeat(Velocity.zero, 2)
ns.a = numpy.repeat(Acceleration.zero, 2)

if fluid:

Expand Down Expand Up @@ -339,7 +349,7 @@ def main(domain: Domain = Domain(), solid: Optional[Solid] = Solid(), fluid: Opt

DL = uxy = None # for unit tests only

for t in log.iter.fraction('timestep', dynamic.times) if dynamic else [Time.wrap(float('inf'))]:
for t in log.iter.fraction('timestep', dynamic.times) if dynamic else [Time.zero * float('inf')]:

if dynamic:
if solid:
Expand Down
4 changes: 3 additions & 1 deletion nutils/SI.py → src/nutils/SI.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@
import typing
import numpy
from functools import partial, partialmethod, reduce
from . import function, topology, sample
from . import function, topology, sample, warnings

warnings.deprecation("nutils.SI is deprecated and will be removed in Nutils 11; please use the externally installable nutils.units instead (pip install nutils-units)")


class DimensionError(TypeError):
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions nutils/unit.py → src/nutils/unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
'''

import re
from . import warnings

warnings.deprecation("nutils.unit is deprecated and will be removed in Nutils 11; please use the externally installable nutils.units instead (pip install nutils-units)")


def create(_typename='unit', **units):
Expand Down
File renamed without changes.
Loading