def setUp(self): self.model_part_size = model_part_size = 3 self.parameters = { 'interface_a': [{ 'model_part': 'mp1', 'variables': ['pressure', 'traction'] }, { 'model_part': 'mp2', 'variables': ['density'] }], 'interface_b': [{ 'model_part': 'mp1', 'variables': ['pressure', 'displacement'] }, { 'model_part': 'mp2', 'variables': ['density'] }], 'interface_c': [{ 'model_part': 'mp1', 'variables': ['pressure', 'traction'] }, { 'model_part': 'mp3', 'variables': ['density'] }], 'interface_d': [{ 'model_part': 'mp2', 'variables': ['density'] }, { 'model_part': 'mp1', 'variables': ['pressure', 'displacement'] }], } self.model = Model() self.x0 = x0 = np.random.rand(3 * model_part_size) self.y0 = y0 = np.random.rand(3 * model_part_size) self.z0 = z0 = np.random.rand(3 * model_part_size) self.ids = ids = np.arange(0, model_part_size) np.random.shuffle(ids) self.model.create_model_part('mp1', x0[0:model_part_size], y0[0:model_part_size], z0[0:model_part_size], ids) self.model.create_model_part('mp2', x0[model_part_size:2 * model_part_size], y0[model_part_size:2 * model_part_size], z0[model_part_size:2 * model_part_size], ids) self.model.create_model_part( 'mp3', x0[2 * model_part_size:3 * model_part_size], y0[2 * model_part_size:3 * model_part_size], z0[2 * model_part_size:3 * model_part_size], ids) self.interface = Interface(self.parameters['interface_a'], self.model) self.scalar_size = 1 self.vector_size = 3 self.pressure = np.random.rand(model_part_size, self.scalar_size) self.traction = np.random.rand(model_part_size, self.vector_size) self.temperature = np.random.rand(model_part_size, self.scalar_size) self.density = np.random.rand(model_part_size, self.scalar_size) self.interface_data = np.random.rand(model_part_size * 5)
def test_eq(self): self.interface.set_interface_data(self.interface_data) model_part_size = self.model_part_size x0 = self.x0 y0 = self.y0 z0 = self.z0 ids = self.ids model2 = Model() model2.create_model_part('mp1', x0[0:model_part_size], y0[0:model_part_size], z0[0:model_part_size], ids) model2.create_model_part('mp2', x0[model_part_size:2 * model_part_size], y0[model_part_size:2 * model_part_size], z0[model_part_size:2 * model_part_size], ids) interface2 = Interface(self.parameters['interface_a'], model2) interface2.set_interface_data(self.interface_data) self.assertIsNot(self.interface, interface2) self.assertEqual(self.interface, interface2) interface3 = Interface(self.parameters['interface_b'], model2) interface3.set_interface_data(self.interface_data) self.assertNotEqual(self.interface, interface3) interface4 = interface2.copy() interface_data4 = self.interface_data.copy() interface_data4[np.random.randint(interface4.size)] = np.random.rand() interface4.set_interface_data(interface_data4) self.assertNotEqual(self.interface, interface4)
def test_convergence_criterion_relative_norm(self): m = 10 dz = 2 a0 = 10 a1 = 1e-4 a2 = 1e-6 variable = 'area' model_part_name = 'wall' interface_settings = [{'model_part': model_part_name, 'variables': [variable]}] # create model and model_part model = data_structure.Model() ids = np.arange(0, m) x0 = np.zeros(m) y0 = np.zeros(m) z0 = np.arange(0, m * dz, dz) model.create_model_part(model_part_name, x0, y0, z0, ids) a0_array = np.full((m, 1), a0) a1_array = np.full((m, 1), a1) a2_array = np.full((m, 1), a2) # create interface interface = Interface(interface_settings, model) # create convergence criterion parameters = {'type': 'convergence_criteria.relative_norm', 'settings': {'tolerance': 1e-6, 'order': 2}} convergence_criterion_relative_norm = create_instance(parameters) convergence_criterion_relative_norm.initialize() # test convergence criterion for i in range(3): convergence_criterion_relative_norm.initialize_solution_step() is_satisfied = convergence_criterion_relative_norm.is_satisfied() self.assertFalse(is_satisfied) interface.set_variable_data(model_part_name, variable, a0_array) convergence_criterion_relative_norm.update(interface) is_satisfied = convergence_criterion_relative_norm.is_satisfied() self.assertFalse(is_satisfied) interface.set_variable_data(model_part_name, variable, a1_array) convergence_criterion_relative_norm.update(interface) is_satisfied = convergence_criterion_relative_norm.is_satisfied() self.assertFalse(is_satisfied) interface.set_variable_data(model_part_name, variable, a2_array) convergence_criterion_relative_norm.update(interface) is_satisfied = convergence_criterion_relative_norm.is_satisfied() self.assertTrue(is_satisfied) interface.set_variable_data(model_part_name, variable, a1_array) convergence_criterion_relative_norm.update(interface) is_satisfied = convergence_criterion_relative_norm.is_satisfied() self.assertFalse(is_satisfied) convergence_criterion_relative_norm.finalize_solution_step()
def test_convergence_criterion_and(self): m = 10 dz = 2 a0 = 1 variable = 'area' model_part_name = 'wall' interface_settings = [{'model_part': model_part_name, 'variables': [variable]}] # create model and model_part model = data_structure.Model() ids = np.arange(0, m) x0 = np.zeros(m) y0 = np.zeros(m) z0 = np.arange(0, m * dz, dz) model.create_model_part(model_part_name, x0, y0, z0, ids) a0_array = np.full((m, 1), a0) # create interface interface = Interface(interface_settings, model) interface.set_variable_data(model_part_name, variable, a0_array) # read settings parameter_file_name = os.path.join(os.path.dirname(__file__), 'test_and.json') with open(parameter_file_name, 'r') as parameter_file: parameters = json.load(parameter_file) convergence_criterion_and = create_instance(parameters) convergence_criterion_and.initialize() for i in range(3): convergence_criterion_and.initialize_solution_step() is_satisfied = convergence_criterion_and.is_satisfied() self.assertFalse(is_satisfied) convergence_criterion_and.update(interface) is_satisfied = convergence_criterion_and.is_satisfied() self.assertFalse(is_satisfied) convergence_criterion_and.update(interface) is_satisfied = convergence_criterion_and.is_satisfied() self.assertFalse(is_satisfied) convergence_criterion_and.update(interface) is_satisfied = convergence_criterion_and.is_satisfied() self.assertFalse(is_satisfied) convergence_criterion_and.update(interface) is_satisfied = convergence_criterion_and.is_satisfied() self.assertTrue(is_satisfied) convergence_criterion_and.update(interface) is_satisfied = convergence_criterion_and.is_satisfied() self.assertTrue(is_satisfied) convergence_criterion_and.finalize_solution_step()
def __init__(self, parameters): super().__init__() self.settings = parameters['settings'] self.model = data_structure.Model() dx = lx / (nx - 1) dy = ly / (ny - 1) perturb_factor = 0.0 x = np.linspace(0, lx, nx) + np.random.rand(nx) * dx * perturb_factor y = np.linspace(0, ly, ny) + np.random.rand(ny) * dy * perturb_factor xx, yy = np.meshgrid(x, y) x0_in = xx.ravel() y0_in = yy.ravel() x0_out = xx.ravel() y0_out = yy.ravel() z0_in = np.zeros_like(x0_in) z0_out = np.zeros_like(x0_out) node_ids_in = np.arange(0, nx * ny) node_ids_out = np.arange(0, nx * ny) self.mp_name_in_list = [] for interface_settings in self.settings['interface_input']: self.model.create_model_part(interface_settings['model_part'], x0_in, y0_in, z0_in, node_ids_in) self.mp_name_in_list.append(interface_settings['model_part']) self.mp_name_out_list = [] for interface_settings in self.settings['interface_output']: self.model.create_model_part(interface_settings['model_part'], x0_out, y0_out, z0_out, node_ids_out) self.mp_name_out_list.append(interface_settings['model_part']) # # Interfaces self.interface_input = Interface(self.settings["interface_input"], self.model) self.interface_output = Interface(self.settings["interface_output"], self.model) # run time self.run_time = 0.0
def test_predictor_linear(self): m = 10 dz = 3 a0 = 1 p1 = 1 a1 = 2 p2 = 3 variable = 'area' model_part_name = 'wall' interface_settings = [{ 'model_part': model_part_name, 'variables': [variable] }] # create model and model_part model = data_structure.Model() ids = np.arange(0, m) x0 = np.zeros(m) y0 = np.zeros(m) z0 = np.arange(0, m * dz, dz) model.create_model_part(model_part_name, x0, y0, z0, ids) a0_array = np.full((m, 1), a0) # create interface interface = Interface(interface_settings, model) interface.set_variable_data(model_part_name, variable, a0_array) # create predictor parameters = {'type': 'predictors.linear'} predictor_linear = create_instance(parameters) predictor_linear.initialize(interface) # first prediction needs to be equal to initialized value predictor_linear.initialize_solution_step() prediction = predictor_linear.predict(interface) self.assertIsInstance(prediction, Interface) prediction_as_array = prediction.get_interface_data() for i in range(m): self.assertAlmostEqual(p1, prediction_as_array[i]) interface_as_array = a1 * prediction_as_array interface.set_interface_data(interface_as_array) predictor_linear.update(interface) predictor_linear.finalize_solution_step() # second prediction needs to be linear predictor_linear.initialize_solution_step() prediction = predictor_linear.predict(interface) self.assertIsInstance(prediction, Interface) prediction_as_array = prediction.get_interface_data() for i in range(m): self.assertAlmostEqual(p2, prediction_as_array[i])
def __init__(self, parameters): super().__init__() self.settings = parameters["settings"] self.working_directory = join(os.getcwd(), self.settings["working_directory"]) self.env = tools.get_solver_env(__name__, self.working_directory) delta_t = self.settings["delta_t"] timestep_start = self.settings["timestep_start"] dimensions = self.settings["dimensions"] self.timestep = None input_file_name = join(self.working_directory, self.settings["input_file"]) with open(input_file_name, "r") as parameter_file: kratos_parameters = json.load(parameter_file) kratos_parameters["problem_data"]["start_time"] = timestep_start kratos_parameters["problem_data"]["time_step"] = delta_t kratos_parameters["problem_data"]["domain_size"] = dimensions kratos_parameters["problem_data"]["end_time"] = 1e15 interface_sub_model_parts_list = self.settings[ "kratos_interface_sub_model_parts_list"] kratos_parameters[ "interface_sub_model_parts_list"] = interface_sub_model_parts_list with open(os.path.join(self.working_directory, input_file_name), 'w') as f: json.dump(kratos_parameters, f, indent=4) self.check_interface() self.model = data_structure.Model() dir_path = os.path.dirname(os.path.realpath(__file__)) run_script_file = os.path.join(dir_path, 'run_kratos_structural_60.py') self.kratos_process = Popen( f'python3 {run_script_file} {input_file_name} &> log', shell=True, cwd=self.working_directory, env=self.env) self.wait_message('start_ready') for mp_name in interface_sub_model_parts_list: file_path = os.path.join(self.working_directory, f'{mp_name}_nodes.csv') node_data = pd.read_csv(file_path, skipinitialspace=True) node_ids = np.array(node_data.node_id) x0 = np.array(node_data.x0) y0 = np.array(node_data.y0) z0 = np.array(node_data.z0) self.model.create_model_part(f'{mp_name}_input', x0, y0, z0, node_ids) self.model.create_model_part(f'{mp_name}_output', x0, y0, z0, node_ids) # # Interfaces self.interface_input = Interface(self.settings["interface_input"], self.model) self.interface_output = Interface(self.settings["interface_output"], self.model) # time self.init_time = self.init_time self.run_time = 0.0 self.residual_variables = self.settings.get('residual_variables', None) self.res_filepath = os.path.join(self.working_directory, 'residuals.csv') if self.residual_variables is not None: self.write_residuals_fileheader()
class SolverWrapperKratosStructure60(Component): @tools.time_initialize def __init__(self, parameters): super().__init__() self.settings = parameters["settings"] self.working_directory = join(os.getcwd(), self.settings["working_directory"]) self.env = tools.get_solver_env(__name__, self.working_directory) delta_t = self.settings["delta_t"] timestep_start = self.settings["timestep_start"] dimensions = self.settings["dimensions"] self.timestep = None input_file_name = join(self.working_directory, self.settings["input_file"]) with open(input_file_name, "r") as parameter_file: kratos_parameters = json.load(parameter_file) kratos_parameters["problem_data"]["start_time"] = timestep_start kratos_parameters["problem_data"]["time_step"] = delta_t kratos_parameters["problem_data"]["domain_size"] = dimensions kratos_parameters["problem_data"]["end_time"] = 1e15 interface_sub_model_parts_list = self.settings[ "kratos_interface_sub_model_parts_list"] kratos_parameters[ "interface_sub_model_parts_list"] = interface_sub_model_parts_list with open(os.path.join(self.working_directory, input_file_name), 'w') as f: json.dump(kratos_parameters, f, indent=4) self.check_interface() self.model = data_structure.Model() dir_path = os.path.dirname(os.path.realpath(__file__)) run_script_file = os.path.join(dir_path, 'run_kratos_structural_60.py') self.kratos_process = Popen( f'python3 {run_script_file} {input_file_name} &> log', shell=True, cwd=self.working_directory, env=self.env) self.wait_message('start_ready') for mp_name in interface_sub_model_parts_list: file_path = os.path.join(self.working_directory, f'{mp_name}_nodes.csv') node_data = pd.read_csv(file_path, skipinitialspace=True) node_ids = np.array(node_data.node_id) x0 = np.array(node_data.x0) y0 = np.array(node_data.y0) z0 = np.array(node_data.z0) self.model.create_model_part(f'{mp_name}_input', x0, y0, z0, node_ids) self.model.create_model_part(f'{mp_name}_output', x0, y0, z0, node_ids) # # Interfaces self.interface_input = Interface(self.settings["interface_input"], self.model) self.interface_output = Interface(self.settings["interface_output"], self.model) # time self.init_time = self.init_time self.run_time = 0.0 self.residual_variables = self.settings.get('residual_variables', None) self.res_filepath = os.path.join(self.working_directory, 'residuals.csv') if self.residual_variables is not None: self.write_residuals_fileheader() @tools.time_initialize def initialize(self): super().initialize() self.timestep = 0 def initialize_solution_step(self): super().initialize_solution_step() self.timestep += 1 self.send_message('next') self.wait_message('next_ready') @tools.time_solve_solution_step def solve_solution_step(self, interface_input): self.interface_input.set_interface_data( interface_input.get_interface_data()) self.write_input_data() self.send_message('continue') self.wait_message('continue_ready') self.update_interface_output() return self.get_interface_output() def finalize_solution_step(self): super().finalize_solution_step() self.send_message('save') self.wait_message('save_ready') if self.residual_variables is not None: self.write_residuals() def finalize(self): super().finalize() self.send_message('stop') self.wait_message('stop_ready') self.remove_all_messages() self.kratos_process.kill() def get_interface_input(self): return self.interface_input def get_interface_output(self): return self.interface_output def write_input_data(self): interface_sub_model_parts_list = self.settings[ "kratos_interface_sub_model_parts_list"] for mp_name in interface_sub_model_parts_list: input_mp_name = f'{mp_name}_input' input_mp = self.model.get_model_part(input_mp_name) file_path_pr = os.path.join(self.working_directory, f'{mp_name}_pressure.csv') with open(file_path_pr, 'w') as f: f.write('node_id, pressure\n') file_path_sl = os.path.join(self.working_directory, f'{mp_name}_surface_load.csv') with open(file_path_sl, 'w') as f: f.write( 'node_id, surface_load_x, surface_load_y, surface_load_z\n' ) pressure_array = np.ravel( self.interface_input.get_variable_data(input_mp_name, 'pressure')) surface_load_array = self.interface_input.get_variable_data( input_mp_name, 'traction') for i in range(0, input_mp.size): with open(file_path_pr, 'a') as f: f.write( str(input_mp.id[i]) + ', ' + str(pressure_array[i]) + '\n') with open(file_path_sl, 'a') as f: f.write( str(input_mp.id[i]) + ', ' + str(surface_load_array[i, 0]) + ', ' + str(surface_load_array[i, 1]) + ', ' + str(surface_load_array[i, 2]) + '\n') def update_interface_output(self): interface_sub_model_parts_list = self.settings[ "kratos_interface_sub_model_parts_list"] for mp_name in interface_sub_model_parts_list: output_mp_name = f'{mp_name}_output' file_path = os.path.join(self.working_directory, f'{mp_name}_displacement.csv') disp_data = pd.read_csv(file_path, skipinitialspace=True) disp_x = np.array(disp_data.displacement_x) disp_y = np.array(disp_data.displacement_y) disp_z = np.array(disp_data.displacement_z) displacement = np.column_stack((disp_x, disp_y, disp_z)) self.interface_output.set_variable_data(output_mp_name, 'displacement', displacement) def check_interface(self): input_interface_model_parts = [ param["model_part"] for param in self.settings["interface_input"] ] output_interface_model_parts = [ param["model_part"] for param in self.settings["interface_output"] ] sub_mp_name_list = self.settings[ "kratos_interface_sub_model_parts_list"] for sub_mp_name in sub_mp_name_list: if f'{sub_mp_name}_input' not in input_interface_model_parts: raise RuntimeError( f'Error in json file: {sub_mp_name}_input not listed in "interface_input": ' f'{self.settings["interface_input"]}.\n. <sub_mp_name> in the ' f'"kratos_interface_sub_model_parts_list" in json file should have corresponding ' f'<sub_mp_name>_input in "interface_input" list. ') if f'{sub_mp_name}_output' not in output_interface_model_parts: raise RuntimeError( f'Error in json file: {sub_mp_name}_output not listed in "interface_output": ' f'{self.settings["interface_output"]}.\n. <sub_mp_name> in the ' f'"kratos_interface_sub_model_parts_list" in json file should have corresponding ' f'<sub_mp_name>_output in "interface_output" list.') def send_message(self, message): file = join(self.working_directory, message + ".coco") open(file, 'w').close() return def wait_message(self, message): file = join(self.working_directory, message + ".coco") while not os.path.isfile(file): time.sleep(0.01) os.remove(file) return def check_message(self, message): file = join(self.working_directory, message + ".coco") if os.path.isfile(file): os.remove(file) return True return False def remove_all_messages(self): for file_name in os.listdir(self.working_directory): if file_name.endswith('.coco'): file = join(self.working_directory, file_name) os.remove(file) def write_residuals_fileheader(self): header = '' sep = ', ' with open(self.res_filepath, 'w') as f: f.write('# Residuals\n') for variable in self.residual_variables: header += variable + sep f.write(header.strip(sep) + '\n') def write_residuals(self): float_pattern = r'[+-]?\d*\.?\d*[eE]?[+-]?\d*' log_filepath = os.path.join(self.working_directory, f'log') if os.path.isfile(log_filepath): with open(log_filepath, 'r') as f: log_string = f.read() time_start_string = r'STEP:\s+' + str(self.timestep - 1) time_end_string = r'STEP:\s+' + str(self.timestep) match = re.search(time_start_string + r'(.*)' + time_end_string, log_string, flags=re.S) if match is not None: time_block = match.group(1) iteration_block_list = re.findall( r'Coupling iteration: \d(.*?)Coupling iteration \d+ end', time_block, flags=re.S) for iteration_block in iteration_block_list: residual_array = np.empty(len(self.residual_variables)) for i, variable in enumerate(self.residual_variables): search_string = r'\n' + variable + r' CRITERION.*[Nn]orm = ' + r'(' + float_pattern + r')' var_residual_list = re.findall(search_string, iteration_block) if var_residual_list: # last initial residual of the non-linear iteration var_residual = float(var_residual_list[-1]) residual_array[i] = var_residual else: raise RuntimeError( f'{variable} CRITERION not found in kratos log file' ) with open(self.res_filepath, 'a') as f: np.savetxt(f, [residual_array], delimiter=', ')
def test_model_mv(self): m = 5 dz = 2 x = 10 variable = 'area' model_part_name = 'wall' interface_settings = [{ 'model_part': model_part_name, 'variables': [variable] }] # create model and model_part model = data_structure.Model() ids = np.arange(0, m) x0 = np.zeros(m) y0 = np.zeros(m) z0 = np.arange(0, m * dz, dz) model.create_model_part(model_part_name, x0, y0, z0, ids) x_array = np.full((m, 1), x) # create interface interface = Interface(interface_settings, model) interface.set_variable_data(model_part_name, variable, x_array) # read settings parameter_file_name = os.path.join(os.path.dirname(__file__), 'test_mv.json') with open(parameter_file_name, 'r') as parameter_file: settings = json.load(parameter_file) min_significant = settings["settings"]["min_significant"] mv = create_instance(settings) mv.size_in = mv.size_out = m mv.out = interface.copy() mv.initialize() mv.initialize_solution_step() r = interface.copy() xt = interface.copy() r1 = np.array([1, 2, 3, 4, 5]) xt1 = np.array([5, 4, 3, 2, 1]) r2 = np.array([8, 5, 5, 5, 8]) xt2 = np.array([1, 4, 8, 5, 5]) r3 = np.array([7, 5, 6, 4, 3]) r4 = np.array([1, 1, 7, 4, 0]) xt4 = np.array([9, 7, 5, 8, 4]) r5 = np.array([9, 5, 10, 6, 4]) xt5 = np.array([5, 1, 2, 3, 9]) r6 = np.array([7, 8, 1, 2, 3]) xt6 = np.array([7, 5, 5, 1, 2]) r7 = np.array([1, 2, 5, 1, 2]) xt7 = np.array([4, 2, 1, 1, 2]) r8 = np.array([6, 3, 9, 0, 3]) xt8 = np.array([3, 1, 2, 3, 9]) r9 = np.array([1, 3, 5, 0, 8]) xt9 = np.array([8, 1, 5, 3, 9]) r10 = np.array([1, 3, -5, 8, 8]) xt10 = np.array([8, -9, 5, 3, -9]) r11 = r1 xt11 = xt1 r12 = r2 xt12 = xt2 r13 = r10 * 0.95 xt13 = xt10 is_ready = mv.is_ready() self.assertFalse(is_ready) r.set_interface_data(r1) xt.set_interface_data(xt1) mv.add(r, xt) self.assertTrue(mv.added) np.testing.assert_array_equal(r1[:, np.newaxis], mv.rref) np.testing.assert_array_equal(xt1[:, np.newaxis], mv.xtref) self.assertIsNone(mv.ncurr) is_ready = mv.is_ready() self.assertFalse(is_ready) r.set_interface_data(r2) xt.set_interface_data(xt2) mv.add(r, xt) self.assertTrue(mv.added) np.testing.assert_array_equal(r2[:, np.newaxis], mv.rref) np.testing.assert_array_equal(xt2[:, np.newaxis], mv.xtref) self.assertEqual(mv.v.shape, (m, 1)) np.testing.assert_array_equal(mv.v[:, 0], r2 - r1) self.assertEqual(mv.w.shape, (m, 1)) np.testing.assert_array_equal(mv.w[:, 0], xt2 - xt1) n_sol = [ -0.388888888888889, -0.166666666666667, -0.111111111111111, -0.0555555555555556, -0.166666666666667, 0, 0, 0, 0, 0, 0.486111111111111, 0.208333333333333, 0.138888888888889, 0.0694444444444445, 0.208333333333333, 0.291666666666667, 0.125000000000000, 0.0833333333333333, 0.0416666666666667, 0.125000000000000, 0.388888888888889, 0.166666666666667, 0.111111111111111, 0.0555555555555556, 0.166666666666667 ] np.testing.assert_allclose(mv.ncurr.flatten(), n_sol) np.testing.assert_array_equal(mv.nprev.flatten(), np.zeros((m, m)).flatten()) is_ready = mv.is_ready() self.assertTrue(is_ready) r.set_interface_data(r3) dxt = mv.predict(-1 * r) dxt_sol = [ 4.94444444444445, 0, -6.18055555555556, -3.70833333333333, -4.944444444444452 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) r.set_interface_data(r4) xt.set_interface_data(xt4) mv.add(r, xt) self.assertEqual(mv.v.shape, (m, 2)) np.testing.assert_array_equal(mv.v[:, 0], r4 - r2) self.assertEqual(mv.w.shape, (m, 2)) np.testing.assert_array_equal(mv.w[:, 0], xt4 - xt2) n_sol = [ -0.306429548563612, -0.216142270861833, 0.251709986320109, -0.0437756497948016, -0.555403556771546, 0.0718194254445965, -0.0430916552667578, 0.316005471956224, 0.0102599179206566, -0.338577291381669, 0.550615595075240, 0.169630642954856, 0.422708618331053, 0.0786593707250342, -0.0957592339261285, 0.445280437756498, 0.0328317373461012, 0.759233926128591, 0.0636114911080711, -0.599179206566348, 0.474008207934337, 0.115595075239398, 0.485636114911081, 0.0677154582763338, -0.234610123119015 ] np.testing.assert_allclose(mv.ncurr.flatten(), n_sol) r.set_interface_data(r3) dxt = mv.predict(-1 * r) dxt_sol = [ 3.55677154582763, -1.20861833105335, -7.26607387140903, -6.29343365253078, -6.37688098495212 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) r.set_interface_data(r5) xt.set_interface_data(xt5) mv.add(r, xt) self.assertEqual(mv.v.shape, (m, 2)) np.testing.assert_array_equal(mv.v[:, 0], r5 - r4) self.assertEqual(mv.w.shape, (m, 2)) np.testing.assert_array_equal(mv.w[:, 0], xt5 - xt4) n_sol = [ -0.258792878853669, -0.180633955709944, 0.376899696048632, 0.0121580547112462, -0.590534085974816, -0.460486322188450, -0.200607902735562, -0.446808510638298, -0.159574468085106, 0.0364741641337384, -0.266391663048198, -0.0651324359531047, -0.729483282674772, -0.168693009118541, 0.479374728614850, -0.379722101606600, -0.171081198436822, -0.316109422492401, -0.123100303951368, -0.0208423795049935, 0.395788102475033, 0.155449413808076, 0.541033434650456, 0.162613981762918, -0.184107685627443 ] np.testing.assert_allclose(mv.ncurr.flatten(), n_sol) r.set_interface_data(r3) dxt = mv.predict(-1 * r) dxt_sol = [ 2.17629179331307, 7.43617021276596, 5.80395136778116, 5.96504559270517, -6.89209726443769 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) self.assertEqual(mv.v.shape, (m, 2)) np.testing.assert_array_equal(mv.v.T.flatten(), np.hstack((r5 - r4, r4 - r2))) self.assertEqual(mv.w.shape, (m, 2)) np.testing.assert_array_equal(mv.w.T.flatten(), np.hstack((xt5 - xt4, xt4 - xt2))) r.set_interface_data(r6) xt.set_interface_data(xt6) mv.add(r, xt) r.set_interface_data(r7) xt.set_interface_data(xt7) mv.add(r, xt) r.set_interface_data(r8) xt.set_interface_data(xt8) mv.add(r, xt) n_sol = [ 1.59692513368984, -1.67045454545455, -1.19117647058823, 0.612967914438510, -1.93649732620321, 3.87433155080215, -5.22727272727274, -3.11764705882354, 0.660427807486646, -2.01336898395721, 4.65909090909091, -6.15909090909093, -3.50000000000001, 0.568181818181834, -1.56818181818181, 5.05213903743316, -7.02272727272729, -3.32352941176471, 0.736631016042804, -2.20721925133689, 1.72192513368984, -1.54545454545455, 0.0588235294117627, -0.262032085561494, -0.561497326203206 ] np.testing.assert_allclose(mv.ncurr.flatten(), n_sol) r.set_interface_data(r3) dxt = mv.predict(-1 * r) dxt_sol = [ 7.67847593582868, 21.1203208556145, 21.6136363636358, 23.3649732620315, -1.94652406417126 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) self.assertEqual(mv.v.shape, (m, 5)) np.testing.assert_array_equal( mv.v.T.flatten(), np.hstack((r8 - r7, r7 - r6, r6 - r5, r5 - r4, r4 - r2))) self.assertEqual(mv.w.shape, (m, 5)) np.testing.assert_array_equal( mv.w.T.flatten(), np.hstack((xt8 - xt7, xt7 - xt6, xt6 - xt5, xt5 - xt4, xt4 - xt2))) r.set_interface_data(r9) xt.set_interface_data(xt9) mv.add(r, xt) r.set_interface_data(r10) xt.set_interface_data(xt10) mv.add(r, xt) r.set_interface_data(r3) dxt = mv.predict(-1 * r) dxt_sol = [ -4.19875900720576, -5.62710168134507, -2.21637309847878, -0.788630904723781, -11.8953162530024 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) self.assertEqual(mv.v.shape, (m, 5)) np.testing.assert_array_equal( mv.v.T.flatten(), np.hstack((r10 - r9, r9 - r8, r8 - r7, r7 - r6, r6 - r5))) self.assertEqual(mv.w.shape, (m, 5)) np.testing.assert_array_equal( mv.w.T.flatten(), np.hstack( (xt10 - xt9, xt9 - xt8, xt8 - xt7, xt7 - xt6, xt6 - xt5))) r.set_interface_data(r13) xt.set_interface_data(xt13) mv.add(r, xt) r.set_interface_data(r3) dxt = mv.predict(-1 * r) dxt_sol = [ -4.19875900720576, -5.62710168134507, -2.21637309847878, -0.788630904723781, -11.8953162530024 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) self.assertEqual(mv.v.shape, (m, 5)) np.testing.assert_array_equal( mv.v.T.flatten(), np.hstack((r10 - r9, r9 - r8, r8 - r7, r7 - r6, r6 - r5))) self.assertEqual(mv.w.shape, (m, 5)) np.testing.assert_array_equal( mv.w.T.flatten(), np.hstack( (xt10 - xt9, xt9 - xt8, xt8 - xt7, xt7 - xt6, xt6 - xt5))) v = mv.v w = mv.w nprev = w @ np.linalg.inv(v.T @ v) @ v.T # New solution step mv.finalize_solution_step() np.testing.assert_array_equal(mv.nprev.flatten(), nprev.flatten()) mv.initialize_solution_step() self.assertIsNone(mv.rref) self.assertFalse(mv.added) self.assertEqual(mv.v.shape, (m, 0)) self.assertEqual(mv.w.shape, (m, 0)) is_ready = mv.is_ready() self.assertTrue(is_ready) np.testing.assert_allclose(mv.ncurr.flatten(), nprev.flatten()) r.set_interface_data(r3) dxt = mv.predict(-1 * r) dxt_sol = [ -4.19875900720576, -5.62710168134507, -2.21637309847878, -0.788630904723781, -11.8953162530024 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) r.set_interface_data(r11) xt.set_interface_data(xt11) mv.add(r, xt) self.assertTrue(mv.added) self.assertEqual(mv.v.shape, (m, 0)) self.assertEqual(mv.w.shape, (m, 0)) r.set_interface_data(r12) xt.set_interface_data(xt12) mv.add(r, xt) n_sol = [ -1.07953029089939, 0.852682145716574, -0.00813984520949948, 0.0950093408059783, 0.306645316253002, -1.08484565430122, 2.54250066720043, 0.878480562227564, -0.192264923049552, -0.532759540966108, 0.315863802152833, 0.444989324793168, -0.139022328974290, -0.215427897873855, 0.649152655457700, 0.519159772262255, -0.566019482252470, -0.0682990837114143, -0.0941975802864517, 0.431578596210302, -0.394248732319190, 0.855284227381908, 1.23271950894049, -0.654857219108619, 0.794435548438751 ] np.testing.assert_allclose(mv.ncurr.flatten(), n_sol) r.set_interface_data(r3) dxt = mv.predict(-1 * r) dxt_sol = [ 2.04216706698691, -8.02212881416246, -4.68760564006761, -1.31217195979005, -8.67687483319990 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) self.assertEqual(mv.v.shape, (m, 1)) np.testing.assert_array_equal(mv.v, r12[:, np.newaxis] - r11[:, np.newaxis]) self.assertEqual(mv.w.shape, (m, 1)) np.testing.assert_array_equal( mv.w, xt12[:, np.newaxis] - xt11[:, np.newaxis])
def test_predictor(self): m = 10 dz = 3 a0 = 1 a1 = 2 a2 = 3 a3 = 4 a4 = 5 variable = 'area' model_part_name = 'wall' interface_settings = [{ 'model_part': model_part_name, 'variables': [variable] }] # create model and model_part model = data_structure.Model() ids = np.arange(0, m) x0 = np.zeros(m) y0 = np.zeros(m) z0 = np.arange(0, m * dz, dz) model.create_model_part(model_part_name, x0, y0, z0, ids) a0_array = np.full((m, 1), a0) # create interface interface = Interface(interface_settings, model) interface.set_variable_data(model_part_name, variable, a0_array) interface_as_array = interface.get_interface_data() # create predictor parameters = {'type': 'predictors.cubic'} predictor_cubic = create_instance(parameters) predictor_cubic.initialize(interface) # a linear relation should be predicted in the same way by linear, quadratic and cubic predictors predictor_cubic.initialize_solution_step() interface.set_interface_data(a1 * interface_as_array) predictor_cubic.update(interface) predictor_cubic.finalize_solution_step() predictor_cubic.initialize_solution_step() interface.set_interface_data(a2 * interface_as_array) predictor_cubic.update(interface) predictor_cubic.finalize_solution_step() predictor_cubic.initialize_solution_step() interface.set_interface_data(a3 * interface_as_array) predictor_cubic.update(interface) predictor_cubic.finalize_solution_step() predictor_cubic.initialize_solution_step() prediction_linear = predictor_cubic.linear( interface).get_interface_data() prediction_quadratic = predictor_cubic.quadratic( interface).get_interface_data() prediction_cubic = predictor_cubic.cubic( interface).get_interface_data() for i in range(m): self.assertAlmostEqual(a4, prediction_linear[i]) self.assertAlmostEqual(a4, prediction_quadratic[i]) self.assertAlmostEqual(a4, prediction_cubic[i]) # rror if no update with self.assertRaises(Exception): predictor_cubic.initialize_solution_step() predictor_cubic.finalize_solution_step() # error if updated twice with self.assertRaises(Exception): predictor_cubic.initialize_solution_step() _ = predictor_cubic.predict(interface) _ = predictor_cubic.predict(interface) predictor_cubic.finalize_solution_step() # error if prediction after update with self.assertRaises(Exception): predictor_cubic.initialize_solution_step() _ = predictor_cubic.update(interface) _ = predictor_cubic.predict(interface) predictor_cubic.finalize_solution_step()
def test_coupled_solver_aitken(self): m = 10 dz = 2 r = 0.1 x = 10 xt0 = 10.5 xt1 = 10.2 xt2 = 10.1 xt3 = 10.7 xt4 = 9.9 variable = 'area' # TODO: does not match JSON setings model_part_name = 'wall' interface_settings = [{ 'model_part': model_part_name, 'variables': [variable] }] # create model and model_part model = data_structure.Model() ids = np.arange(0, m) x0 = np.zeros(m) y0 = np.zeros(m) z0 = np.arange(0, m * dz, dz) model.create_model_part(model_part_name, x0, y0, z0, ids) # create interface interface = Interface(interface_settings, model) omega_max = self.parameters['settings']['omega_max'] with cd(self.working_dir): coupled_solver = create_instance(self.parameters) coupled_solver.initialize() coupled_solver.initialize_solution_step() interface_r = interface.copy() interface_r.set_interface_data(np.full(m, r)) interface_x = interface.copy() interface_x.set_interface_data(x * np.ones(m)) interface_xt0 = interface.copy() interface_xt0.set_interface_data(xt0 * np.ones(m)) interface_xt1 = interface.copy() interface_xt1.set_interface_data(xt1 * np.ones(m)) interface_xt2 = interface.copy() interface_xt2.set_interface_data(xt2 * np.ones(m)) interface_xt3 = interface.copy() interface_xt3.set_interface_data(xt3 * np.ones(m)) interface_xt4 = interface.copy() interface_xt4.set_interface_data(xt4 * np.ones(m)) # test value of self.added is_ready = coupled_solver.is_ready() self.assertFalse(is_ready) # test update() coupled_solver.update(interface_x, interface_xt0) is_ready = coupled_solver.is_ready() self.assertTrue(is_ready) omega = coupled_solver.omega self.assertEqual(omega, omega_max) coupled_solver.update(interface_x, interface_xt1) is_ready = coupled_solver.is_ready() self.assertTrue(is_ready) omega = coupled_solver.omega self.assertAlmostEqual(omega, 5 / 3 * omega_max, 10) coupled_solver.update(interface_x, interface_xt2) omega = coupled_solver.omega self.assertAlmostEqual(omega, 10 / 3 * omega_max, 10) # test predict() interface_dx = coupled_solver.predict(interface_r) omega = interface_dx.get_interface_data()[0] / r self.assertEqual(omega, coupled_solver.omega) coupled_solver.predict(interface_r) omega = coupled_solver.omega self.assertAlmostEqual(omega, 10 / 3 * omega_max, 10) # new solution step coupled_solver.finalize_solution_step() coupled_solver.initialize_solution_step() # test value of self.added is_ready = coupled_solver.is_ready() self.assertFalse(is_ready) # test update() coupled_solver.update(interface_x, interface_xt0) is_ready = coupled_solver.is_ready() self.assertTrue(is_ready) omega = coupled_solver.omega self.assertEqual(omega, omega_max) coupled_solver.update(interface_x, interface_xt3) omega = coupled_solver.omega self.assertAlmostEqual(omega, -5 / 2 * omega_max, 10) # new solution step coupled_solver.finalize_solution_step() coupled_solver.initialize_solution_step() # test update() coupled_solver.update(interface_x, interface_xt0) omega = coupled_solver.omega self.assertEqual(omega, -omega_max) coupled_solver.update(interface_x, interface_xt4) omega = coupled_solver.omega self.assertAlmostEqual(omega, -5 / 6 * omega_max, 10) # new solution step coupled_solver.finalize_solution_step() coupled_solver.initialize_solution_step() # test update() coupled_solver.update(interface_x, interface_xt0) omega = coupled_solver.omega self.assertAlmostEqual(omega, -5 / 6 * omega_max, 10)
class DummySolver1(Component): def __init__(self, parameters): super().__init__() self.settings = parameters['settings'] self.model = data_structure.Model() dx = lx / (nx - 1) dy = ly / (ny - 1) perturb_factor = 0.0 x = np.linspace(0, lx, nx) + np.random.rand(nx) * dx * perturb_factor y = np.linspace(0, ly, ny) + np.random.rand(ny) * dy * perturb_factor xx, yy = np.meshgrid(x, y) x0_in = xx.ravel() y0_in = yy.ravel() x0_out = xx.ravel() y0_out = yy.ravel() z0_in = np.zeros_like(x0_in) z0_out = np.zeros_like(x0_out) node_ids_in = np.arange(0, nx * ny) node_ids_out = np.arange(0, nx * ny) self.mp_name_in_list = [] for interface_settings in self.settings['interface_input']: self.model.create_model_part(interface_settings['model_part'], x0_in, y0_in, z0_in, node_ids_in) self.mp_name_in_list.append(interface_settings['model_part']) self.mp_name_out_list = [] for interface_settings in self.settings['interface_output']: self.model.create_model_part(interface_settings['model_part'], x0_out, y0_out, z0_out, node_ids_out) self.mp_name_out_list.append(interface_settings['model_part']) # # Interfaces self.interface_input = Interface(self.settings["interface_input"], self.model) self.interface_output = Interface(self.settings["interface_output"], self.model) # run time self.run_time = 0.0 def initialize(self): super().initialize() self.timestep = 0 def initialize_solution_step(self): super().initialize_solution_step() self.timestep += 1 @tools.time_solve_solution_step def solve_solution_step(self, interface_input): interface_data = interface_input.get_interface_data() for mp_name in self.mp_name_out_list: pressure_array, traction_array = self.calculate_output( interface_data, self.interface_output, mp_name) self.interface_output.set_variable_data(mp_name, 'pressure', pressure_array) self.interface_output.set_variable_data(mp_name, 'traction', traction_array) return self.get_interface_output() def finalize_solution_step(self): super().finalize_solution_step() def finalize(self): super().finalize() def get_interface_input(self): return self.interface_input def get_interface_output(self): return self.interface_output def calculate_output(self, data, out_interface, out_mp_name): nr_nodes = out_interface.get_model_part(out_mp_name).size norm = np.linalg.norm(data) min = np.min(data) pressure = norm traction = [min, -1 * min, 2 * min] return np.full((nr_nodes, 1), pressure), np.full((nr_nodes, 3), traction)
def test_model_ls(self): m = 5 dz = 2 x = 10 variable = 'area' model_part_name = 'wall' interface_settings = [{ 'model_part': model_part_name, 'variables': [variable] }] # create model and model_part model = data_structure.Model() ids = np.arange(0, m) x0 = np.zeros(m) y0 = np.zeros(m) z0 = np.arange(0, m * dz, dz) model.create_model_part(model_part_name, x0, y0, z0, ids) x_array = np.full((m, 1), x) # create interface interface = Interface(interface_settings, model) interface.set_variable_data(model_part_name, variable, x_array) # read settings parameter_file_name = os.path.join(os.path.dirname(__file__), 'test_ls.json') with open(parameter_file_name, 'r') as parameter_file: settings = json.load(parameter_file) # with reuse min_significant = settings["setting1"]["settings"]["min_significant"] q = settings["setting1"]["settings"]["q"] ls = create_instance(settings["setting1"]) ls.size_in = ls.size_out = m ls.out = interface.copy() ls.initialize() ls.initialize_solution_step() r = interface.copy() xt = interface.copy() r1 = np.array([1, 2, 3, 4, 5]) xt1 = np.array([5, 4, 3, 2, 1]) r2 = np.array([8, 5, 5, 5, 8]) xt2 = np.array([1, 4, 8, 5, 5]) r3 = np.array([7, 5, 6, 4, 3]) r4 = np.array([1, 1, 7, 4, 0]) xt4 = np.array([9, 7, 5, 8, 4]) r5 = np.array([9, 5, 10, 6, 4]) xt5 = np.array([5, 1, 2, 3, 9]) r6 = np.array([7, 8, 1, 2, 3]) xt6 = np.array([7, 5, 5, 1, 2]) r7 = np.array([1, 2, 5, 1, 2]) xt7 = np.array([4, 2, 1, 1, 2]) r8 = np.array([6, 3, 9, 0, 3]) xt8 = np.array([3, 1, 2, 3, 9]) r9 = np.array([1, 3, 5, 0, 8]) xt9 = np.array([8, 1, 5, 3, 9]) r10 = np.array([1, 3, -5, 8, 8]) xt10 = np.array([8, -9, 5, 3, -9]) r11 = r1 xt11 = xt1 r12 = r2 xt12 = xt2 r13 = r10 * 0.95 xt13 = xt10 is_ready = ls.is_ready() self.assertFalse(is_ready) r.set_interface_data(r1) xt.set_interface_data(xt1) ls.add(r, xt) self.assertTrue(ls.added) np.testing.assert_array_equal(r1[:, np.newaxis], ls.rref) np.testing.assert_array_equal(xt1[:, np.newaxis], ls.xtref) is_ready = ls.is_ready() self.assertFalse(is_ready) r.set_interface_data(r2) xt.set_interface_data(xt2) ls.add(r, xt) self.assertTrue(ls.added) np.testing.assert_array_equal(r2[:, np.newaxis], ls.rref) np.testing.assert_array_equal(xt2[:, np.newaxis], ls.xtref) v = np.hstack((ls.vcurr, np.hstack(ls.vprev))) w = np.hstack((ls.wcurr, np.hstack(ls.wprev))) self.assertEqual(v.shape, (m, 1)) np.testing.assert_array_equal(v[:, 0], r2 - r1) self.assertEqual(w.shape, (m, 1)) np.testing.assert_array_equal(w[:, 0], xt2 - xt1) is_ready = ls.is_ready() self.assertTrue(is_ready) r.set_interface_data(r3) dxt = ls.predict(-1 * r) dxt_sol = [ 4.94444444444445, 0, -6.18055555555556, -3.70833333333333, -4.944444444444452 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) r.set_interface_data(r4) xt.set_interface_data(xt4) ls.add(r, xt) v = np.hstack((ls.vcurr, np.hstack(ls.vprev))) w = np.hstack((ls.wcurr, np.hstack(ls.wprev))) self.assertEqual(v.shape, (m, 2)) np.testing.assert_array_equal(v[:, 0], r4 - r2) self.assertEqual(w.shape, (m, 2)) np.testing.assert_array_equal(w[:, 0], xt4 - xt2) r.set_interface_data(r3) dxt = ls.predict(-1 * r) dxt_sol = [ 3.55677154582763, -1.20861833105335, -7.26607387140903, -6.29343365253078, -6.37688098495212 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) r.set_interface_data(r5) xt.set_interface_data(xt5) ls.add(r, xt) v = np.hstack((ls.vcurr, np.hstack(ls.vprev))) w = np.hstack((ls.wcurr, np.hstack(ls.wprev))) self.assertEqual(v.shape, (m, 2)) np.testing.assert_array_equal(v[:, 0], r5 - r4) self.assertEqual(w.shape, (m, 2)) np.testing.assert_array_equal(w[:, 0], xt5 - xt4) r.set_interface_data(r3) dxt = ls.predict(-1 * r) dxt_sol = [ 2.17629179331307, 7.43617021276596, 5.80395136778116, 5.96504559270517, -6.89209726443769 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) v = np.hstack((ls.vcurr, np.hstack(ls.vprev))) w = np.hstack((ls.wcurr, np.hstack(ls.wprev))) self.assertEqual(v.shape, (m, 2)) np.testing.assert_array_equal(v.T.flatten(), np.hstack((r5 - r4, r4 - r2))) self.assertEqual(w.shape, (m, 2)) np.testing.assert_array_equal(w.T.flatten(), np.hstack((xt5 - xt4, xt4 - xt2))) r.set_interface_data(r6) xt.set_interface_data(xt6) ls.add(r, xt) r.set_interface_data(r7) xt.set_interface_data(xt7) ls.add(r, xt) r.set_interface_data(r8) xt.set_interface_data(xt8) ls.add(r, xt) r.set_interface_data(r3) dxt = ls.predict(-1 * r) dxt_sol = [ 7.67847593582868, 21.1203208556145, 21.6136363636358, 23.3649732620315, -1.94652406417126 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) v = np.hstack((ls.vcurr, np.hstack(ls.vprev))) w = np.hstack((ls.wcurr, np.hstack(ls.wprev))) self.assertEqual(v.shape, (m, 5)) np.testing.assert_array_equal( v.T.flatten(), np.hstack((r8 - r7, r7 - r6, r6 - r5, r5 - r4, r4 - r2))) self.assertEqual(w.shape, (m, 5)) np.testing.assert_array_equal( w.T.flatten(), np.hstack((xt8 - xt7, xt7 - xt6, xt6 - xt5, xt5 - xt4, xt4 - xt2))) r.set_interface_data(r9) xt.set_interface_data(xt9) ls.add(r, xt) r.set_interface_data(r10) xt.set_interface_data(xt10) ls.add(r, xt) r.set_interface_data(r3) dxt = ls.predict(-1 * r) dxt_sol = [ -4.19875900720576, -5.62710168134507, -2.21637309847878, -0.788630904723781, -11.8953162530024 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) v = np.hstack((ls.vcurr, np.hstack(ls.vprev))) w = np.hstack((ls.wcurr, np.hstack(ls.wprev))) self.assertEqual(v.shape, (m, 5)) np.testing.assert_array_equal( v.T.flatten(), np.hstack((r10 - r9, r9 - r8, r8 - r7, r7 - r6, r6 - r5))) self.assertEqual(w.shape, (m, 5)) np.testing.assert_array_equal( w.T.flatten(), np.hstack( (xt10 - xt9, xt9 - xt8, xt8 - xt7, xt7 - xt6, xt6 - xt5))) r.set_interface_data(r13) xt.set_interface_data(xt13) ls.add(r, xt) r.set_interface_data(r3) dxt = ls.predict(-1 * r) dxt_sol = [ -4.19875900720576, -5.62710168134507, -2.21637309847878, -0.788630904723781, -11.8953162530024 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) v = np.hstack((ls.vcurr, np.hstack(ls.vprev))) w = np.hstack((ls.wcurr, np.hstack(ls.wprev))) self.assertEqual(v.shape, (m, 5)) np.testing.assert_array_equal( v.T.flatten(), np.hstack((r10 - r9, r9 - r8, r8 - r7, r7 - r6, r6 - r5))) self.assertEqual(w.shape, (m, 5)) np.testing.assert_array_equal( w.T.flatten(), np.hstack( (xt10 - xt9, xt9 - xt8, xt8 - xt7, xt7 - xt6, xt6 - xt5))) v1 = ls.vcurr w1 = ls.wcurr # new solution step ls.finalize_solution_step() np.testing.assert_array_equal(ls.vprev[0].flatten(), v1.flatten()) np.testing.assert_array_equal(ls.wprev[0].flatten(), w1.flatten()) ls.initialize_solution_step() self.assertIsNone(ls.rref) self.assertFalse(ls.added) self.assertEqual(ls.vcurr.shape, (m, 0)) self.assertEqual(ls.wcurr.shape, (m, 0)) is_ready = ls.is_ready() self.assertTrue(is_ready) r.set_interface_data(r11) xt.set_interface_data(xt11) ls.add(r, xt) r.set_interface_data(r3) dxt = ls.predict(-1 * r) dxt_sol = [ -4.19875900720576, -5.62710168134507, -2.21637309847878, -0.788630904723781, -11.8953162530024 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) self.assertTrue(ls.added) self.assertEqual(ls.vcurr.shape, (m, 0)) self.assertEqual(ls.wcurr.shape, (m, 0)) r.set_interface_data(r12) xt.set_interface_data(xt12) ls.add(r, xt) r.set_interface_data(r3) dxt = ls.predict(-1 * r) dxt_sol = [ -8.52029914529913, -3.96866096866096, -0.505163817663819, -0.426103988603991, -14.1239316239316 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) v = np.hstack((ls.vcurr, np.hstack(ls.vprev))) w = np.hstack((ls.wcurr, np.hstack(ls.wprev))) self.assertEqual(v.shape, (m, 5)) np.testing.assert_array_equal( v.T.flatten(), np.hstack((r12 - r11, r10 - r9, r9 - r8, r7 - r6, r6 - r5))) self.assertEqual(w.shape, (m, 5)) np.testing.assert_array_equal( w.T.flatten(), np.hstack( (xt12 - xt11, xt10 - xt9, xt9 - xt8, xt7 - xt6, xt6 - xt5))) v2 = ls.vcurr w2 = ls.wcurr # new solution step ls.finalize_solution_step() np.testing.assert_array_equal( np.hstack(ls.vprev).flatten(), np.hstack([v2, v1[:, :2], v1[:, 3:]]).flatten()) np.testing.assert_array_equal( np.hstack(ls.wprev).flatten(), np.hstack([w2, w1[:, :2], w1[:, 3:]]).flatten()) ls.initialize_solution_step() # new solution step ls.finalize_solution_step() np.testing.assert_array_equal( np.hstack(ls.vprev).flatten(), np.hstack([np.empty((m, 0)), v2]).flatten()) np.testing.assert_array_equal( np.hstack(ls.wprev).flatten(), np.hstack([np.empty((m, 0)), w2]).flatten()) self.assertEqual(len(ls.vprev), q) self.assertEqual(len(ls.wprev), q) ls.initialize_solution_step() # without reuse min_significant = settings["setting2"]["settings"]["min_significant"] q = settings["setting2"]["settings"]["q"] ls = create_instance(settings["setting2"]) ls.size_in = ls.size_out = m ls.out = interface.copy() ls.initialize() ls.initialize_solution_step() r.set_interface_data(r1) xt.set_interface_data(xt1) ls.add(r, xt) r.set_interface_data(r2) xt.set_interface_data(xt2) ls.add(r, xt) r.set_interface_data(r4) xt.set_interface_data(xt4) ls.add(r, xt) r.set_interface_data(r5) xt.set_interface_data(xt5) ls.add(r, xt) r.set_interface_data(r6) xt.set_interface_data(xt6) ls.add(r, xt) r.set_interface_data(r7) xt.set_interface_data(xt7) ls.add(r, xt) r.set_interface_data(r8) xt.set_interface_data(xt8) ls.add(r, xt) r.set_interface_data(r9) xt.set_interface_data(xt9) ls.add(r, xt) r.set_interface_data(r10) xt.set_interface_data(xt10) ls.add(r, xt) r.set_interface_data(r3) dxt = ls.predict(-1 * r) dxt_sol = [ -4.19875900720576, -5.62710168134507, -2.21637309847878, -0.788630904723781, -11.8953162530024 ] np.testing.assert_allclose(dxt.get_interface_data(), dxt_sol) v = np.hstack((ls.vcurr, np.hstack(ls.vprev))) w = np.hstack((ls.wcurr, np.hstack(ls.wprev))) self.assertEqual(v.shape, (m, 5)) np.testing.assert_array_equal( v.T.flatten(), np.hstack((r10 - r9, r9 - r8, r8 - r7, r7 - r6, r6 - r5))) self.assertEqual(w.shape, (m, 5)) np.testing.assert_array_equal( w.T.flatten(), np.hstack( (xt10 - xt9, xt9 - xt8, xt8 - xt7, xt7 - xt6, xt6 - xt5))) # new solution step ls.finalize_solution_step() np.testing.assert_array_equal( np.hstack(ls.vprev).flatten(), np.hstack((np.empty((m, 0)))).flatten()) np.testing.assert_array_equal( np.hstack(ls.wprev).flatten(), np.hstack((np.empty((m, 0)))).flatten()) ls.initialize_solution_step() self.assertIsNone(ls.rref) self.assertFalse(ls.added) self.assertEqual(ls.vcurr.shape, (m, 0)) self.assertEqual(ls.wcurr.shape, (m, 0)) is_ready = ls.is_ready() self.assertFalse(is_ready) r.set_interface_data(r11) xt.set_interface_data(xt11) ls.add(r, xt) is_ready = ls.is_ready() self.assertFalse(is_ready) r.set_interface_data(r12) xt.set_interface_data(xt12) ls.add(r, xt) is_ready = ls.is_ready() self.assertTrue(is_ready)
class TestInterface(unittest.TestCase): def setUp(self): self.model_part_size = model_part_size = 3 self.parameters = { 'interface_a': [{ 'model_part': 'mp1', 'variables': ['pressure', 'traction'] }, { 'model_part': 'mp2', 'variables': ['density'] }], 'interface_b': [{ 'model_part': 'mp1', 'variables': ['pressure', 'displacement'] }, { 'model_part': 'mp2', 'variables': ['density'] }], 'interface_c': [{ 'model_part': 'mp1', 'variables': ['pressure', 'traction'] }, { 'model_part': 'mp3', 'variables': ['density'] }], 'interface_d': [{ 'model_part': 'mp2', 'variables': ['density'] }, { 'model_part': 'mp1', 'variables': ['pressure', 'displacement'] }], } self.model = Model() self.x0 = x0 = np.random.rand(3 * model_part_size) self.y0 = y0 = np.random.rand(3 * model_part_size) self.z0 = z0 = np.random.rand(3 * model_part_size) self.ids = ids = np.arange(0, model_part_size) np.random.shuffle(ids) self.model.create_model_part('mp1', x0[0:model_part_size], y0[0:model_part_size], z0[0:model_part_size], ids) self.model.create_model_part('mp2', x0[model_part_size:2 * model_part_size], y0[model_part_size:2 * model_part_size], z0[model_part_size:2 * model_part_size], ids) self.model.create_model_part( 'mp3', x0[2 * model_part_size:3 * model_part_size], y0[2 * model_part_size:3 * model_part_size], z0[2 * model_part_size:3 * model_part_size], ids) self.interface = Interface(self.parameters['interface_a'], self.model) self.scalar_size = 1 self.vector_size = 3 self.pressure = np.random.rand(model_part_size, self.scalar_size) self.traction = np.random.rand(model_part_size, self.vector_size) self.temperature = np.random.rand(model_part_size, self.scalar_size) self.density = np.random.rand(model_part_size, self.scalar_size) self.interface_data = np.random.rand(model_part_size * 5) def test_instantiation(self): parameters = {'mp1': ['pressure']} self.assertRaises(TypeError, Interface, parameters, self.model) parameters = [{'model_part': 'mp1', 'variables': ['pressure']}, 2] self.assertRaises(TypeError, Interface, parameters, self.model) parameters = [{'model_part': 'mp1'}] self.assertRaises(KeyError, Interface, parameters, self.model) parameters = [{ 'model_part': 'mp1', 'variables': ['pressure'], 'extra': 2 }] self.assertRaises(KeyError, Interface, parameters, self.model) parameters = [{'model_part': 'mp1', 'variables': 'pressure'}] self.assertRaises(TypeError, Interface, parameters, self.model) self.assertEqual(self.interface.parameters, self.parameters['interface_a']) def test_properties(self): # check model_part_variable_pairs() method pairs_a = self.interface.model_part_variable_pairs pairs_b = self.interface.model_part_variable_pairs self.assertFalse(pairs_a is pairs_b) self.assertEqual(str(pairs_a), str(pairs_b)) # check parameters() method parameters_bis = self.interface.parameters self.assertFalse(parameters_bis is self.parameters['interface_a']) self.assertEqual(str(parameters_bis), str(self.parameters['interface_a'])) # check model() method model_bis = self.interface.model self.assertTrue(model_bis is self.model) def test_model_part_variable_pairs(self): ref_result = [('mp1', 'pressure'), ('mp1', 'traction'), ('mp2', 'density')] self.assertListEqual(ref_result, self.interface.model_part_variable_pairs) def test_size(self): self.assertEqual(self.interface.size, 5 * self.model_part_size) def test_attribute_change(self): with self.assertRaises(AttributeError): self.interface.model_part_variable_pairs = () with self.assertRaises(AttributeError): parameters = {'mp1': ['pressure']} self.interface.parameters = parameters with self.assertRaises(AttributeError): self.interface.size = 0 def test_copy(self): self.interface.set_interface_data(self.interface_data) interface_copy = self.interface.copy() self.assertIsNot(self.interface, interface_copy) # interface_copy has the same values self.assertEqual(self.interface.model_part_variable_pairs, interface_copy.model_part_variable_pairs) np.testing.assert_array_equal(self.interface.get_interface_data(), interface_copy.get_interface_data()) # interface_copy not affected by change in self.interface interface_data = self.interface.get_interface_data() self.interface.set_interface_data(interface_data * 2) np.testing.assert_array_equal(interface_copy.get_interface_data(), interface_data) def test_get_variable_data(self): self.assertRaises(KeyError, self.interface.get_variable_data, 'mp2', 'pressure') model_part_variable_pair = ('mp1', 'pressure') variable_data = self.pressure # returns copy self.interface.set_variable_data(*model_part_variable_pair, variable_data) variable_data = self.interface.get_variable_data( *model_part_variable_pair) variable_data *= 2 np.testing.assert_array_equal( self.interface.get_variable_data(*model_part_variable_pair), variable_data / 2) def test_set_variable_data(self): self.interface.set_variable_data('mp1', 'pressure', self.pressure) self.interface.set_variable_data('mp1', 'traction', self.traction) self.interface.set_variable_data('mp2', 'density', self.density) np.testing.assert_array_equal( self.interface._Interface__data['mp1']['pressure'], self.pressure) np.testing.assert_array_equal( self.interface._Interface__data['mp1']['traction'], self.traction) np.testing.assert_array_equal( self.interface._Interface__data['mp2']['density'], self.density) # input is array with correct shape self.assertRaises(ValueError, self.interface.set_variable_data, 'mp1', 'pressure', self.traction) self.assertRaises(ValueError, self.interface.set_variable_data, 'mp1', 'pressure', self.pressure.flatten()) self.assertRaises(ValueError, self.interface.set_variable_data, 'mp1', 'pressure', list(self.pressure)) # copy is made of input self.interface.set_variable_data('mp1', 'pressure', self.pressure) self.pressure *= 2 np.testing.assert_array_equal( self.interface._Interface__data['mp1']['pressure'], self.pressure / 2) def test_get_interface_data(self): # output has correct size self.assertEqual(self.interface.get_interface_data().size, self.interface.size) # correct output from variable data self.interface.set_variable_data('mp1', 'pressure', self.pressure) self.interface.set_variable_data('mp1', 'traction', self.traction) self.interface.set_variable_data('mp2', 'density', self.density) interface_data = np.concatenate( (self.pressure.flatten(), self.traction.flatten(), self.density.flatten())) np.testing.assert_equal(self.interface.get_interface_data(), interface_data) # correct output from interface data self.interface.set_interface_data(self.interface_data) np.testing.assert_equal(self.interface.get_interface_data(), self.interface_data) # returns copy self.interface.get_interface_data() * 2 np.testing.assert_equal(self.interface.get_interface_data(), self.interface_data) def test_set_interface_data(self): self.interface.set_interface_data(self.interface_data) np.testing.assert_array_equal( self.interface._Interface__data['mp1']['pressure'].flatten(), self.interface_data[:self.scalar_size * self.model_part_size]) np.testing.assert_array_equal( self.interface._Interface__data['mp1']['traction'].flatten(), self.interface_data[self.scalar_size * self.model_part_size:(self.scalar_size + self.vector_size) * self.model_part_size]) np.testing.assert_array_equal( self.interface._Interface__data['mp2']['density'].flatten(), self.interface_data[(self.scalar_size + self.vector_size) * self.model_part_size:]) # input is array with correct shape self.assertRaises(ValueError, self.interface.set_interface_data, self.pressure) self.assertRaises(ValueError, self.interface.set_interface_data, self.interface_data.reshape(-1, 1)) self.assertRaises(ValueError, self.interface.set_interface_data, list(self.interface_data)) # copy is made of input self.interface.set_interface_data(self.interface_data) self.interface_data *= 2 np.testing.assert_array_equal(self.interface.get_interface_data(), self.interface_data / 2) def test_norm(self): self.interface.set_interface_data(self.interface_data) norm = np.linalg.norm(self.interface_data) self.assertEqual(self.interface.norm(), norm) def test_has_same_modelparts(self): self.interface.set_interface_data(self.interface_data) interface_a = self.interface.copy() interface_a.set_interface_data(np.random.rand(self.model_part_size * 5)) self.assertTrue(self.interface.has_same_model_parts(interface_a)) interface_b = Interface(self.parameters['interface_b'], self.model) interface_b.set_interface_data(self.interface_data) self.assertTrue(self.interface.has_same_model_parts(interface_b)) interface_c = Interface(self.parameters['interface_c'], self.model) interface_c.set_interface_data(self.interface_data) self.assertFalse(self.interface.has_same_model_parts(interface_c)) interface_d = Interface(self.parameters['interface_d'], self.model) interface_d.set_interface_data(self.interface_data) self.assertFalse(self.interface.has_same_model_parts(interface_d)) def create_test_interfaces(self): interface_data1 = np.random.rand(self.interface.size) interface_data2 = np.random.rand(self.interface.size) interface1 = self.interface.copy() interface1.set_interface_data(interface_data1) interface2 = self.interface.copy() interface2.set_interface_data(interface_data2) return interface_data1, interface_data2, interface1, interface2 def test_eq(self): self.interface.set_interface_data(self.interface_data) model_part_size = self.model_part_size x0 = self.x0 y0 = self.y0 z0 = self.z0 ids = self.ids model2 = Model() model2.create_model_part('mp1', x0[0:model_part_size], y0[0:model_part_size], z0[0:model_part_size], ids) model2.create_model_part('mp2', x0[model_part_size:2 * model_part_size], y0[model_part_size:2 * model_part_size], z0[model_part_size:2 * model_part_size], ids) interface2 = Interface(self.parameters['interface_a'], model2) interface2.set_interface_data(self.interface_data) self.assertIsNot(self.interface, interface2) self.assertEqual(self.interface, interface2) interface3 = Interface(self.parameters['interface_b'], model2) interface3.set_interface_data(self.interface_data) self.assertNotEqual(self.interface, interface3) interface4 = interface2.copy() interface_data4 = self.interface_data.copy() interface_data4[np.random.randint(interface4.size)] = np.random.rand() interface4.set_interface_data(interface_data4) self.assertNotEqual(self.interface, interface4) def test_add(self): interface_data1, interface_data2, interface1, interface2 = self.create_test_interfaces( ) interface_sum = interface1 + interface2 self.interface.set_interface_data(interface_data1 + interface_data2) self.assertEqual(interface_sum, self.interface) interface3 = interface1.copy() interface3 += interface2 self.assertEqual(interface3, self.interface) for number in (np.random.rand(1), float(np.random.rand(1)), int(10 * np.random.rand(1))): interface_sum = interface1 + number self.interface.set_interface_data(interface_data1 + number) self.assertEqual(interface_sum, self.interface) interface_sum = number + interface1 self.assertEqual(interface_sum, self.interface) interface3 = interface1.copy() interface3 += number self.assertEqual(interface3, self.interface) for other in ('a', True): with self.assertRaises(TypeError): _ = interface1 + other with self.assertRaises(TypeError): _ = other + interface1 with self.assertRaises(TypeError): interface1 += other def test_sub(self): interface_data1, interface_data2, interface1, interface2 = self.create_test_interfaces( ) interface_sum = interface1 - interface2 self.interface.set_interface_data(interface_data1 - interface_data2) self.assertEqual(interface_sum, self.interface) interface3 = interface1.copy() interface3 -= interface2 self.assertEqual(interface3, self.interface) for number in (np.random.rand(1), float(np.random.rand(1)), int(10 * np.random.rand(1))): interface_sum = interface1 - number self.interface.set_interface_data(interface_data1 - number) self.assertEqual(interface_sum, self.interface) interface_sum = number - interface1 self.assertEqual(interface_sum, self.interface) interface3 = interface1.copy() interface3 -= number self.assertEqual(interface3, self.interface) for other in ('a', True): with self.assertRaises(TypeError): _ = interface1 - other with self.assertRaises(TypeError): _ = other - interface1 with self.assertRaises(TypeError): interface1 -= other def test_mul(self): interface_data1, interface_data2, interface1, interface2 = self.create_test_interfaces( ) for number in (np.random.rand(1), float(np.random.rand(1)), int(10 * np.random.rand(1))): interface_sum = interface1 * number self.interface.set_interface_data(interface_data1 * number) self.assertEqual(interface_sum, self.interface) interface_sum = number * interface1 self.assertEqual(interface_sum, self.interface) interface3 = interface1.copy() interface3 *= number self.assertEqual(interface3, self.interface) for other in ('a', True, interface2): with self.assertRaises(TypeError): _ = interface1 * other with self.assertRaises(TypeError): _ = other * interface1 with self.assertRaises(TypeError): interface1 *= other def test_truediv(self): interface_data1, interface_data2, interface1, interface2 = self.create_test_interfaces( ) for number in (1 - np.random.rand(1), float(1 - np.random.rand(1)), int(10 * (1 - np.random.rand(1)))): interface_sum = interface1 / number self.interface.set_interface_data(interface_data1 / number) self.assertEqual(interface_sum, self.interface) with self.assertRaises(TypeError): _ = number / interface1 interface3 = interface1.copy() interface3 /= number self.assertEqual(interface3, self.interface) for other in ('a', True, interface2): with self.assertRaises(TypeError): _ = interface1 / other with self.assertRaises(TypeError): _ = other / interface1 with self.assertRaises(TypeError): interface1 /= other
class SolverWrapperOpenFOAM41(Component): @tools.time_initialize def __init__(self, parameters): super().__init__() # settings self.settings = parameters['settings'] self.working_directory = self.settings['working_directory'] self.env = get_solver_env(__name__, self.working_directory) # adapted application from openfoam ('coconut_<application name>') self.application = self.settings['application'] self.delta_t = self.settings['delta_t'] self.time_precision = self.settings['time_precision'] self.start_time = self.settings['timestep_start'] * self.delta_t self.timestep = self.physical_time = self.iteration = self.prev_timestamp = self.cur_timestamp = None self.openfoam_process = None self.write_interval = self.write_precision = None # boundary_names is the set of boundaries in OpenFoam used for coupling self.boundary_names = self.settings['boundary_names'] self.version = '4.1' # set on True to save copy of input and output files in every iteration self.debug = False # check interface names in 'interface_input' and 'interface_output' with boundary names provided in # boundary_names self.check_interfaces() # check that the correct modules have been loaded self.check_software() # remove possible CoCoNuT-message from previous interrupt self.remove_all_messages() # obtain number of cores from self.working_directory/system/decomposeParDict self.cores = 1 if self.settings['parallel']: file_name = os.path.join(self.working_directory, 'system/decomposeParDict') if not os.path.isfile(file_name): raise RuntimeError( f'In the parameters:\n{self.settings}\n key "parallel" is set to {True} but {file_name} ' f'does not exist') else: with open(file_name, 'r') as file: decomposedict_string = file.read() self.cores = of_io.get_int(input_string=decomposedict_string, keyword='numberOfSubdomains') # modify controlDict file to add pressure and wall shear stress functionObjects for all the boundaries in # self.settings["boundary_names"] self.read_modify_controldict() # creating Model self.model = data_structure.Model() # writeCellcentres writes cellcentres in internal field and face centres in boundaryField check_call(f'writeCellCentres -time 0 &> log.writeCellCentres;', cwd=self.working_directory, shell=True, env=self.env) boundary_filename = os.path.join(self.working_directory, 'constant/polyMesh/boundary') for boundary in self.boundary_names: with open(boundary_filename, 'r') as boundary_file: boundary_file_string = boundary_file.read() boundary_dict = of_io.get_dict(input_string=boundary_file_string, keyword=boundary) # get point ids and coordinates for all the faces in the boundary node_ids, node_coords = of_io.get_boundary_points( case_directory=self.working_directory, time_folder='0', boundary_name=boundary) nfaces = of_io.get_int(input_string=boundary_dict, keyword='nFaces') start_face = of_io.get_int(input_string=boundary_dict, keyword='startFace') # create input model part self.model.create_model_part(f'{boundary}_input', node_coords[:, 0], node_coords[:, 1], node_coords[:, 2], node_ids) filename_x = os.path.join(self.working_directory, '0/ccx') filename_y = os.path.join(self.working_directory, '0/ccy') filename_z = os.path.join(self.working_directory, '0/ccz') x0 = of_io.get_boundary_field(file_name=filename_x, boundary_name=boundary, size=nfaces, is_scalar=True) y0 = of_io.get_boundary_field(file_name=filename_y, boundary_name=boundary, size=nfaces, is_scalar=True) z0 = of_io.get_boundary_field(file_name=filename_z, boundary_name=boundary, size=nfaces, is_scalar=True) ids = np.arange(0, nfaces) # create output model part mp_output = self.model.create_model_part(f'{boundary}_output', x0, y0, z0, ids) mp_output.start_face = start_face mp_output.nfaces = nfaces # create interfaces self.interface_input = Interface(self.settings['interface_input'], self.model) self.interface_output = Interface(self.settings['interface_output'], self.model) # time self.init_time = self.init_time self.run_time = 0.0 # compile openfoam adapted solver solver_dir = os.path.join(os.path.dirname(__file__), self.application) try: check_call(f'wmake {solver_dir} &> log.wmake', cwd=self.working_directory, shell=True, env=self.env) except subprocess.CalledProcessError: raise RuntimeError( f'Compilation of {self.application} failed. Check {os.path.join(self.working_directory, "log.wmake")}' ) self.residual_variables = self.settings.get('residual_variables', None) self.res_filepath = os.path.join(self.working_directory, 'residuals.csv') if self.residual_variables is not None: self.write_residuals_fileheader() @tools.time_initialize def initialize(self): super().initialize() # define timestep and physical time self.timestep = 0 self.physical_time = self.start_time # copy zero folder to folder with correctly named timeformat if self.start_time == 0: timestamp = '{:.{}f}'.format(self.physical_time, self.time_precision) path_orig = os.path.join(self.working_directory, '0') path_new = os.path.join(self.working_directory, timestamp) shutil.rmtree(path_new, ignore_errors=True) shutil.copytree(path_orig, path_new) # if parallel do a decomposition and establish a remapping for the output based on the faceProcAddressing """Note concerning the sequence: The file ./processorX/constant/polyMesh/pointprocAddressing contains a list of indices referring to the original index in the ./constant/polyMesh/points file, these indices go from 0 to nPoints -1 However, mesh faces can be shared between processors and it has to be tracked whether these are inverted or not This inversion is indicated by negative indices However, as minus 0 is not a thing, the indices are first incremented by 1 before inversion Therefore to get the correct index one should use |index|-1!! Normally no doubles should be encountered on an interface as these faces are not shared by processors """ if self.settings['parallel']: if self.start_time == 0: check_call( f'decomposePar -force -time {self.start_time} &> log.decomposePar', cwd=self.working_directory, shell=True, env=self.env) for boundary in self.boundary_names: mp_output = self.model.get_model_part(f'{boundary}_output') mp_output.sequence = [] for p in range(self.cores): path = os.path.join( self.working_directory, f'processor{p}/constant/polyMesh/faceProcAddressing') with open(path, 'r') as f: face_proc_add_string = f.read() face_proc_add = np.abs( of_io.get_scalar_array( input_string=face_proc_add_string, is_int=True)) face_proc_add -= 1 mp_output.sequence += ( face_proc_add[(face_proc_add >= mp_output.start_face) & (face_proc_add < mp_output.start_face + mp_output.nfaces)] - mp_output.start_face).tolist() np.savetxt(os.path.join(self.working_directory, f'sequence_{boundary}.txt'), np.array(mp_output.sequence), fmt='%i') if len(mp_output.sequence) != mp_output.nfaces: print(f'sequence: {len(mp_output.sequence)}') print(f'nNodes: {mp_output.size}') raise ValueError( 'Number of face indices in sequence does not correspond to number of faces' ) # starting the OpenFOAM infinite loop for coupling! if not self.settings['parallel']: cmd = self.application + '&> log.' + self.application else: cmd = 'mpirun -np ' + str( self.cores ) + ' ' + self.application + ' -parallel &> log.' + self.application self.openfoam_process = subprocess.Popen(cmd, cwd=self.working_directory, shell=True, env=self.env) def initialize_solution_step(self): super().initialize_solution_step() # for parallel: create a folder with the correct time stamp for decomposition of pointDisplacement_Next # for serial: folder will normally be present, except for time 0: make a folder 0.0000 with specified precision timestamp = '{:.{}f}'.format(self.physical_time, self.time_precision) path = os.path.join(self.working_directory, timestamp) if self.cores > 1 or self.physical_time == 0: os.makedirs(path, exist_ok=True) # prepare new time step folder and reset the number of iterations self.timestep += 1 self.iteration = 0 self.physical_time += self.delta_t self.prev_timestamp = timestamp self.cur_timestamp = f'{self.physical_time:.{self.time_precision}f}' if not self.settings['parallel']: # if serial new_path = os.path.join(self.working_directory, self.cur_timestamp) if os.path.isdir(new_path): tools.print_info( f'Overwrite existing time step folder: {new_path}', layout='warning') check_call(f'rm -rf {new_path}', shell=True) check_call(f'mkdir -p {new_path}', shell=True) else: for i in np.arange(self.cores): new_path = os.path.join(self.working_directory, 'processor' + str(i), self.cur_timestamp) if os.path.isdir(new_path): if i == 0: tools.print_info( f'Overwrite existing time step folder: {new_path}', layout='warning') check_call(f'rm -rf {new_path}', shell=True) check_call(f'mkdir -p {new_path}', shell=True) self.send_message('next') self.wait_message('next_ready') @tools.time_solve_solution_step def solve_solution_step(self, interface_input): self.iteration += 1 # store incoming displacements self.interface_input.set_interface_data( interface_input.get_interface_data()) # write interface data to OpenFOAM-file self.write_node_input() # copy output data for debugging if self.debug: if self.cores > 1: for i in range(0, self.cores): path_from = os.path.join(self.working_directory, 'processor' + str(i), self.prev_timestamp, 'pointDisplacement_Next') path_to = os.path.join( self.working_directory, 'processor' + str(i), self.prev_timestamp, 'pointDisplacement_Next_Iter' + str(self.iteration)) shutil.copy(path_from, path_to) else: path_from = os.path.join(self.working_directory, self.prev_timestamp, 'pointDisplacement_Next') path_to = os.path.join( self.working_directory, self.prev_timestamp, 'pointDisplacement_Next_Iter' + str(self.iteration)) shutil.copy(path_from, path_to) self.delete_prev_iter_output() self.send_message('continue') self.wait_message('continue_ready') # copy output data for debugging if self.debug: for boundary in self.boundary_names: # specify location of pressure and traction traction_name = 'TRACTION_' + boundary pressure_name = 'PRESSURE_' + boundary wss_filepath = os.path.join( self.working_directory, 'postProcessing', traction_name, 'surface', self.cur_timestamp, f'wallShearStress_patch_{boundary}.raw') pres_filepath = os.path.join(self.working_directory, 'postProcessing', pressure_name, 'surface', self.cur_timestamp, f'p_patch_{boundary}.raw') wss_iter_filepath = os.path.join( self.working_directory, 'postProcessing', traction_name, 'surface', self.cur_timestamp, f'wallShearStress_patch_{boundary}_{self.iteration}.raw') pres_iter_filepath = os.path.join( self.working_directory, 'postProcessing', pressure_name, 'surface', self.cur_timestamp, f'p_patch_{boundary}_{self.iteration}.raw') shutil.copy(wss_filepath, wss_iter_filepath) shutil.copy(pres_filepath, pres_iter_filepath) # read data from OpenFOAM self.read_node_output() # return interface_output object return self.interface_output def finalize_solution_step(self): super().finalize_solution_step() prev_timestep = self.timestep - 1 # remove the folder that was used for pointDisplacement_Next if not in writeInterval if self.settings['parallel']: dir_pointdisp_next = os.path.join(self.working_directory, self.prev_timestamp) shutil.rmtree(dir_pointdisp_next) if prev_timestep % self.write_interval: for p in range(self.cores): prev_timestep_dir = os.path.join( self.working_directory, f'processor{p}/{self.prev_timestamp}') shutil.rmtree(prev_timestep_dir) else: if prev_timestep % self.write_interval: dir_pointdisp_next = os.path.join(self.working_directory, self.prev_timestamp) shutil.rmtree(dir_pointdisp_next) if not (self.timestep % self.write_interval): self.send_message('save') self.wait_message('save_ready') if self.residual_variables is not None: self.write_of_residuals() def finalize(self): super().finalize() self.send_message('stop') self.wait_message('stop_ready') self.openfoam_process.wait() def get_interface_input(self): return self.interface_input def get_interface_output(self): return self.interface_output def delete_prev_iter_output(self): # pressure and wall shear stress files are removed to avoid openfoam to append data in the new iteration for boundary in self.boundary_names: # specify location of pressure and traction traction_name = 'TRACTION_' + boundary pressure_name = 'PRESSURE_' + boundary wss_file = os.path.join( self.working_directory, 'postProcessing', traction_name, 'surface', self.cur_timestamp, 'wallShearStress_patch_' + boundary + '.raw') pres_file = os.path.join(self.working_directory, 'postProcessing', pressure_name, 'surface', self.cur_timestamp, 'p_patch_' + boundary + '.raw') if os.path.isfile(wss_file): os.remove(wss_file) if os.path.isfile(pres_file): os.remove(pres_file) def read_node_output(self): """ reads the pressure and wall shear stress from the <case directory>/postProcessing for serial and parallel. In case of parallel, it uses mp.sequence (using faceProcAddressing) to map the values to the face centres. :return: """ # default value is 1.0 for compressible case # when the solver is incompressible, the pressure and shear stress are kinematic; therefore multiply with # the fluid density density = 1.0 if self.settings['is_incompressible']: density = self.settings['density'] for boundary in self.boundary_names: # specify location of pressure and traction traction_name = 'TRACTION_' + boundary pressure_name = 'PRESSURE_' + boundary mp_name = f'{boundary}_output' mp = self.model.get_model_part(mp_name) nfaces = mp.size wss_filename = os.path.join( self.working_directory, 'postProcessing', traction_name, 'surface', self.cur_timestamp, 'wallShearStress_patch_' + boundary + '.raw') pres_filepath = os.path.join(self.working_directory, 'postProcessing', pressure_name, 'surface', self.cur_timestamp, 'p_patch_' + boundary + '.raw') # check if the pressure and wall shear stress files completed by openfoam and read data self.check_output_file(wss_filename, nfaces) wss_tmp = np.loadtxt(wss_filename, comments='#')[:, 3:] self.check_output_file(pres_filepath, nfaces) pres_tmp = np.loadtxt(pres_filepath, comments='#')[:, 3] if self.settings['parallel']: pos_list = mp.sequence else: pos_list = [pos for pos in range(0, nfaces)] wall_shear_stress = np.empty_like(wss_tmp) pressure = np.empty((pres_tmp.size, 1)) wall_shear_stress[pos_list, ] = wss_tmp[:, ] pressure[pos_list, 0] = pres_tmp self.interface_output.set_variable_data( mp_name, 'traction', wall_shear_stress * -1 * density) self.interface_output.set_variable_data(mp_name, 'pressure', pressure * density) # noinspection PyMethodMayBeStatic def write_footer(self, file_name): # write OpenFOAM-footer at the end of file with open(file_name, 'a') as f: f.write( '\n// ************************************************************************* //\n' ) def write_node_input(self): """ creates pointDisplacementNext for supplying the displacement field in the FSI coupling. This file is created from 0/pointDisplacement. The boundary field for boundaries participating in the FSI coupling is modified to supply the boundary displacement field from structural solver. If the OpenFOAM solver is run in parallel, the field is subsequently decomposed using the command: decomposePar. :return: """ pointdisp_filename_ref = os.path.join(self.working_directory, '0', 'pointDisplacement') pointdisp_filename = os.path.join(self.working_directory, self.prev_timestamp, 'pointDisplacement_Next') with open(pointdisp_filename_ref, 'r') as ref_file: pointdisp_string = ref_file.read() for boundary in self.boundary_names: mp_name = f'{boundary}_input' displacement = self.interface_input.get_variable_data( mp_name, 'displacement') boundary_dict = of_io.get_dict(input_string=pointdisp_string, keyword=boundary) boundary_dict_new = of_io.update_vector_array_dict( dict_string=boundary_dict, vector_array=displacement) pointdisp_string = pointdisp_string.replace( boundary_dict, boundary_dict_new) with open(pointdisp_filename, 'w') as f: f.write(pointdisp_string) if self.settings['parallel']: check_call( f'decomposePar -fields -time {self.prev_timestamp} &> log.decomposePar;', cwd=self.working_directory, shell=True, env=self.env) # noinspection PyMethodMayBeStatic def check_output_file(self, filename, nfaces): counter = 0 nlines = 0 lim = 1000 while (nlines < nfaces + 2) and counter < lim: if os.path.isfile(filename): with open(filename, 'r') as f: nlines = sum(1 for _ in f) time.sleep(0.01) counter += 1 if counter == lim: raise RuntimeError(f'Timed out waiting for file: {filename}') else: return True def send_message(self, message): file = os.path.join(self.working_directory, message + '.coco') open(file, 'w').close() return def wait_message(self, message): wait_time_lim = 10 * 60 # 10 minutes maximum waiting time for a single flow solver iteration cumul_time = 0 file = os.path.join(self.working_directory, message + '.coco') while not os.path.isfile(file): time.sleep(0.01) cumul_time += 0.01 if cumul_time > wait_time_lim: self.openfoam_process.kill() self.openfoam_process.wait() raise RuntimeError( f'CoCoNuT timed out in the OpenFOAM solver_wrapper, waiting for message: ' f'{message}.coco') os.remove(file) return def check_message(self, message): file = os.path.join(self.working_directory, message + '.coco') if os.path.isfile(file): os.remove(file) return True return False def remove_all_messages(self): for file_name in os.listdir(self.working_directory): if file_name.endswith('.coco'): file = os.path.join(self.working_directory, file_name) os.remove(file) def check_software(self): if check_call(self.application + ' -help &> checkSoftware', shell=True, env=self.env) != 0: raise RuntimeError( f'OpenFOAM not loaded properly. You should perform the following steps:\n' f'-\tLoad the module for OpenFOAM-{self.version},\n' f'-\tSource $FOAM_BASH,\n' f'-\tCompile {self.application}') # check version with open('checkSoftware', 'r') as f: last_line = f.readlines( )[-2] # second last line contains 'Build: XX' with XX the version number os.remove('checkSoftware') version_nr = last_line.split(' ')[-1] if version_nr[:-1] != self.version: raise RuntimeError( f'OpenFOAM-{self.version} should be loaded! Currently, OpenFOAM-{version_nr[:-1]} is loaded' ) def check_interfaces(self): """ checks the dictionaries from 'interface_input' and 'interface_output' in parameters.json file. The model part name must be the concatenation of an entry from `boundary_names` and the string `_input`, for 'interface_input' and for 'interface_output' it must be the concatenation of an entry from `boundary_names` and the string `_output`. :return: """ input_interface_model_parts = [ param['model_part'] for param in self.settings['interface_input'] ] output_interface_model_parts = [ param['model_part'] for param in self.settings['interface_output'] ] boundary_names = self.settings['boundary_names'] for boundary_name in boundary_names: if f'{boundary_name}_input' not in input_interface_model_parts: raise RuntimeError( f'Error in json file: {boundary_name}_input not listed in "interface_input": ' f'{self.settings["interface_input"]}.\n. <boundary> in the "boundary_names" in json file should ' f'have corresponding <boundary>_input in "interface_input" list' ) if f'{boundary_name}_output' not in output_interface_model_parts: raise RuntimeError( f'Error in json file: {boundary_name}_output not listed in "interface_output": ' f'{self.settings["interface_output"]}.\n. <boundary> in the "boundary_names" in json file should ' f'have corresponding <boundary>_output in "interface_output" list' ) def read_modify_controldict(self): """ reads the controlDict file in the case-directory and modifies some entries required by the coconut_pimpleFoam. The values of these entries are taken from paramters.json file. :return: """ file_name = os.path.join(self.working_directory, 'system/controlDict') with open(file_name, 'r') as control_dict_file: control_dict = control_dict_file.read() self.write_interval = of_io.get_int(input_string=control_dict, keyword='writeInterval') time_format = of_io.get_string(input_string=control_dict, keyword='timeFormat') self.write_precision = of_io.get_int(input_string=control_dict, keyword='writePrecision') if not time_format == 'fixed': msg = f'timeFormat:{time_format} in controlDict not implemented. Changed to "fixed"' tools.print_info(msg, layout='warning') control_dict = re.sub(r'timeFormat' + of_io.delimter + r'\w+', f'timeFormat fixed', control_dict) control_dict = re.sub(r'application' + of_io.delimter + r'\w+', f'application {self.application}', control_dict) control_dict = re.sub( r'startTime' + of_io.delimter + of_io.float_pattern, f'startTime {self.start_time}', control_dict) control_dict = re.sub( r'deltaT' + of_io.delimter + of_io.float_pattern, f'deltaT {self.delta_t}', control_dict) control_dict = re.sub( r'timePrecision' + of_io.delimter + of_io.int_pattern, f'timePrecision {self.time_precision}', control_dict) control_dict = re.sub( r'endTime' + of_io.delimter + of_io.float_pattern, f'endTime 1e15', control_dict) # delete previously defined coconut functions coconut_start_string = '// CoCoNuT function objects' control_dict = re.sub(coconut_start_string + r'.*', '', control_dict, flags=re.S) with open(file_name, 'w') as control_dict_file: control_dict_file.write(control_dict) control_dict_file.write(coconut_start_string + '\n') control_dict_file.write('boundary_names (') for boundary_name in self.boundary_names: control_dict_file.write(boundary_name + ' ') control_dict_file.write(');\n\n') control_dict_file.write('functions\n{\n') for boundary_name in self.boundary_names: control_dict_file.write( f'PRESSURE_{boundary_name}\n' f'{{\n' f'type surfaceRegion;\n' f'libs ("libfieldFunctionObjects.so");\n' f'executeControl timeStep;\n' f'executeInterval 1;\n' f'writeControl timeStep;\n' f'writeInterval 1;\n' f'timeFormat fixed;\n' f'timePrecision {self.time_precision};\n' f'operation none;\n' f'writeFields true;\n' f'surfaceFormat raw;\n' f'regionType patch;\n' f'name {boundary_name};\n' f'fields (p);\n' f'}}\n') control_dict_file.write( f'wallShearStress\n' f'{{\n' f'type wallShearStress;\n' f'libs ("libfieldFunctionObjects.so");\n' f'executeControl timeStep;\n' f'executeInterval 1;\n' f'writeControl timeStep;\n' f'writeInterval 1;\n' f'timeFormat fixed;\n' f'timePrecision {self.time_precision};\n' f'log false;\n' f'}}\n') control_dict_file.write( f'TRACTION_{boundary_name}\n' f'{{\n' f'type surfaceRegion;\n' f'libs ("libfieldFunctionObjects.so");\n' f'' f'executeControl timeStep;\n' f'executeInterval 1;\n' f'writeControl timeStep;\n' f'writeInterval 1;\n' f'timeFormat fixed;\n' f'timePrecision {self.time_precision};\n' f'operation none;\n' f'writeFields true;\n' f'surfaceFormat raw;\n' f'regionType patch;\n' f'name {boundary_name};\n' f'fields ( wallShearStress);\n' f'}}\n') control_dict_file.write('}') self.write_footer(file_name) def write_residuals_fileheader(self): header = '' sep = ', ' with open(self.res_filepath, 'w') as f: f.write('# Residuals\n') for variable in self.residual_variables: header += variable + sep f.write(header.strip(sep) + '\n') def write_of_residuals(self): """ it reads the log file generated by coconut_pimpleFoam solver and writes the last initial residual of the fields in the pimple iterations, for every coupling iteration. The fields should be given in the parameters.json file with the key-'residual_variables' and values-list(OpenFOAM variables), e.g. 'residual_variables': ['U', 'p'] :return: """ log_filepath = os.path.join(self.working_directory, f'log.{self.application}') if os.path.isfile(log_filepath): with open(log_filepath, 'r') as f: log_string = f.read() time_start_string = f'Time = {self.prev_timestamp}' time_end_string = f'Time = {self.cur_timestamp}' match = re.search(time_start_string + r'(.*)' + time_end_string, log_string, flags=re.S) if match is not None: time_block = match.group(1) iteration_block_list = re.findall( r'Coupling iteration = \d+(.*?)Coupling iteration \d+ end', time_block, flags=re.S) for iteration_block in iteration_block_list: residual_array = np.empty(len(self.residual_variables)) for i, variable in enumerate(self.residual_variables): search_string = f'Solving for {variable}, Initial residual = ({of_io.float_pattern})' var_residual_list = re.findall(search_string, iteration_block) if var_residual_list: # last initial residual of pimple loop var_residual = float(var_residual_list[-1]) residual_array[i] = var_residual else: raise RuntimeError( f'Variable: {variable} equation is not solved in {self.application}' ) with open(self.res_filepath, 'a') as f: np.savetxt(f, [residual_array], delimiter=', ')
def test_has_same_modelparts(self): self.interface.set_interface_data(self.interface_data) interface_a = self.interface.copy() interface_a.set_interface_data(np.random.rand(self.model_part_size * 5)) self.assertTrue(self.interface.has_same_model_parts(interface_a)) interface_b = Interface(self.parameters['interface_b'], self.model) interface_b.set_interface_data(self.interface_data) self.assertTrue(self.interface.has_same_model_parts(interface_b)) interface_c = Interface(self.parameters['interface_c'], self.model) interface_c.set_interface_data(self.interface_data) self.assertFalse(self.interface.has_same_model_parts(interface_c)) interface_d = Interface(self.parameters['interface_d'], self.model) interface_d.set_interface_data(self.interface_data) self.assertFalse(self.interface.has_same_model_parts(interface_d))
def __init__(self, parameters): super().__init__() # settings self.settings = parameters['settings'] self.working_directory = self.settings['working_directory'] self.env = get_solver_env(__name__, self.working_directory) # adapted application from openfoam ('coconut_<application name>') self.application = self.settings['application'] self.delta_t = self.settings['delta_t'] self.time_precision = self.settings['time_precision'] self.start_time = self.settings['timestep_start'] * self.delta_t self.timestep = self.physical_time = self.iteration = self.prev_timestamp = self.cur_timestamp = None self.openfoam_process = None self.write_interval = self.write_precision = None # boundary_names is the set of boundaries in OpenFoam used for coupling self.boundary_names = self.settings['boundary_names'] self.version = '4.1' # set on True to save copy of input and output files in every iteration self.debug = False # check interface names in 'interface_input' and 'interface_output' with boundary names provided in # boundary_names self.check_interfaces() # check that the correct modules have been loaded self.check_software() # remove possible CoCoNuT-message from previous interrupt self.remove_all_messages() # obtain number of cores from self.working_directory/system/decomposeParDict self.cores = 1 if self.settings['parallel']: file_name = os.path.join(self.working_directory, 'system/decomposeParDict') if not os.path.isfile(file_name): raise RuntimeError( f'In the parameters:\n{self.settings}\n key "parallel" is set to {True} but {file_name} ' f'does not exist') else: with open(file_name, 'r') as file: decomposedict_string = file.read() self.cores = of_io.get_int(input_string=decomposedict_string, keyword='numberOfSubdomains') # modify controlDict file to add pressure and wall shear stress functionObjects for all the boundaries in # self.settings["boundary_names"] self.read_modify_controldict() # creating Model self.model = data_structure.Model() # writeCellcentres writes cellcentres in internal field and face centres in boundaryField check_call(f'writeCellCentres -time 0 &> log.writeCellCentres;', cwd=self.working_directory, shell=True, env=self.env) boundary_filename = os.path.join(self.working_directory, 'constant/polyMesh/boundary') for boundary in self.boundary_names: with open(boundary_filename, 'r') as boundary_file: boundary_file_string = boundary_file.read() boundary_dict = of_io.get_dict(input_string=boundary_file_string, keyword=boundary) # get point ids and coordinates for all the faces in the boundary node_ids, node_coords = of_io.get_boundary_points( case_directory=self.working_directory, time_folder='0', boundary_name=boundary) nfaces = of_io.get_int(input_string=boundary_dict, keyword='nFaces') start_face = of_io.get_int(input_string=boundary_dict, keyword='startFace') # create input model part self.model.create_model_part(f'{boundary}_input', node_coords[:, 0], node_coords[:, 1], node_coords[:, 2], node_ids) filename_x = os.path.join(self.working_directory, '0/ccx') filename_y = os.path.join(self.working_directory, '0/ccy') filename_z = os.path.join(self.working_directory, '0/ccz') x0 = of_io.get_boundary_field(file_name=filename_x, boundary_name=boundary, size=nfaces, is_scalar=True) y0 = of_io.get_boundary_field(file_name=filename_y, boundary_name=boundary, size=nfaces, is_scalar=True) z0 = of_io.get_boundary_field(file_name=filename_z, boundary_name=boundary, size=nfaces, is_scalar=True) ids = np.arange(0, nfaces) # create output model part mp_output = self.model.create_model_part(f'{boundary}_output', x0, y0, z0, ids) mp_output.start_face = start_face mp_output.nfaces = nfaces # create interfaces self.interface_input = Interface(self.settings['interface_input'], self.model) self.interface_output = Interface(self.settings['interface_output'], self.model) # time self.init_time = self.init_time self.run_time = 0.0 # compile openfoam adapted solver solver_dir = os.path.join(os.path.dirname(__file__), self.application) try: check_call(f'wmake {solver_dir} &> log.wmake', cwd=self.working_directory, shell=True, env=self.env) except subprocess.CalledProcessError: raise RuntimeError( f'Compilation of {self.application} failed. Check {os.path.join(self.working_directory, "log.wmake")}' ) self.residual_variables = self.settings.get('residual_variables', None) self.res_filepath = os.path.join(self.working_directory, 'residuals.csv') if self.residual_variables is not None: self.write_residuals_fileheader()