Skip to content

Commit

Permalink
Fixed a bug in the abaqus interface.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmnp19 committed Aug 2, 2024
1 parent bc9569e commit d8a450d
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 44 deletions.
4 changes: 0 additions & 4 deletions examples/abaqus_solver_fitting/config.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@

iters: 25

optimiser: botorch


parameters:
Young: [100, 100, 300]
S1: [200, 200, 400]
S2: [500, 500, 700]


objective:
name: fitting
solver:
Expand All @@ -20,7 +17,6 @@ objective:
cases:
'sample.inp':
step_name: Step-1 # optional field for this case
instance_name: Part-1-1 # optional field for this case
fields:
'reaction_x':
name: FieldsOutput
Expand Down
4 changes: 0 additions & 4 deletions examples/abaqus_solver_fitting/config_composite.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@

iters: 25

optimiser: botorch


parameters:
Young: [100, 100, 300]
S1: [200, 200, 400]
S2: [500, 500, 700]


objective:
name: fitting
composite: True
Expand All @@ -21,7 +18,6 @@ objective:
cases:
'sample.inp':
step_name: Step-1 # optional field for this case
instance_name: Part-1-1 # optional field for this case
fields:
'reaction_x':
name: FieldsOutput
Expand Down
2 changes: 0 additions & 2 deletions examples/templates/solvers/abaqus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ solver:
cases:
# Example for an input file
'sample.inp':
# If the input has only one job this field is optional
job_name: Job-1 # Job name to extract data
# If the input has only one step this field is optional
step_name: Step-1 # Step name to extract data
# If the input has only one instance this field is optional
Expand Down
13 changes: 7 additions & 6 deletions piglot/solver/abaqus/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ def __sanitize_field(field_name: str, field_list: List[str], keyword: str) -> st
raise ValueError(f"The {keyword} name '{field_name}' not found in the file.")
if field_name is None:
if len(field_list) > 1:
raise ValueError(f"Multiple {keyword}s found in the file. \
Please specify the {keyword} name.")
raise ValueError(
f"Multiple {keyword}s found in the file. Please specify the {keyword} name."
)
return field_list[0]
return field_name

Expand Down Expand Up @@ -195,12 +196,10 @@ def check(self, input_data: AbaqusInputData) -> None:
input_file, ext = os.path.splitext(os.path.basename(input_data.input_file))
with open(input_file + ext, 'r', encoding='utf-8') as file:
data = file.read()

if has_space:
nsets_list = re.findall(r'\*Nset, nset="?([^",]+)"?', data)
else:
nsets_list = re.findall(r'\*Nset, nset="?([^",\s]+)"?', data)

if len(nsets_list) == 0:
raise ValueError("No sets found in the file.")
if self.set_name not in nsets_list:
Expand Down Expand Up @@ -230,8 +229,10 @@ def get(self, input_data: AbaqusInputData) -> OutputResult:
}

# X field
field_filename = os.path.join(output_dir,
f'{input_file}_{self.set_name}_{self.x_field}.txt')
field_filename = os.path.join(
output_dir,
f'{input_file}_{self.set_name}_{self.x_field}.txt',
)
# Ensure the file exists
if not os.path.exists(field_filename):
return OutputResult(np.empty(0), np.empty(0))
Expand Down
70 changes: 54 additions & 16 deletions piglot/solver/abaqus/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ def field_location(i, variables_array, output_variable, location):
"""
variable = variables_array[i]
if variable in ['S', 'E', 'LE']:
location_output_variable = output_variable.getSubset(region=location,
position=ELEMENT_NODAL)
location_output_variable = output_variable.getSubset(
region=location,
position=ELEMENT_NODAL,
)
else:
location_output_variable = output_variable.getSubset(region=location)
return location_output_variable
Expand Down Expand Up @@ -184,16 +186,20 @@ def write_output_file(i, variables_array, variable, step, location, file_name):
component_labels = output_variable.componentLabels
# Write the column headers dynamically based on the number of nodes and output
# variable components
header = "Frame " + " ".join("%s_%d" % (label, v.nodeLabel)
for v in location_output_variable.values
for label in component_labels) + "\n"
header = "Frame " + " ".join(
"%s_%d" % (label, v.nodeLabel)
for v in location_output_variable.values
for label in component_labels
) + "\n"
output_file.write(header)
for frame in step.frames:
output_variable = frame.fieldOutputs[variable]
location_output_variable = field_location(i,
variables_array,
output_variable,
location)
location_output_variable = field_location(
i,
variables_array,
output_variable,
location,
)
output_file.write("%d " % frame.frameId)
for v in location_output_variable.values:
output_file.write(" ".join("%.9f" % value for value in v.data))
Expand All @@ -214,19 +220,31 @@ def find_case_insensitive_key(key_name, keys_list):
Returns
-------
str
The original key name from the list that matches the provided key_name, ignoring case.
Raises
------
ValueError
If the key_name is not found in the keys_list, ignoring case.
The original key name from the list, if found. Otherwise, None.
"""
keys_list_upper = [key.upper() for key in keys_list]
key_name_upper = key_name.upper()
if key_name_upper not in keys_list_upper:
raise ValueError("{} not found.".format(key_name))
return None
return keys_list[keys_list_upper.index(key_name_upper)]

