Skip to content

Commit

Permalink
Added Client.modules() and Model.modules().
Browse files Browse the repository at this point in the history
  • Loading branch information
john-hen committed Oct 12, 2021
1 parent e5ed645 commit c3bc8fa
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 2 deletions.
72 changes: 72 additions & 0 deletions mph/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,67 @@
########################################
log = getLogger(__package__) # event log

########################################
# Constants #
########################################

# See table on page 40 of Comsol 5.6's Programming Reference Manual.
# The following dictionary is essentially the same table with the two
# columns swapped. It maps vendor strings to product names, except that
# we shorten the product names somewhat (drop "Module" everywhere) and
# leave out the pointless trademark symbols. The dictionary keys (vendor
# strings) are what we need to query the `ModelUtil.hasProduct()`.

modules = {
'COMSOL': 'Comsol core',
'ACDC': 'AC/DC',
'ACOUSTICS': 'Acoustics',
'BATTERYDESIGN': 'Battery Design',
'CADIMPORT': 'CAD Import',
'CFD': 'CFD',
'CHEM': 'Chemical Reaction Engineering',
'CLUSTERNODE': 'Cluster Computing',
'COMPOSITEMATERIALS': 'Composite Materials',
'CORROSION': 'Corrosion',
'DESIGN': 'Design',
'ECADIMPORT': 'ECAD Import',
'ELECTROCHEMISTRY': 'Electrochemistry',
'ELECTRODEPOSITION': 'Electrodeposition',
'FATIGUE': 'Fatigue',
'CATIA5': 'File Import for Catia v5',
'FUELCELLANDELECTROLYZER': 'Fuel Cell & Electrolyzer',
'GEOMECHANICS': 'Geomechanics',
'HEATTRANSFER': 'Heat Transfer',
'LIQUIDANDGASPROPERTIES': 'Liquid & Gas Properties',
'LLAUTOCAD': 'LiveLink AutoCAD',
'LLCREOPARAMETRIC': 'LiveLink PTC Creo Parametric',
'LLEXCEL': 'LiveLink Excel',
'LLINVENTOR': 'LiveLink Inventor',
'LLMATLAB': 'LiveLink Matlab',
'LLREVIT': 'LiveLink Revit',
'LLPROENGINEER': 'LiveLink PTC Pro/ENGINEER',
'LLSOLIDEDGE': 'LiveLink Solid Edge',
'LLSOLIDWORKS': 'LiveLink SolidWorks',
'MEMS': 'MEMS',
'MICROFLUIDICS': 'Microfluidics',
'MIXER': 'Mixer',
'MOLECULARFLOW': 'Molecular Flow',
'MULTIBODYDYNAMICS': 'Multibody Dynamics',
'NONLINEARSTRUCTMATERIALS': 'Nonlinear Structural Materials',
'OPTIMIZATION': 'Optimization',
'PARTICLETRACING': 'Particle Tracing',
'PIPEFLOW': 'Pipe Flow',
'PLASMA': 'Plasma',
'POLYMERFLOW': 'Polymer Flow',
'RAYOPTICS': 'Ray Optics',
'RF': 'RF',
'ROTORDYNAMICS': 'Rotordynamics',
'SEMICONDUCTOR': 'Semiconductor',
'STRUCTURALMECHANICS': 'Structural Mechanics',
'SUBSURFACEFLOW': 'Subsurface Flow',
'WAVEOPTICS': 'Wave Optics',
}


########################################
# Client #
Expand Down Expand Up @@ -228,6 +289,17 @@ def files(self):
"""Returns the file-system paths of all loaded models."""
return [model.file() for model in self.models()]

def modules(self):
"""Returns the names of available licensed modules/products."""
names = []
for (key, value) in modules.items():
try:
if self.java.hasProduct(key):
names.append(value)
except Exception:
pass
return names

####################################
# Interaction #
####################################
Expand Down
65 changes: 64 additions & 1 deletion mph/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,65 @@
########################################
log = getLogger(__package__) # event log

########################################
# Constants #
########################################

# See table on page 40 of Comsol 5.6's Programming Reference Manual.
# The following dictionary maps the product names returned by
# `model.getUsedProducts()` to the same sanitized names used in the
# `clients` module.

