MPh-py / MPh

Pythonic scripting interface for Comsol Multiphysics
https://mph.readthedocs.io
MIT License
265 stars 67 forks source link

Not all time steps returned for local evaluations #120

Closed john-hen closed 1 year ago

john-hen commented 1 year ago

Originally posted by @wacht02 in https://github.com/MPh-py/MPh/issues/112#issuecomment-1429843305

Local evaluations of field variables in parametric sweeps do not return all time steps, similar to global evaluations in #112.

demo model: time_steps_missing.zip (unzip after download)

reproducer:

import mph

client = mph.start()
model = client.load('time_steps_missing.mph')
model.solve('sweep')
(indices, values) = model.outer('parametric sweep')

for (index, value) in zip(indices, values):
    times = model.evaluate('t', 's', 'parametric sweep', outer=index)
    print(f'd = {value} mm: {len(times)} time steps')

for (index, value) in zip(indices, values):
    field = model.evaluate('ec.Ex', 'V/m', 'parametric sweep', outer=index)
    print(f'd = {value} mm: {len(field)} time steps')

output:

d = 1.0 mm: 106 time steps
d = 2.0 mm: 205 time steps
d = 3.0 mm: 304 time steps
d = 1.0 mm: 106 time steps
d = 2.0 mm: 106 time steps
d = 3.0 mm: 106 time steps
john-hen commented 1 year ago

So, as I've remarked in an earlier comment, I don't really know what MPh would be doing wrong here. Maybe nothing. Maybe this is a bug in Comsol, and that's that.

The following script reproduces, using only direct calls to the Comsol Java API, what MPh does in this case to retrieve the results for the electric field (ec.Ex) for the third parameter value (d = 3.0 mm):

import mph
from numpy import array
from numpy import squeeze

print('Starting client.')
client = mph.start()

print('Loading model.')
model = client.load('time_steps_missing.mph')

print('Solving model.')
model.solve('sweep')

expression = 'ec.Ex'
unit = 'V/m'
dataset = model/'datasets'/'parametric sweep'
assert dataset.exists()
outer = 3

print('Finding corresponding solution.')
tag = dataset.property('solution')
for solution in model/'solutions':
    if solution.tag() == tag:
        break
assert not solution.java.isEmpty()

print('Creating evaluation feature.')
eval = (model/'evaluations').create('Eval')
eval.property('expr', expression)
eval.property('unit', unit)
eval.property('data', dataset)
eval.property('outersolnum', outer)

print('Retrieving data.')
results = array(eval.java.getData())

print('Squeezing out singleton dimensions.')
results = squeeze(results)

print('Shape of final array:')
print(results.shape)

Its output is:

Starting client.
Loading model.
Solving model.
Finding corresponding solution.
Creating evaluation feature.
Retrieving data.
Squeezing out singleton dimensions.
Shape of final array:
(106, 6852)

So we get 106 instead of the expected 304 for the number of time steps.

I don't know why that happens. I don't see anything wrong with the way we call into the Comsol API. I would expect it to return the correct answer.

In #112, for global evaluation instead of local evaluations here, we essentially fixed the issue by calling the computeResult() method of the global evaluation feature, instead of the getData() method we call above. However, calling computeResult() on the local evaluation feature we have to use here (as we're evaluating a field, not a global parameter), leads to the following error:

Traceback (most recent call last):
  File "SourceFile", line 63, in com.comsol.model.impl.NumericalFeatureImpl.computeResult
Exception: Java Exception

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "eval_local_param_sweep.py", line 37, in <module>
    results = array(eval.java.computeResult())
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
com.comsol.util.exceptions.com.comsol.util.exceptions.UnknownEntityException: Exception:
        com.comsol.util.exceptions.UnknownEntityException: Unknown property
Messages:
        Unknown property
        - Property: solrepresentation

I don't know what's up with that. I may be missing something in the Comsol Programming Manual, specifically the Results chapter, but I don't see what. Again, it could be a bug (in Comsol). Hard to tell without a clear example in the Comsol documentation on how to use the API in this case.

General reminder: MPh is but a scripting interface. All it does is turn Python calls into Java calls of the Comsol API. If that doesn't work as expected, then there's nothing "we" can do on the Python side of things, unless there is a work-around, via other Comsol API calls.

If anyone wants to look into this more, please do.

john-hen commented 1 year ago

To reproduce the problem with Comsol alone:

// Create the evaluation feature. NumericalFeature eval = model.result().numerical().create("eval", "Eval"); eval.set("expr", "ec.Ex"); eval.set("unit", "V/m"); eval.set("data", "dset4"); eval.set("outersolnum", 3); debugLog("outer solution: " + eval.getInt("outersolnum"));

// Evaluate the results. double[][][] results = eval.getData(); debugLog("time steps: " + results[0].length);

* Run the method (like by pressing F8).
* The "Debug Log" shows:

outer solution: 3 time steps: 106



Question then is: What Java code do we need to run there to get the correct result?
john-hen commented 1 year ago

Closed as: upstream bug. (I.e., bug in Comsol, for all we know.)