Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue172 validate experiment setup #207

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
100 changes: 58 additions & 42 deletions buildingspy/development/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,14 @@ def _check_experiment(self, name, val, value, model_path, mos_file):
:param value: Value found in mos file.
:param model_path: Path to mo file.
:param mos_file: Path to mos file.
:return: List of error messages.

"""

errMes = ""

if("*" in str(val)):
s = (
errMes += (
"Found mo file=" +
str(model_path) +
" with experiment annotation " +
Expand All @@ -221,18 +224,17 @@ def _check_experiment(self, name, val, value, model_path, mos_file):
self._capitalize_first(name) +
" contains invalid expressions such as x * y. Only literal expressions are allowed " +
"by JModelica and OpenModelica unit tests.\n")
raise ValueError(s)

delta = abs(eval(val) - eval(value))

if (delta > 0):
s = ("Found mo file={!s} with experiment annotation {!s}.\n" +
errMes += ("Found mo file={!s} with experiment annotation {!s}.\n" +
"The value of {!s}={!s} is different from the (default) value={!s}" +
" found in the mos file={!s}.\n").format(model_path,
self._capitalize_first(name),
self._capitalize_first(name),
val, value, mos_file)
raise ValueError(s)
return errMes

def _missing_parameter(self, name, value, model_path, mos_file):
"""
Expand All @@ -242,10 +244,11 @@ def _missing_parameter(self, name, value, model_path, mos_file):
:param value: Value found in mos file.
:param model_path: Path to mo file.
:param mos_file: Path to mos file.
:return: List of error messages.

"""

s = (
errMes = (
"Found mo file={!s} without parameter {!s} defined.\n" +
"The parameter name {!s} is defined in the mos file={!s}" +
" with the value {!s}. It must hence be defined in the mo file.\n").format(
Expand All @@ -254,7 +257,7 @@ def _missing_parameter(self, name, value, model_path, mos_file):
name,
mos_file,
value)
raise ValueError(s)
return errMes

def _capitalize_first(self, name):
"""
Expand All @@ -274,9 +277,10 @@ def _missing_experiment_stoptime(self, mos_files):
Return number of mo files with experiment.

:param mos_files: List of mos files.
:return: List of error messages.

"""

errMes = ""
n_mo_files = 0
for mos_file in mos_files:
mos_path = os.path.join(os.sep, 'Resources', 'Scripts', 'Dymola')
Expand All @@ -297,16 +301,14 @@ def _missing_experiment_stoptime(self, mos_files):
if "StopTime=" in line.replace(" ", ""):
foundStop = True
if (not foundExp):
s = ("Found mo file={!s} without experiment annotation.\n").format(model_path)
raise ValueError(s)
errMes += ("Found mo file={!s} without experiment annotation.\n").format(model_path)
if (not foundStop):
s = ("Found mo file={!s} without StopTime in experiment annotation.\n").format(
errMes += ("Found mo file={!s} without StopTime in experiment annotation.\n").format(
model_path)
raise ValueError(s)

# close and exit
fm.close()
return n_mo_files
return n_mo_files, errMes

def _separate_mos_files(self, mos_files):
"""
Expand All @@ -315,7 +317,8 @@ def _separate_mos_files(self, mos_files):
and the other one with the translateModelFMU command.

:param mos_files: file path.
:return: Number of files with tolerance parameter,
:return: List of error messages
and number of files with tolerance parameter,
and two lists of mos files file, one with the simulateModel
and the other one with the translateModelFMU command.

Expand All @@ -327,6 +330,7 @@ def _separate_mos_files(self, mos_files):
n_tols = 0
n_fmus = 0
n_sim = 0
errMes = ""

for itr in mos_files:
found_sim = False
Expand All @@ -348,13 +352,12 @@ def _separate_mos_files(self, mos_files):
mos_fmus.append(itr)
i += 1
f.close()