def sanity_check(key_name):
"""
Check if the key name is None, and raise a ValueError if it is.
Parameters
----------
key_name : str
The name of the key to check.
Raises
------
ValueError
Raises an error if the key name is None.
"""
if key_name is None:
raise ValueError("{} not found in the output database.".format(key_name))

def main():
"""Main function to extract the nodal data from the output database (.odb) file.
"""
Expand All @@ -243,14 +261,34 @@ def main():

# Create a variable that refers to the respective step
step = odb.steps[find_case_insensitive_key(variables["step_name"], list(odb.steps.keys()))]
# Sanity check for step
sanity_check(step)

# Create a variable that refers to the instance
instance_name = find_case_insensitive_key(
variables["instance_name"],
list(odb.rootAssembly.instances.keys()),
)
# Sanity check for instance_name
sanity_check(instance_name)

# Create a variable that refers to the node set
nodeset_name = find_case_insensitive_key(
variables["set_name"],
list(odb.rootAssembly.instances[instance_name].nodeSets.keys()),
)
# if nodeset_name is empty, it gets the node sets of the assembly
if nodeset_name is None:
instance_name = None
nodeset_name = find_case_insensitive_key(
variables["set_name"],
list(odb.rootAssembly.nodeSets.keys()),
)
# Sanity check for nodeset_name
sanity_check(nodeset_name)
else:
# Sanity check for nodeset_name
sanity_check(nodeset_name)

node_sets = get_node_sets(instance_name, odb)

Expand Down
38 changes: 26 additions & 12 deletions piglot/solver/abaqus/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,26 +128,39 @@ def _run_case(self, values: np.ndarray, case: Case, tmp_dir: str) -> CaseResult:
python_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'reader.py')

run_odb = subprocess.run(
[self.abaqus_bin, 'viewer', f"noGUI={python_script}", "--",
f"input_file={variables['input_file']}", "--",
f"job_name={variables['job_name']}", "--",
f"step_name={variables['step_name']}", "--",
f"instance_name={variables['instance_name']}", "--",
f"set_name={variables['set_name']}", "--",
f"field={variables['field']}", "--",
f"x_field={variables['x_field']}"],
[
self.abaqus_bin,
'viewer',
f"noGUI={python_script}",
"--",
f"input_file={variables['input_file']}",
"--",
f"job_name={variables['job_name']}",
"--",
f"step_name={variables['step_name']}",
"--",
f"instance_name={variables['instance_name']}",
"--",
f"set_name={variables['set_name']}",
"--",
f"field={variables['field']}",
"--",
f"x_field={variables['x_field']}"
],
cwd=tmp_dir,
shell=False,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False
check=False,
)
end_time = time.time()

failed_case = (run_inp.returncode != 0 or run_odb.returncode != 0)

responses = {name: field.get(input_data) if not failed_case else
OutputResult(np.empty(0), np.empty(0)) for name, field in case.fields.items()}
responses = {
name: field.get(input_data) if not failed_case
else OutputResult(np.empty(0), np.empty(0)) for name, field in case.fields.items()
}

return CaseResult(
begin_time,
Expand Down Expand Up @@ -242,7 +255,8 @@ def read(config: Dict[str, Any], parameters: ParameterSet, output_dir: str) -> S
for case_name, case_config in config['cases'].items():
if 'fields' not in case_config:
raise ValueError(
f"Missing 'fields' in case '{case_name}' configuration.")
f"Missing 'fields' in case '{case_name}' configuration."
)
fields = {
field_name: abaqus_fields_reader(field_config)
for field_name, field_config in case_config['fields'].items()
Expand Down

0 comments on commit d8a450d

Please sign in to comment.