modules = {
'AC/DC Module': 'AC/DC',
'Acoustics Module': 'Acoustics',
'Battery Design Module': 'Battery Design',
'CAD Import Module': 'CAD Import',
'CFD Module': 'CFD',
'COMSOL Multiphysics': 'Comsol core',
'Chemical Reaction Engineering Module': 'Chemical Reaction Engineering',
'Cluster Computing Module': 'Cluster Computing',
'Composite Materials Module': 'Composite Materials',
'Corrosion Module': 'Corrosion',
'Design Module': 'Design',
'ECAD Import Module': 'ECAD Import',
'Electrochemistry Module': 'Electrochemistry',
'Electrodeposition Module': 'Electrodeposition',
'Fatigue Module': 'Fatigue',
'File Import for CATIA V5': 'File Import for Catia v5',
'Fuel Cell & Electrolyzer Module': 'Fuel Cell & Electrolyzer',
'Geomechanics Module': 'Geomechanics',
'Heat Transfer Module': 'Heat Transfer',
'Liquid & Gas Properties Module': 'Liquid & Gas Properties',
'LiveLink™ for AutoCAD®': 'LiveLink AutoCAD',
'LiveLink™ for PTC® Creo® Parametric™': 'LiveLink PTC Creo Parametric',
'LiveLink™ for Excel®': 'LiveLink Excel',
'LiveLink™ for Inventor®': 'LiveLink Inventor',
'LiveLink™ for MATLAB®': 'LiveLink Matlab',
'LiveLink™ for Revit®': 'LiveLink Revit',
'LiveLink™ for PTC® Pro/ENGINEER®': 'LiveLink PTC Pro/ENGINEER',
'LiveLink™ for Solid Edge®': 'LiveLink Solid Edge',
'LiveLink™ for SOLIDWORKS®': 'LiveLink SolidWorks',
'MEMS Module': 'MEMS',
'Microfluidics Module': 'Microfluidics',
'Mixer Module': 'Mixer',
'Molecular Flow Module': 'Molecular Flow',
'Multibody Dynamics Module': 'Multibody Dynamics',
'Nonlinear Structural Materials Module': 'Nonlinear Structural Materials',
'Optimization Module': 'Optimization',
'Particle Tracing Module': 'Particle Tracing',
'Pipe Flow Module': 'Pipe Flow',
'Plasma Module': 'Plasma',
'Polymer Flow Module': 'Polymer Flow',
'Ray Optics Module': 'Ray Optics',
'RF Module': 'RF',
'Rotordynamics Module': 'Rotordynamics',
'Semiconductor Module': 'Semiconductor',
'Structural Mechanics Module': 'Structural Mechanics',
'Subsurface Flow Module': 'Subsurface Flow',
'Wave Optics Module': 'Wave Optics',
}


########################################
# Model #
Expand Down Expand Up @@ -178,6 +237,10 @@ def exports(self):
"""Returns the names of all exports."""
return [child.name() for child in self/'exports']

def modules(self):
"""Returns the names of modules/products required to be licensed."""
return [modules.get(key, key) for key in self.java.getUsedProducts()]

####################################
# Solving #
####################################
Expand Down Expand Up @@ -707,7 +770,7 @@ def import_(self, node, file):
if not node.exists():
error = f'Node "{node}" does not exist in model tree.'
log.error(error)
raise ValueError(error)
raise LookupError(error)
node.import_(file)

def export(self, node=None, file=None):
Expand Down
11 changes: 11 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ def test_files():
assert demo in client.files()


def test_modules():
assert 'Comsol core' in client.modules()
for key in mph.client.modules.keys():
assert client.java.hasProduct(key) in (True, False)
for value in mph.client.modules.values():
assert value in mph.model.modules.values()
mph.client.modules['invalid'] = 'invalid'
client.modules()
del mph.client.modules['invalid']


def test_caching():
assert not client.caching()
copy = client.load(demo)
Expand Down
14 changes: 13 additions & 1 deletion tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ def test_exports():
assert 'image' in model.exports()


def test_modules():
assert 'Comsol core' in model.modules()
for value in mph.model.modules.values():
assert value in mph.client.modules.values()


def test_build():
model.build()
model.build('geometry')
Expand Down Expand Up @@ -482,7 +488,7 @@ def test_import():
# Import image with file name specified as string and Path.
here = Path(__file__).resolve().parent
assert image.property('sourcetype') == 'user'
model.import_(image, str(here/'gaussian.tif'))
model.import_('functions/image', str(here/'gaussian.tif'))
assert image.property('sourcetype') == 'model'
image.java.discardData()
assert image.property('sourcetype') == 'user'
Expand Down Expand Up @@ -521,6 +527,12 @@ def test_import():
(E_re, y_re) = (E.max(), y[E.argmax()])
assert (E_re - E_pre) < 1
assert (y_re - y_pre) < 0.001
# Test error handling.
with logging_disabled():
with raises(LookupError):
model.import_('functions/does_not_exist', here/'gaussian.tif')
with raises(IOError):
model.import_(image, here/'does_not_exist.tif')
# Remove test fixtures.
model.remove('functions/image')
model.remove('functions/table')
Expand Down

0 comments on commit c3bc8fa

Please sign in to comment.