if (found_sim and not found_tol):
s = ("Found mos file={!s} without tolerance defined.\n" +
errMes += ("Found mos file={!s} without tolerance defined.\n" +
"A minimum tolerance of 1e-6 is required for JModelica.\n").format(itr)
raise ValueError(s)

return n_tols, mos_non_fmus, mos_fmus
return errMes, n_tols, mos_non_fmus, mos_fmus

def _check_tolerance(self, content, name, value, mos_file):
"""
Expand All @@ -364,11 +367,14 @@ def _check_tolerance(self, content, name, value, mos_file):
:param name: variable name.
:param value: variable value.
:param mos_file: mos file.
:return: List of error messages.

"""

if (name + "=" == "tolerance=" and float(value) > 1e-6):
self._wrong_parameter(mos_file, name, value)
return self._wrong_parameter(mos_file, name, value)
else:
return ""

def _wrong_parameter(self, mos_file, name, value):
"""
Expand All @@ -377,28 +383,29 @@ def _wrong_parameter(self, mos_file, name, value):
:param mos_file: mos file.
:param name: parameter name.
:param value: parameter value.
:return: List of error messages.

"""

errMes = ""

if (name + "=" == "tolerance="):
if value is None:
s = (
errMes += (
"Found mos file={!s} without tolerance specified.\n" +
"A minimum tolerance of 1e-6 is required for JModelica for unit tests.\n").format(mos_file)
raise ValueError(s)
else:
if(float(value) > 1e-6):
s = ("Found mos file={!s} with tolerance={!s}.\n"
errMes += ("Found mos file={!s} with tolerance={!s}.\n"
"The tolerance found is bigger than 1e-6, the maximum required by "
"JModelica for unit tests.\n").format(mos_file, value)
raise ValueError(s)

if (name + "=" == "stopTime="):
if value is None:
s = (
errMes += (
"Found mos file={!s} without stopTime specified.\n" +
"A non-null stopTime is required by OpenModelica for unit tests.\n").format(mos_file)
raise ValueError(s)
return errMes

def _getValue(self, name, line, fil_nam):
"""
Expand Down Expand Up @@ -429,17 +436,19 @@ def _wrong_literal(self, mos_file, name):

:param mos_file: mos file.
:param name: Parameter name.
:return: List of error messages.


"""

s = (
errMes = (
"Found mos file={!s} with invalid expression={!s}.\n" +
"This is not allowed for cross validation with JModelica.\n").format(
mos_file,
name +
'=' +
name)
raise ValueError(s)
return errMes

def _validate_experiment_setup(self, name, mos_files):
"""
Expand All @@ -451,6 +460,8 @@ def _validate_experiment_setup(self, name, mos_files):

N_mos_defect = 0

errMes = ""

j = 1
for mos_file in mos_files:
j += 1
Expand All @@ -470,11 +481,11 @@ def _validate_experiment_setup(self, name, mos_files):
try:
if name + "=" + name in line.replace(" ", ""):
value = name
self._wrong_literal(mos_file, name)
errMes += self._wrong_literal(mos_file, name)

if name + "=" in line.replace(" ", ""):
value = self._getValue(name, line.replace(" ", ""), mos_file)
self._check_tolerance(content, name, value, mos_file)
errMes += self._check_tolerance(content, name, value, mos_file)
else:
found = False
while not found and i < len(content):
Expand All @@ -484,18 +495,18 @@ def _validate_experiment_setup(self, name, mos_files):
if name + "=" in line.replace(" ", ""):
found = True
value = self._getValue(name, line.replace(" ", ""), mos_file)
self._check_tolerance(content, name, value, mos_file)
errMes += self._check_tolerance(content, name, value, mos_file)
if name + "=" + name in line.replace(" ", ""):
value = name
self._wrong_literal(mos_file, name)
errMes += self._wrong_literal(mos_file, name)
if not found:
if (name == "startTime"):
value = "0.0"
elif (name == "stopTime"):
value = "1.0"
elif(name == "tolerance"):
value = None
self._wrong_parameter(mos_file, name, value)
errMes += self._wrong_parameter(mos_file, name, value)

except AttributeError:
N_mos_defect += 1
Expand Down Expand Up @@ -526,17 +537,17 @@ def _validate_experiment_setup(self, name, mos_files):

# Check if attributes StartTime/startTime are defined in mos and mo
if (name + "=" == "startTime=" and abs(eval(value)) > 0.0 and (not foundStartExp_mo)):
self._missing_parameter(name, value, model_path, mos_file)
errMes += self._missing_parameter(name, value, model_path, mos_file)

# Check if attributes StopTime/stopTime are defined in mos and mo
if (name + "=" == "stopTime=" and abs(eval(value) - 1.0) >
0.0 and (not foundStopExp_mo)):
self._missing_parameter(name, value, model_path, mos_file)
errMes += self._missing_parameter(name, value, model_path, mos_file)

# Check if attributes Tolerance/tolerance are defined in mos and mo
if (name + "=" == "tolerance=" and abs(eval(value)) >
0.0 and (not foundToleranceExp_mo)):
self._missing_parameter(name, value, model_path, mos_file)
errMes += self._missing_parameter(name, value, model_path, mos_file)

for i in range(Nlines - 1, 0, -1):
line = model_content[i]
Expand All @@ -545,14 +556,15 @@ def _validate_experiment_setup(self, name, mos_files):
if self._capitalize_first(name) + "=" in line.replace(" ", "") and not found:
val = self._getValue(self._capitalize_first(
name), line.replace(" ", ""), model_path)
self._check_experiment(name, val, value, model_path, mos_file)
errMes += self._check_experiment(name, val, value, model_path, mos_file)
found = True

fm.close()
elif value == name:
self._wrong_literal(model_path, name)
errMes += self._wrong_literal(model_path, name)

f.close()
return errMes

def validateExperimentSetup(self, root_dir):
"""
Expand All @@ -563,11 +575,12 @@ def validateExperimentSetup(self, root_dir):
"""

# Make sure that the parameter root_dir points to a Modelica package.
errMes = ""

topPackage = os.path.join(root_dir, "package.mo")
if not os.path.isfile(topPackage):
s = ("Argument root_dir={!s} is not a Modelica package.\n" +
errMes += ("Argument root_dir={!s} is not a Modelica package.\n" +
"Expected file={!s}.\n").format(root_dir, topPackage)
raise ValueError(s)

# Get the path to the mos files
rootPackage = os.path.join(root_dir, 'Resources', 'Scripts', 'Dymola')
Expand All @@ -576,16 +589,19 @@ def validateExperimentSetup(self, root_dir):
mos_files = self._recursive_glob(rootPackage, '.mos')

# Split mos files which either contain simulateModel or translateModelFMU
n_tols, mos_non_fmus, _ = self._separate_mos_files(mos_files)
errMesRes, n_tols, mos_non_fmus, _ = self._separate_mos_files(mos_files)
errMes += errMesRes

# Check if all .mo files contain experiment annotation
n_mo_files = self._missing_experiment_stoptime(mos_non_fmus)
n_mo_files, errMesRes = self._missing_experiment_stoptime(mos_non_fmus)
errMes += errMesRes

# Validate model parameters
for i in ["stopTime", "tolerance", "startTime"]:
self._validate_experiment_setup(i, mos_non_fmus)

if(n_tols != n_mo_files):
s = ("The number of tolerances in the mos files={!s} does no match " +
errMes += ("The number of tolerances in the mos files={!s} does no match " +
"the number of mo files={!s}.\n").format(n_tols, n_mo_files)
raise ValueError(s)
if len(errMes)>0:
raise ValueError(errMes)