Compare commits

..

2 Commits

5 changed files with 246 additions and 17 deletions

15
TODO.md
View File

@ -13,9 +13,9 @@
- [x] Unit System
- [ ] Implement presets, including "Tidy3D" and "Blender", shown in the label row.
- [ ] Constants / Scientific Constant
- [ ] Create `utils.sci_constants` to map `scipy` constants to `sympy` units.
- [ ] Utilize `utils.sci_constants` to make it easy for the user to select appropriate constants with two-layered dropdowns.
- [x] Constants / Scientific Constant
- [x] Create `utils.sci_constants` to map `scipy` constants to `sympy` units.
- [x] Utilize `utils.sci_constants` to make it easy for the user to select appropriate constants with two-layered dropdowns.
- [x] Constants / Number Constant
- [ ] Constants / Physical Constant
- [ ] Pol: Elliptical viz as 2D plot.
@ -455,6 +455,13 @@
We're trying to do our part by reporting bugs we find!
This is where we keep track of them for now.
## Blender Maxwell Bugs
- [ ] Slow changing of socket sets / range on wave constant.
- [ ] API auth shouldn't show if everything is fine in Cloud Task socket
- [ ] Cloud task socket loads folders before its node shows, which can be slow (and error prone if offline)
- [ ] Dispersive fit is slow, which means lag on normal operations that rely on the fit result - fit computation should be integrated into the node, and the output socket should only appear when the fit is available.
- [ ] Numerical, Physical Constant is missing entries
## Blender Bugs
Reported:
- (SOLVED) <https://projects.blender.org/blender/blender/issues/119664>
@ -462,6 +469,6 @@ Reported:
Unreported:
- The `__mp_main__` bug.
# Tidy3D bugs
## Tidy3D bugs
Unreported:
- Directly running `SimulationTask.get()` is missing fields - it doesn't return some fields, including `created_at`. Listing tasks by folder is not broken.

View File

