def test_mission_group_breguet_with_loop(cleanup): input_file_path = pth.join(DATA_FOLDER_PATH, "test_mission.xml") vars = VariableIO(input_file_path).read() del vars["data:mission:operational:TOW"] ivc = vars.to_ivc() problem = run_system( Mission( propulsion_id="test.wrapper.propulsion.dummy_engine", out_file=pth.join(RESULTS_FOLDER_PATH, "test_looped_mission_group.csv"), use_initializer_iteration=True, mission_file_path=pth.join(DATA_FOLDER_PATH, "test_breguet.yml"), add_solver=True, ), ivc, ) # check loop assert_allclose( problem["data:mission:operational:TOW"], problem["data:mission:operational:OWE"] + problem["data:mission:operational:payload"] + problem["data:mission:operational:block_fuel"], atol=1.0, ) assert_allclose( problem["data:mission:operational:needed_block_fuel"], problem["data:mission:operational:block_fuel"], atol=1.0, ) assert_allclose( problem["data:mission:operational:needed_block_fuel"], 5640.0, atol=1.0, )
def test_mission_group_without_loop(cleanup): input_file_path = pth.join(DATA_FOLDER_PATH, "test_mission.xml") vars = VariableIO(input_file_path).read() ivc = vars.to_ivc() with pytest.raises(FastMissionFileMissingMissionNameError): run_system( Mission( propulsion_id="test.wrapper.propulsion.dummy_engine", out_file=pth.join(RESULTS_FOLDER_PATH, "test_unlooped_mission_group.csv"), use_initializer_iteration=False, mission_file_path=pth.join(DATA_FOLDER_PATH, "test_mission.yml"), adjust_fuel=False, ), ivc, ) problem = run_system( Mission( propulsion_id="test.wrapper.propulsion.dummy_engine", out_file=pth.join(RESULTS_FOLDER_PATH, "test_unlooped_mission_group.csv"), use_initializer_iteration=False, mission_file_path=pth.join(DATA_FOLDER_PATH, "test_mission.yml"), mission_name="operational", adjust_fuel=False, ), ivc, ) assert_allclose(problem["data:mission:operational:needed_block_fuel"], 6589.0, atol=1.0) assert_allclose(problem["data:mission:operational:block_fuel"], 15000.0, atol=1.0)
def generate_block_analysis( system: Union[ExplicitComponent, ImplicitComponent, Group], var_inputs: List, xml_file_path: str, overwrite: bool = False, ): # Search what are the component/group outputs variables = list_variables(system) inputs_names = [var.name for var in variables if var.is_input] outputs_names = [var.name for var in variables if not var.is_input] # Check that variable inputs are in the group/component list if not(set(var_inputs) == set(inputs_names).intersection(set(var_inputs))): raise Exception('The input list contains name(s) out of component/group input list!') # Perform some tests on the .xml availability and completeness if not(os.path.exists(xml_file_path)) and not(set(var_inputs) == set(inputs_names)): # If no input file and some inputs are missing, generate it and return None if isinstance(system, Group): problem = FASTOADProblem(system) else: group = AutoUnitsDefaultGroup() group.add_subsystem('system', system, promotes=["*"]) problem = FASTOADProblem(group) problem.input_file_path = xml_file_path problem.setup() problem.write_needed_inputs(None, VariableXmlStandardFormatter()) raise Exception('Input .xml file not found, a default file has been created with default NaN values, ' 'but no function is returned!\nConsider defining proper values before second execution!') elif os.path.exists(xml_file_path): reader = VariableIO(xml_file_path, VariableXmlStandardFormatter()).read(ignore=(var_inputs + outputs_names)) xml_inputs = reader.names() if not(set(xml_inputs + var_inputs).intersection(set(inputs_names)) == set(inputs_names)): # If some inputs are missing write an error message and add them to the problem if authorized missing_inputs = list( set(inputs_names).difference(set(xml_inputs + var_inputs).intersection(set(inputs_names))) ) message = 'The following inputs are missing in .xml file:' for item in missing_inputs: message += ' [' + item + '],' message = message[:-1] + '.\n' if overwrite: reader.path_separator = ":" ivc = reader.to_ivc() group = AutoUnitsDefaultGroup() group.add_subsystem('system', system, promotes=["*"]) group.add_subsystem('ivc', ivc, promotes=["*"]) problem = FASTOADProblem(group) problem.input_file_path = xml_file_path problem.output_file_path = xml_file_path problem.setup() problem.write_outputs() message += 'Default values have been added to {} file. ' \ 'Consider modifying them for a second run!'.format(xml_file_path) raise Exception(message) else: raise Exception(message) else: # If all inputs addressed either by .xml or var_inputs, construct the function def patched_function(inputs_dict: dict) -> dict: """ The patched function perform a run of an openmdao component or group applying FASTOAD formalism. @param inputs_dict: dictionary of input (values, units) saved with their key name, as an example: inputs_dict = {'in1': (3.0, "m")}. @return: dictionary of the component/group outputs saving names as keys and (value, units) as tuple. """ # Read .xml file and construct Independent Variable Component excluding outputs reader.path_separator = ":" ivc_local = reader.to_ivc() for name, value in inputs_dict.items(): ivc_local.add_output(name, value[0], units=value[1]) group_local = AutoUnitsDefaultGroup() group_local.add_subsystem('system', system, promotes=["*"]) group_local.add_subsystem('ivc', ivc_local, promotes=["*"]) problem_local = FASTOADProblem(group_local) problem_local.setup() problem_local.run_model() if overwrite: problem_local.output_file_path = xml_file_path problem_local.write_outputs() # Get output names from component/group and construct dictionary outputs_units = [var.units for var in variables if not var.is_input] outputs_dict = {} for idx in range(len(outputs_names)): value = problem_local.get_val(outputs_names[idx], outputs_units[idx]) outputs_dict[outputs_names[idx]] = (value, outputs_units[idx]) return outputs_dict return patched_function