@ -1,15 +1,15 @@
# from . import scientific_constant
# from . import physical_constant
from . import blender_constant, number_constant
from . import blender_constant, number_constant, scientific_constant
BL_REGISTER = [
# *scientific_constant.BL_REGISTER,
*scientific_constant.BL_REGISTER,
*number_constant.BL_REGISTER,
# *physical_constant.BL_REGISTER,
*blender_constant.BL_REGISTER,
]
BL_NODES = {
# **scientific_constant.BL_NODES,
**scientific_constant.BL_NODES,
**number_constant.BL_NODES,
# **physical_constant.BL_NODES,
**blender_constant.BL_NODES,

View File

@ -1,6 +1,89 @@
## TODO: Discover dropdown options from sci_constants.py
import typing as typ
import bpy
from ......utils import sci_constants as constants
from .... import contracts as ct
from .... import sockets
from ... import base, events
class ScientificConstantNode(base.MaxwellSimNode):
node_type = ct.NodeType.ScientificConstant
bl_label = 'Scientific Constant'
output_sockets: typ.ClassVar = {
'Value': sockets.AnySocketDef(),
}
####################
# - Properties
####################
sci_constant: bpy.props.StringProperty(
name='Sci Constant',
description='The name of a scientific constant',
default='',
search=lambda self, _, edit_text: self.search_sci_constants(edit_text),
update=lambda self, context: self.on_update_sci_constant(context),
)
cache__units: bpy.props.StringProperty(default='')
cache__uncertainty: bpy.props.StringProperty(default='')
def search_sci_constants(
self,
edit_text: str,
):
return [
name
for name in constants.SCI_CONSTANTS
if edit_text.lower() in name.lower()
]
def on_update_sci_constant(
self,
context: bpy.types.Context,
):
if self.sci_constant:
self.cache__units = str(
constants.SCI_CONSTANTS_INFO[self.sci_constant]['units']
)
self.cache__uncertainty = str(
constants.SCI_CONSTANTS_INFO[self.sci_constant]['uncertainty']
)
else:
self.cache__units = ''
self.cache__uncertainty = ''
self.sync_prop('sci_constant', context)
####################
# - UI
####################
def draw_props(self, _: bpy.types.Context, col: bpy.types.UILayout) -> None:
col.prop(self, 'sci_constant', text='')
def draw_info(self, _: bpy.types.Context, col: bpy.types.UILayout) -> None:
if self.sci_constant:
col.label(text=f'Units: {self.cache__units}')
col.label(text=f'Uncertainty: {self.cache__uncertainty}')
col.label(text=f'Ref: {constants.SCI_CONSTANTS_REF[0]}')
####################
# - Callbacks
####################
@events.computes_output_socket('Value', props={'sci_constant'})
def compute_value(self, props: dict) -> typ.Any:
return constants.SCI_CONSTANTS[props['sci_constant']]
####################
# - Blender Registration
####################
BL_REGISTER = []
BL_NODES = {}
BL_REGISTER = [
ScientificConstantNode,
]
BL_NODES = {
ct.NodeType.ScientificConstant: (ct.NodeCategory.MAXWELLSIM_INPUTS_CONSTANTS)
}

View File

@ -2,9 +2,6 @@ import functools
import itertools
import typing as typ
from . import pydeps
with pydeps.syspath_from_bpy_prefs():
import sympy as sp
import sympy.physics.units as spu
@ -39,6 +36,20 @@ femtosecond = fs = spu.Quantity('femtosecond', abbrev='fs')
femtosecond.set_global_relative_scale_factor(spu.femto, spu.second)
####################
# - Length
####################
femtometer = fm = spu.Quantity('femtometer', abbrev='fm')
femtometer.set_global_relative_scale_factor(spu.femto, spu.meter)
####################
# - Lum Flux
####################
lumen = lm = spu.Quantity('lumen', abbrev='lm')
lumen.set_global_relative_scale_factor(1, spu.candela * spu.steradian)
####################
# - Force
####################

View File

@ -1,6 +1,134 @@
"""Access `scipy.constants` using `sympy` units.
Notes:
See <https://docs.scipy.org/doc/scipy/reference/constants.html#scipy.constants.physical_constants>
Attributes:
_SCIPY_COMBINED_UNITS: A mapping from scipy constant names to its combined unit, represented as a tuple of "base" units.
SCIPY_UNIT_TO_SYMPY_UNIT: A mapping from scipy constant names to its combined unit, represented as a tuple of "base" units.
SCI_CONSTANTS: A mapping from scipy constant names to an equivalent sympy expression.expression.
SCI_CONSTANTS_REF: Original source of constant data / choices.
"""
import functools
import scipy as sc
import sympy as sp
import sympy.physics.units as spu
# from . import extra_sympy_units as spux
from . import extra_sympy_units as spux
vac_speed_of_light = sc.constants.speed_of_light * spu.meter / spu.second
SUPPORTED_SCIPY_PREFIX = '1.12'
if not sc.version.full_version.startswith(SUPPORTED_SCIPY_PREFIX):
msg = f'The active scipy version "{sc.version.full_version}" has not been tested with the "sci_constants.py" module, which only supports scipy version(s prefixed with) "{SUPPORTED_SCIPY_PREFIX}". While the module may otherwise work, constants available in other versions of scipy may not conform to hard-coded unit lookups; as such, we throw an error, to ensure the absence of unfortunate resulting bugs'
raise RuntimeError(msg)
####################
# - Fundamental Constants
####################
vac_speed_of_light = sp.nsimplify(sc.constants.speed_of_light) * spu.meter / spu.second
hartree_energy = (
sp.nsimplify(sc.constants.physical_constants['Hartree energy in eV'][0])
* spu.electronvolt
)
####################
# - Parse scipy.constants
####################
_SCIPY_EXCLUDED_ENTRIES: set[str] = {
'Faraday constant for conventional electric current',
}
_SCIPY_COMBINED_UNITS: dict[str, tuple[str]] = {
name: tuple(cst[1].split(' '))
for name, cst in sc.constants.physical_constants.items()
if cst[1] and name not in _SCIPY_EXCLUDED_ENTRIES
}
## TODO: Better interface to the official Units section? See https://docs.scipy.org/doc/scipy/reference/constants.html#units
SCIPY_UNIT_TO_SYMPY_UNIT = {
#'C_90': spu.coulombs, ## "Conventional electric current"
'H': spu.henry,
'C^4': spu.coulombs**4,
'm^4': spu.meters**4,
'm^-1': 1 / spu.meter,
'J^-3': 1 / spu.joules**3,
's^-2': 1 / spu.second**2,
'kg': spu.kilogram,
'eV': spu.electronvolt,
'GeV': 10**9 * spu.electronvolt,
'S': spu.siemens,
'(GeV/c^2)^-2': (10**9 * spu.electronvolt / vac_speed_of_light**2) ** -2,
'GeV^-2': (10**9 * spu.electronvolt) ** -2,
'E_h': hartree_energy,
'Hz': spu.hertz,
'MeV/c': (10**6 * spu.electronvolt) / vac_speed_of_light,
'Pa': spu.pascal,
'ohm': spu.ohms,
'Wb': spu.weber,
'W^-1': 1 / spu.watt,
'u': spu.atomic_mass_constant,
'm^-3': 1 / spu.meters**3,
'J': spu.joules,
'sr^-1': 1 / spu.steradian,
'T^-1': 1 / spu.tesla,
'C^2': spu.coulombs**2,
'F': spu.farad,
'MeV': 10**6 * spu.electronvolt,
'J^-2': 1 / spu.joules**2,
'mol^-1': 1 / spu.mole,
'kg^-1': 1 / spu.kilogram,
'T^-2': 1 / spu.tesla**2,
'fm': spux.femtometer,
'V^-1': 1 / spu.volt,
'N': spu.newton,
'A': spu.ampere,
's^-1': 1 / spu.second,
'lm': spux.lumen,
'm^3': spu.meters**3,
'm^2': spu.meters**2,
'K^-1': 1 / spu.kelvin,
'm^-2': 1 / spu.meters**2,
'MHz': 10**6 * spu.hertz,
'J^-1': 1 / spu.joules,
'Hz^-1': 1 / spu.hertz,
'm': spu.meter,
'C^3': spu.coulombs**3,
'K': spu.kelvin,
'A^-2': 1 / spu.ampere**2,
'T': spu.tesla,
'K^-4': 1 / spu.kelvin**4,
'W': spu.watt,
'C': spu.coulombs,
's': spu.second,
'V': spu.volt,
}
####################
# - Extract Units
####################
SCI_CONSTANT_UNITS = {
name: functools.reduce(
lambda a, b: a * SCIPY_UNIT_TO_SYMPY_UNIT[b],
combined_unit,
sp.S(1),
)
for name, combined_unit in _SCIPY_COMBINED_UNITS.items()
}
SCI_CONSTANTS_INFO = {
name: {
'units': SCI_CONSTANT_UNITS[name],
'uncertainty': sc.constants.physical_constants[name][2],
'scipy_units': sc.constants.physical_constants[name][1],
}
for name, combined_unit in _SCIPY_COMBINED_UNITS.items()
}
SCI_CONSTANTS_REF = (
'[CODATA2018]',
'CODATA Recommended Values of the Fundamental Physical Constants 2018.',
'https://physics.nist.gov/cuu/Constants/',
)
SCI_CONSTANTS = {
name: sc.constants.physical_constants[name][0] * SCI_CONSTANT_UNITS[name]
for name, combined_unit in _SCIPY_COMBINED_UNITS.items()
}