def test_call_3d_var(self): var = 'displacement' mp_name_in = 'wall_in' mp_name_out = 'wall_out' n = 10 x, y, z = np.random.rand(n), np.random.rand(n), np.random.rand(n) v_in = np.random.rand(n, 3) model = data_structure.Model() model.create_model_part(mp_name_in, x, y, z, np.arange(n)) parameters_in = [{'model_part': mp_name_in, 'variables': [var]}] interface_in = data_structure.Interface(parameters_in, model) interface_in.set_variable_data(mp_name_in, var, v_in) mapper = create_instance(self.parameters) mapper.initialize(model, mp_name_in, mp_name_out, forward=True) parameters_out = [{'model_part': mp_name_out, 'variables': [var]}] interface_out = data_structure.Interface(parameters_out, model) mapper((interface_in, mp_name_in, var), (interface_out, mp_name_out, var)) v_out = interface_out.get_variable_data(mp_name_out, var) np.testing.assert_array_equal(v_in[:, 0], v_out[:, 1]) np.testing.assert_array_equal(v_in[:, 1], v_out[:, 2]) np.testing.assert_array_equal(v_in[:, 2], v_out[:, 0])
def __init__(self, n_from, n_to): self.n_from = n_from self.n_to = n_to self.var = 'pressure' self.mp_name_from = 'wall_from' self.mp_name_to = 'wall_to' self.model = data_structure.Model() # Interface from dtheta = 2 * np.pi / self.n_from self.theta_from = np.linspace(0, 2 * np.pi - dtheta, self.n_from) self.x_from, self.y_from = self.get_cartesian(self.theta_from) self.v_from = self.fun(self.x_from, self.y_from) self.model.create_model_part(self.mp_name_from, self.x_from, self.y_from, np.zeros(self.n_from), np.arange(self.n_from)) parameters = [{'model_part': self.mp_name_from, 'variables': [self.var]}] self.interface_from = data_structure.Interface(parameters, self.model) self.interface_from.set_interface_data(self.v_from) # Interface to dtheta = 2 * np.pi / self.n_to self.theta_to = np.linspace(0, 2 * np.pi - dtheta, self.n_to) self.x_to, self.y_to = self.get_cartesian(self.theta_to) self.model.create_model_part(self.mp_name_to, self.x_to, self.y_to, np.zeros(self.n_to), np.arange(self.n_to)) parameters = [{'model_part': self.mp_name_to, 'variables': [self.var]}] self.interface_to = data_structure.Interface(parameters, self.model)
def __call__(self, args_from, args_to): # unpack arguments interface_from, mp_name_from, var_from = args_from interface_to, mp_name_to, var_to = args_to # check variables if var_from not in variables_dimensions: raise NameError(f'Variable "{var_from}" does not exist') if var_from != var_to: raise TypeError('Variables must be equal') var = var_from # create Interfaces interfaces = [] for mp_name in self.mp_names: parameters = [{'model_part': mp_name, 'variables': [var]}] interfaces.append(data_structure.Interface(parameters, self.model)) # map data data_from = interface_from.get_variable_data(mp_name_from, var) interfaces[0].set_variable_data(self.mp_names[0], var, data_from) for i, mapper in enumerate(self.mappers): mapper((interfaces[i], self.mp_names[i], var), (interfaces[i + 1], self.mp_names[i + 1], var)) data_to = interfaces[-1].get_variable_data(self.mp_names[-1], var) interface_to.set_variable_data(mp_name_to, var, data_to)
def test_mapper_combined(self): parameter_file_name = os.path.join(os.path.dirname(__file__), 'test_combined.json') with open(parameter_file_name, 'r') as parameter_file: parameters = json.load(parameter_file) # compare 3 mappers: nearest, combined_a, combined_b for var in ['pressure', 'displacement']: mp_name_from = 'wall_from' mp_name_to = 'wall_to' model = data_structure.Model() n = 100 tmp = np.linspace(0, 1, n) x, y, z = tmp, tmp**1.1, tmp**1.2 v_from = np.random.rand(n, data_structure.variables_dimensions[var]) mp_from = model.create_model_part(mp_name_from, x, y, z, np.arange(n)) mp_to = model.create_model_part(mp_name_to, np.flip(x), np.flip(y), np.flip(z), np.arange(n)) parameters_from = [{ 'model_part': mp_name_from, 'variables': [var] }] int_from = data_structure.Interface(parameters_from, model) int_from.set_variable_data(mp_name_from, var, v_from) parameters_to = [{'model_part': mp_name_to, 'variables': [var]}] int_to = data_structure.Interface(parameters_to, model) # create mappers, get output data data = [] for mapper_name in [ 'mapper_nearest', 'mapper_combined_a', 'mapper_combined_b' ]: mapper = create_instance(parameters[mapper_name]) mapper.initialize(mp_from, mp_to) mapper((int_from, mp_name_from, var), (int_to, mp_name_to, var)) data.append(int_to.get_variable_data(mp_name_to, var)) # check output data np.testing.assert_array_equal(data[0], data[1]) np.testing.assert_array_equal(data[0], data[2])
def __init__(self, n_x_from, n_theta_from, n_x_to, n_theta_to, length): self.n_x_from = n_x_from self.n_theta_from = n_theta_from self.n_from = n_x_from * n_theta_from self.n_x_to = n_x_to self.n_theta_to = n_theta_to self.n_to = n_x_to * n_theta_to self.length = length self.var = 'pressure' self.mp_name_from = 'wall_from' self.mp_name_to = 'wall_to' self.model = data_structure.Model() self.model = data_structure.Model() # Interface from shape = (self.n_x_from, self.n_theta_from) dtheta = 2 * np.pi / self.n_theta_from theta_from = np.ones(shape) * np.linspace(0, 2 * np.pi - dtheta, self.n_theta_from).reshape(1, -1) self.x_from = np.ones(shape) * np.linspace(0, self.length, self.n_x_from).reshape(-1, 1) self.y_from, self.z_from = self.get_cartesian(theta_from) self.v_from = self.fun(self.x_from, self.y_from, self.z_from) self.model.create_model_part(self.mp_name_from, self.x_from.flatten(), self.y_from.flatten(), self.z_from.flatten(), np.arange(self.n_from)) parameters = [{'model_part': self.mp_name_from, 'variables': [self.var]}] self.interface_from = data_structure.Interface(parameters, self.model) self.interface_from.set_interface_data(self.v_from.flatten()) # Interface to shape = (self.n_x_to, self.n_theta_to) dtheta = 2 * np.pi / self.n_theta_to theta_to = np.ones(shape) * np.linspace(0, 2 * np.pi - dtheta, self.n_theta_to).reshape(1, -1) self.x_to = np.ones(shape) * np.linspace(0, self.length, self.n_x_to).reshape(-1, 1) self.y_to, self.z_to = self.get_cartesian(theta_to) self.model.create_model_part(self.mp_name_to, self.x_to.flatten(), self.y_to.flatten(), self.z_to.flatten(), np.arange(self.n_to)) parameters = [{'model_part': self.mp_name_to, 'variables': [self.var]}] self.interface_to = data_structure.Interface(parameters, self.model)
def __init__(self, n_x_from, n_y_from, n_x_to, n_y_to): self.n_x_from = n_x_from self.n_y_from = n_y_from self.n_from = n_x_from * n_y_from self.n_x_to = n_x_to self.n_y_to = n_y_to self.n_to = n_x_to * n_y_to self.var = 'displacement' self.mp_name_from = 'wall_from' self.mp_name_to = 'wall_to' self.model = data_structure.Model() model = data_structure.Model() # ModelPart from shape = (self.n_x_from, self.n_y_from) self.x_from = np.ones(shape) * np.linspace(-1, 1, self.n_x_from).reshape(-1, 1) self.y_from = np.ones(shape) * np.linspace(-1, 1, self.n_y_from).reshape(1, -1) self.z_from = np.sinc(np.sqrt((10 * self.x_from) ** 2 + (self.y_from * 10) ** 2) / np.pi) self.v_from = self.fun(self.x_from, self.y_from, self.z_from) self.model.create_model_part(self.mp_name_from, self.x_from.flatten(), self.y_from.flatten(), self.z_from.flatten(), np.arange(self.n_from)) parameters = [{'model_part': self.mp_name_from, 'variables': [self.var]}] self.interface_from = data_structure.Interface(parameters, self.model) tmp = np.hstack((self.v_from[0].reshape(-1, 1), self.v_from[1].reshape(-1, 1), self.v_from[2].reshape(-1, 1))) self.interface_from.set_variable_data(self.mp_name_from, self.var, tmp) # ModelPart to shape = (self.n_x_to, self.n_y_to) self.x_to = np.ones(shape) * np.linspace(-1, 1, self.n_x_to).reshape(-1, 1) self.y_to = np.ones(shape) * np.linspace(-1, 1, self.n_y_to).reshape(1, -1) self.z_to = np.sinc(np.sqrt((10 * self.x_to) ** 2 + (self.y_to * 10) ** 2) / np.pi) self.v_to = self.fun(self.x_to, self.y_to, self.z_to) self.model.create_model_part(self.mp_name_to, self.x_to.flatten(), self.y_to.flatten(), self.z_to.flatten(), np.arange(self.n_to)) parameters = [{'model_part': self.mp_name_to, 'variables': [self.var]}] self.interface_to = data_structure.Interface(parameters, self.model)
def __init__(self, n_theta_from, n_phi_from, n_theta_to, n_phi_to): self.n_theta_from = n_theta_from self.n_phi_from = n_phi_from self.n_from = n_theta_from * n_phi_from self.n_theta_to = n_theta_to self.n_phi_to = n_phi_to # for bounding box: not too far from n_phi_from! self.n_to = n_theta_to * n_phi_to self.var = 'pressure' self.mp_name_from = 'wall_from' self.mp_name_to = 'wall_to' self.model = data_structure.Model() # Interface from shape = (self.n_theta_from, self.n_phi_from) dtheta = 2 * np.pi / self.n_theta_from dphi = np.pi / (self.n_phi_from - 1) theta = np.ones(shape) * np.linspace(0, 2 * np.pi - dtheta, self.n_theta_from).reshape(-1, 1) phi = np.ones(shape) * np.linspace(dphi, np.pi - dphi, self.n_phi_from).reshape(1, -1) self.x_from, self.y_from, self.z_from = self.get_cartesian(theta, phi) self.v_from = self.fun(self.x_from, self.y_from, self.z_from) self.model.create_model_part(self.mp_name_from, self.x_from.flatten(), self.y_from.flatten(), self.z_from.flatten(), np.arange(self.n_from)) parameters = [{'model_part': self.mp_name_from, 'variables': [self.var]}] self.interface_from = data_structure.Interface(parameters, self.model) self.interface_from.set_interface_data(self.v_from.flatten()) # Interface to shape = (self.n_theta_to, self.n_phi_to) dtheta = 2 * np.pi / self.n_theta_to dphi = np.pi / (self.n_phi_to - 1) theta = np.ones(shape) * np.linspace(0, 2 * np.pi - dtheta, self.n_theta_to).reshape(-1, 1) phi = np.ones(shape) * np.linspace(dphi, np.pi - dphi, self.n_phi_to).reshape(1, -1) self.x_to, self.y_to, self.z_to = self.get_cartesian(theta, phi) self.model.create_model_part(self.mp_name_to, self.x_to.flatten(), self.y_to.flatten(), self.z_to.flatten(), np.arange(self.n_to)) parameters = [{'model_part': self.mp_name_to, 'variables': [self.var]}] self.interface_to = data_structure.Interface(parameters, self.model)
def __init__(self, n_from, n_to): self.n_from = n_from self.n_to = n_to self.var = 'pressure' self.mp_name_from = 'wall_from' self.mp_name_to = 'wall_to' self.model = data_structure.Model() # Interface from self.z_from = np.linspace(0, 10, self.n_from) ** .5 self.v_from = self.fun(self.z_from) self.model.create_model_part(self.mp_name_from, np.zeros(self.n_from), np.zeros(self.n_from), self.z_from, np.arange(self.n_from)) parameters = [{'model_part': self.mp_name_from, 'variables': [self.var]}] self.interface_from = data_structure.Interface(parameters, self.model) self.interface_from.set_interface_data(self.v_from) # Interface to self.z_to = np.linspace(0, 10, self.n_to) ** .5 self.model.create_model_part(self.mp_name_to, np.zeros(self.n_to), np.zeros(self.n_to), self.z_to, np.arange(self.n_to)) parameters = [{'model_part': self.mp_name_to, 'variables': [self.var]}] self.interface_to = data_structure.Interface(parameters, self.model)
def initialize(self): super().initialize() # prepare Fluent journal journal = f'v{self.version}.jou' thread_names_str = '' for thread_name in self.thread_ids: thread_names_str += ' "' + thread_name + '"' unsteady = '#f' if self.unsteady: unsteady = '#t' with open(join(self.dir_src, journal)) as infile: with open(join(self.dir_cfd, journal), 'w') as outfile: for line in infile: line = line.replace('|CASE|', join(self.dir_cfd, self.case_file)) line = line.replace('|THREAD_NAMES|', thread_names_str) line = line.replace('|UNSTEADY|', unsteady) line = line.replace('|FLOW_ITERATIONS|', str(self.flow_iterations)) line = line.replace('|DELTA_T|', str(self.delta_t)) line = line.replace('|TIMESTEP_START|', str(self.timestep_start)) outfile.write(line) # prepare Fluent UDF if self.timestep_start == 0: udf = f'v{self.version}.c' with open(join(self.dir_src, udf)) as infile: with open(join(self.dir_cfd, udf), 'w') as outfile: for line in infile: line = line.replace('|MAX_NODES_PER_FACE|', str(self.mnpf)) outfile.write(line) # start Fluent with journal log = join(self.dir_cfd, 'fluent.log') cmd1 = f'fluent -r{self.version_bis} {self.dimensions}ddp ' cmd2 = f'-t{self.cores} -i {journal}' if self.settings['fluent_gui']: cmd = cmd1 + cmd2 else: cmd = cmd1 + '-gu ' + cmd2 + f' >> {log} 2>&1' # TODO: does log work well? # cmd = cmd1 + '-gu ' + cmd2 + f' 2> >(tee -a {log}) 1>> {log}' # TODO: specify what this option does? self.fluent_process = subprocess.Popen(cmd, executable='/bin/bash', shell=True, cwd=self.dir_cfd, env=self.env) # get general simulation info from report.sum self.wait_message('case_info_exported') report = join(self.dir_cfd, 'report.sum') check = 0 with open(report, 'r') as file: for line in file: if check == 2 and 'Time' in line: if 'Steady' in line and self.unsteady: raise ValueError('unsteady in JSON does not match steady Fluent') elif 'Unsteady' in line and not self.unsteady: raise ValueError('steady in JSON does not match unsteady Fluent') break if check == 1 and 'Space' in line: if str(self.dimensions) not in line: if not (self.dimensions == 2 and 'Axisymmetric' in line): raise ValueError(f'dimension in JSON does not match Fluent') check = 2 if 'Model' in line and 'Settings' in line: check = 1 # get surface thread ID's from report.sum and write them to bcs.txt check = 0 info = [] with open(report, 'r') as file: for line in file: if check == 3 and line.islower(): name, id, _ = line.strip().split() if name in self.thread_ids: info.append(' '.join((name, id))) self.thread_ids[name] = id if check == 3 and not line.islower(): break if check == 2: # skip 1 line check = 3 if 'name' in line and check == 1: check = 2 if 'Boundary Conditions' in line: check = 1 with open(join(self.dir_cfd, 'bcs.txt'), 'w') as file: file.write(str(len(info)) + '\n') for line in info: file.write(line + '\n') self.send_message('thread_ids_written_to_file') # import node and face information if no restart if self.timestep_start == 0: self.wait_message('nodes_and_faces_stored') # create Model self.model = data_structure.Model() # create input ModelParts (nodes) for item in (self.settings['interface_input']): mp_name = item['model_part'] # get face thread ID that corresponds to ModelPart for thread_name in self.thread_ids: if thread_name in mp_name: self.model_part_thread_ids[mp_name] = self.thread_ids[thread_name] if mp_name not in self.model_part_thread_ids: raise AttributeError('Could not find thread name corresponding ' + f'to ModelPart {mp_name}') # read in datafile thread_id = self.model_part_thread_ids[mp_name] file_name = join(self.dir_cfd, f'nodes_timestep0_thread{thread_id}.dat') data = np.loadtxt(file_name, skiprows=1) if data.shape[1] != self.dimensions + 1: raise ValueError('Given dimension does not match coordinates') # get node coordinates and ids coords_tmp = np.zeros((data.shape[0], 3)) * 0. coords_tmp[:, :self.dimensions] = data[:, :-1] # add column z if 2D ids_tmp = data[:, -1].astype(int) # array is flattened # sort and remove doubles args = np.unique(ids_tmp, return_index=True)[1].tolist() x0 = coords_tmp[args, 0] y0 = coords_tmp[args, 1] z0 = coords_tmp[args, 2] ids = ids_tmp[args] # create ModelPart self.model.create_model_part(mp_name, x0, y0, z0, ids) # create output ModelParts (faces) for item in (self.settings['interface_output']): mp_name = item['model_part'] # get face thread ID that corresponds to ModelPart for thread_name in self.thread_ids: if thread_name in mp_name: self.model_part_thread_ids[mp_name] = self.thread_ids[thread_name] if mp_name not in self.model_part_thread_ids: raise AttributeError('Could not find thread name corresponding ' + f'to ModelPart {mp_name}') # read in datafile thread_id = self.model_part_thread_ids[mp_name] file_name = join(self.dir_cfd, f'faces_timestep0_thread{thread_id}.dat') data = np.loadtxt(file_name, skiprows=1) if data.shape[1] != self.dimensions + self.mnpf: raise ValueError(f'given dimension does not match coordinates') # get face coordinates and ids coords_tmp = np.zeros((data.shape[0], 3)) * 0. coords_tmp[:, :self.dimensions] = data[:, :-self.mnpf] # add column z if 2D ids_tmp = self.get_unique_face_ids(data[:, -self.mnpf:]) # sort and remove doubles args = np.unique(ids_tmp, return_index=True)[1].tolist() x0 = coords_tmp[args, 0] y0 = coords_tmp[args, 1] z0 = coords_tmp[args, 2] ids = ids_tmp[args] # create ModelPart self.model.create_model_part(mp_name, x0, y0, z0, ids) # create Interfaces self.interface_input = data_structure.Interface(self.settings['interface_input'], self.model) self.interface_output = data_structure.Interface(self.settings['interface_output'], self.model)
def test_call(self): def fun_s(x): return 1. + 2.5 * x def fun_v(x, y, z): theta = np.arctan2(z, y) v_x = 1. + 2.5 * x v_y = v_x * 0.5 * np.cos(theta) v_z = v_x * 0.5 * np.sin(theta) return np.column_stack((v_x, v_y, v_z)) mp_name_from = 'wall_from' mp_name_to = 'wall_to' var_s = 'pressure' var_v = 'displacement' n_in = 10 n_to = n_in * 2 tmp = np.linspace(0, 5, n_in) r_tmp = (1. + 0.2 * np.sin(2 * np.pi / 5 * tmp)) # create model_part_to (3D) x_to = np.zeros(n_to) y_to = np.zeros(n_to) z_to = np.zeros(n_to) i = 0 for k in range(n_in): for p in range(2): x_to[i] = tmp[k] y_to[i] = r_tmp[k] * np.cos(np.radians(2.5)) z_to[i] = r_tmp[k] * ((-1)**p) * np.sin(np.radians(2.5)) i += 1 k += 1 model = data_structure.Model() model.create_model_part(mp_name_to, x_to, y_to, z_to, np.arange(n_to)) # initialize mapper to get model_part_from (2D) mapper = create_instance(self.parameters) mapper.initialize(model, mp_name_to, mp_name_from, forward=False) parameters_from = [{ 'model_part': mp_name_from, 'variables': [var_s, var_v] }] interface_from = data_structure.Interface(parameters_from, model) mp_from = interface_from.get_model_part(mp_name_from) x_from, y_from, z_from = mp_from.x0, mp_from.y0, mp_from.z0 v_s_from = fun_s(x_from).reshape(-1, 1) v_v_from = fun_v(x_from, y_from, z_from) interface_from.set_variable_data(mp_name_from, var_s, v_s_from) interface_from.set_variable_data(mp_name_from, var_v, v_v_from) parameters_to = [{ 'model_part': mp_name_to, 'variables': [var_s, var_v] }] interface_to = data_structure.Interface(parameters_to, model) # check mapped values for 1D variable mapper((interface_from, mp_name_from, var_s), (interface_to, mp_name_to, var_s)) v_s_to_ref = fun_s(x_to).reshape(-1, 1) v_s_to = interface_to.get_variable_data(mp_name_to, var_s) np.testing.assert_allclose(v_s_to, v_s_to_ref, rtol=1e-14) # check mapped values for 3D variable mapper((interface_from, mp_name_from, var_v), (interface_to, mp_name_to, var_v)) v_v_to_ref = fun_v(x_to, y_to, z_to) v_v_to = interface_to.get_variable_data(mp_name_to, var_v) np.testing.assert_allclose(v_v_to, v_v_to_ref, rtol=1e-14) # extra: visualization if self.gui: v_s_from, v_s_to = v_s_from.flatten(), v_s_to.flatten() c_from = cm.jet((v_s_from - v_s_from.min()) / (v_s_from.max() - v_s_from.min())) c_to = cm.jet( (v_s_to - v_s_from.min()) / (v_s_from.max() - v_s_from.min())) fig = plt.figure() ax_s = fig.add_subplot(121, projection='3d') ax_s.set_title('check geometry and scalar mapping') ax_s.scatter(x_from, y_from, z_from, s=50, c=c_from, depthshade=True, marker='s') ax_s.scatter(x_to, y_to, z_to, s=20, c=c_to, depthshade=True) ax_v = fig.add_subplot(122, projection='3d') ax_v.set_title('check vector mapping') ax_v.quiver(x_from, y_from, z_from, v_v_from[:, 0], v_v_from[:, 1], v_v_from[:, 2], pivot='tail', arrow_length_ratio=0.05, normalize=False, length=0.05, colors='r', linewidth=3) ax_v.quiver(x_to, y_to, z_to, v_v_to[:, 0], v_v_to[:, 1], v_v_to[:, 2], pivot='tail', arrow_length_ratio=0.05, normalize=False, length=0.05) for ax in [ax_s, ax_v]: ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('z') plt.get_current_fig_manager().window.showMaximized() plt.xlim(0, 6) plt.ylim(0.7, 1.5) plt.show() plt.close()
def __init__(self, parameters): super().__init__() # set parameters self.settings = parameters['settings'] self.dir_csm = join( os.getcwd(), self.settings['working_directory']) # *** alternative for getcwd? self.env = tools.get_solver_env(__name__, self.dir_csm) self.check_software() path_src = os.path.realpath(os.path.dirname(__file__)) self.logfile = 'abaqus.log' self.cores = self.settings['cores'] # number of CPUs Abaqus has to use self.dimensions = self.settings['dimensions'] self.array_size = self.settings['arraysize'] self.delta_t = self.settings['delta_t'] self.timestep_start = self.settings['timestep_start'] self.surfaceIDs = self.settings['surfaceIDs'] self.n_surfaces = len(self.surfaceIDs) self.mp_mode = self.settings['mp_mode'] self.input_file = self.settings['input_file'] self.save_interval = self.settings.get('save_interval', 1) self.timestep = self.timestep_start self.iteration = None self.model_part_surface_ids = { } # surface IDs corresponding to ModelParts self.subcycling = self.settings.get( 'subcycling', False) # value from parameters or False if not present if self.subcycling: self.min_inc = self.settings['min_inc'] self.initial_inc = self.settings['initial_inc'] self.max_num_inc = self.settings['max_num_inc'] self.max_inc = self.settings['max_inc'] self.ramp = int( self.settings['ramp'] ) # 0 or 1 required to substitute in user-subroutines (FORTRAN) else: self.ramp = 0 self.max_num_inc = 1 # prepare abaqus_v6.env hostname_replace = '' if self.mp_mode == 'MPI' and 'AbaqusHosts.txt' in os.listdir( self.dir_csm): with open(join(self.dir_csm, 'AbaqusHosts.txt'), 'r') as host_file: host_names = host_file.read().split() hostname_replace = str([[hostname, host_names.count(hostname)] for hostname in set(host_names)]) with open(join(path_src, 'abaqus_v6.env'), 'r') as infile: with open(join(self.dir_csm, 'abaqus_v6.env'), 'w') as outfile: for line in infile: line = line.replace('|HOSTNAME|', hostname_replace) if self.mp_mode == 'MPI' \ else (line, '')['|HOSTNAME|' in line] # replace |HOSTNAME| if MPI else remove line line = line.replace('|MP_MODE|', self.mp_mode) line = line.replace('|PID|', str(os.getpid())) if '|' in line: raise ValueError( f'The following line in abaqus_v6.env still contains a \'|\' after ' f'substitution: \n \t{line} \n Probably a parameter was not substituted' ) outfile.write(line) # create start and restart file (each time step > 1 is a restart of the previous converged time step) self.write_start_and_restart_inp(join(self.dir_csm, self.input_file), self.dir_csm + '/CSM_Time0.inp', self.dir_csm + '/CSM_Restart.inp') # prepare Abaqus USRInit.f usr = '******' with open(join(path_src, usr), 'r') as infile: with open(join(self.dir_csm, 'usrInit.f'), 'w') as outfile: for line in infile: line = line.replace('|dimension|', str(self.dimensions)) line = line.replace('|surfaces|', str(self.n_surfaces)) line = line.replace('|cpus|', str(self.cores)) # if PWD is too long then FORTRAN code can not compile so this needs special treatment line = self.replace_fortran(line, '|PWD|', os.path.abspath(os.getcwd())) line = self.replace_fortran( line, '|CSM_dir|', self.settings['working_directory']) if '|' in line: raise ValueError( f'The following line in USRInit.f still contains a \'|\' after substitution: ' f'\n \t{line} \nProbably a parameter was not substituted' ) outfile.write(line) # compile Abaqus USRInit.f in library libusr path_libusr = join(self.dir_csm, 'libusr/') shutil.rmtree(path_libusr, ignore_errors=True) # needed if restart os.mkdir(path_libusr) cmd = f'abaqus make library=usrInit.f directory={path_libusr} >> {self.logfile} 2>&1' self.print_log(f'### Compilation of usrInit.f ###') subprocess.run(cmd, shell=True, cwd=self.dir_csm, executable='/bin/bash', env=self.env) # get load points from usrInit.f at timestep_start self.print_log( f'\n### Get load integration points using usrInit.f ###') if self.timestep_start == 0: cmd1 = f'rm -f CSM_Time{self.timestep_start}Surface*Faces.dat ' \ f'CSM_Time{self.timestep_start}Surface*FacesBis.dat' # the output files will have a name with a higher time step ('job=') than the input file ('input=') cmd2 = f'abaqus job=CSM_Time{self.timestep_start + 1} input=CSM_Time{self.timestep_start} ' \ f'cpus=1 output_precision=full interactive >> {self.logfile} 2>&1' commands = cmd1 + '; ' + cmd2 subprocess.run(commands, shell=True, cwd=self.dir_csm, executable='/bin/bash', env=self.env) else: # restart: this only used for checks cmd1 = f'rm -f CSM_Time{self.timestep_start}Surface*Faces.dat ' \ f'CSM_Time{self.timestep_start}Surface*FacesBis.dat' cmd2 = f'abaqus job=CSM_Time{self.timestep_start + 1} oldjob=CSM_Time{self.timestep_start} ' \ f'input=CSM_Restart cpus=1 output_precision=full interactive >> {self.logfile} 2>&1' commands = cmd1 + '; ' + cmd2 subprocess.run(commands, shell=True, cwd=self.dir_csm, executable='/bin/bash', env=self.env) # prepare GetOutput.cpp get_output = 'GetOutput.cpp' temp_str = '' for j in range(0, self.n_surfaces - 1): temp_str += f'\"{self.surfaceIDs[j]}\", ' temp_str += f'\"{self.surfaceIDs[self.n_surfaces-1]}\"' with open(join(path_src, get_output), 'r') as infile: with open(join(self.dir_csm, get_output), 'w') as outfile: for line in infile: line = line.replace('|surfaces|', str(self.n_surfaces)) line = line.replace('|surfaceIDs|', temp_str) line = line.replace('|dimension|', str(self.dimensions)) if '|' in line: raise ValueError( f'The following line in GetOutput.cpp still contains a \'|\' after ' f'substitution: \n \t{line} \n Probably a parameter was not substituted' ) outfile.write(line) # compile GetOutput.cpp self.print_log(f'\n### Compilation of GetOutput.cpp ###') cmd = f'abaqus make job=GetOutput user=GetOutput.cpp >> {self.logfile} 2>&1' subprocess.run(cmd, shell=True, cwd=self.dir_csm, executable='/bin/bash', env=self.env) # get node positions (not load points) at timestep_start (0 is an argument to GetOutput.exe) self.print_log( f'\n### Get geometrical node positions using GetOutput ###') cmd = f'abaqus ./GetOutput.exe CSM_Time{self.timestep_start + 1} 0 >> {self.logfile} 2>&1' subprocess.run(cmd, shell=True, cwd=self.dir_csm, executable='/bin/bash', env=self.env) for i in range(0, self.n_surfaces): path_output = join( self.dir_csm, f'CSM_Time{self.timestep_start + 1}Surface{i}Output.dat') path_nodes = join( self.dir_csm, f'CSM_Time{self.timestep_start}Surface{i}Nodes.dat') shutil.move(path_output, path_nodes) # create elements file per surface face_file = os.path.join( self.dir_csm, f'CSM_Time{self.timestep_start}Surface{i}Cpu0Faces.dat') output_file = os.path.join( self.dir_csm, f'CSM_Time{self.timestep_start}Surface{i}Elements.dat') self.make_elements(face_file, output_file) # prepare Abaqus USR.f usr = '******' with open(join(path_src, usr), 'r') as infile: with open(join(self.dir_csm, 'usr.f'), 'w') as outfile: for line in infile: line = line.replace('|dimension|', str(self.dimensions)) line = line.replace('|arraySize|', str(self.array_size)) line = line.replace('|surfaces|', str(self.n_surfaces)) line = line.replace('|cpus|', str(self.cores)) line = line.replace('|ramp|', str(self.ramp)) line = line.replace('|deltaT|', str(self.delta_t)) # if PWD is too long then FORTRAN code cannot compile so this needs special treatment line = self.replace_fortran(line, '|PWD|', os.path.abspath(os.getcwd())) line = self.replace_fortran( line, '|CSM_dir|', self.settings['working_directory']) if '|' in line: raise ValueError( f'The following line in USR.f still contains a \'|\' after substitution: ' f'\n \t{line} \n Probably a parameter was not substituted' ) outfile.write(line) # compile Abaqus USR.f self.print_log(f'\n### Compilation of usr.f ###') shutil.rmtree( path_libusr) # remove libusr containing compiled USRInit.f os.mkdir(path_libusr) cmd = f'abaqus make library=usr.f directory={path_libusr} >> {self.logfile} 2>&1' subprocess.run(cmd, shell=True, cwd=self.dir_csm, executable='/bin/bash', env=self.env) # create Model self.model = data_structure.Model() # create input ModelParts (load points) for item in (self.settings['interface_input']): mp_name = item['model_part'] for i, surfaceID in enumerate( self.surfaceIDs ): # identify surfaceID corresponding to ModelPart if surfaceID in mp_name: self.model_part_surface_ids[mp_name] = i break if mp_name not in self.model_part_surface_ids: raise AttributeError( f'Could not identify surfaceID corresponding to ModelPart {mp_name}' ) mp_id = self.model_part_surface_ids[mp_name] # read in elements file elem0_file = join(self.dir_csm, f'CSM_Time0Surface{mp_id}Elements.dat') elements0 = np.loadtxt(elem0_file) n_elem = int( elements0[0, 0] ) # elements first item on line 1 contains number of elements n_lp = int( elements0[0, 1] ) # elements second item on line 1 contains number of total load points if elements0.shape[0] - 1 != int( n_elem ): # elements remainder contains element numbers in interface raise ValueError( f'Number of lines ({elements0.shape[0]}) in {elem0_file} does not correspond with ' f'the number of elements ({n_elem})') if self.timestep_start != 0: # check if elements0 corresponds to timestep_start elem_file = join( self.dir_csm, f'CSM_Time{self.timestep_start}Surface{mp_id}Elements.dat') elements = np.loadtxt(elem_file) if int(elements[0, 0]) != n_elem or int(elements[0, 1]) != n_lp: raise ValueError( f'Number of load points has changed for {mp_name}') # read in faces file for load points faces0_file = join(self.dir_csm, f'CSM_Time0Surface{mp_id}Cpu0Faces.dat') faces0 = np.loadtxt(faces0_file) if faces0.shape[1] != self.dimensions + 2: raise ValueError(f'Given dimension does not match coordinates') # get load point coordinates and ids of load points prev_elem = 0 prev_lp = 0 ids = np.arange(n_lp) coords_tmp = np.zeros( (n_lp, 3)) # z-coordinate mandatory: 0.0 for 2D for i in range(0, n_lp): elem = int(faces0[i, 0]) lp = int(faces0[i, 1]) if elem < prev_elem: raise ValueError( f'Element sequence is wrong ({elem}<{prev_elem})') elif elem == prev_elem and lp != prev_lp + 1: raise ValueError( f'Next line for same element ({elem}) does not contain next load point' ) elif elem > prev_elem and lp != 1: raise ValueError( f'First line for element ({elem}) does not contain its first load point' ) coords_tmp[i, :self.dimensions] = faces0[ i, -self.dimensions:] # extract last 'dimensions' columns prev_elem = elem prev_lp = lp x0 = coords_tmp[:, 0] y0 = coords_tmp[:, 1] z0 = coords_tmp[:, 2] # create ModelPart self.model.create_model_part(mp_name, x0, y0, z0, ids) # create output ModelParts (geometrical nodes) for item in (self.settings['interface_output']): mp_name = item['model_part'] for i, surfaceID in enumerate( self.surfaceIDs ): # identify surfaceID corresponding to ModelPart if surfaceID in mp_name: self.model_part_surface_ids[mp_name] = i break if mp_name not in self.model_part_surface_ids: raise AttributeError( f'Could not identify surfaceID corresponding to ModelPart {mp_name}' ) mp_id = self.model_part_surface_ids[mp_name] # read in nodes file nodes0_file = join(self.dir_csm, f'CSM_Time0Surface{mp_id}Nodes.dat') nodes0 = np.loadtxt(nodes0_file, skiprows=1) # first line is a header n_nodes0 = nodes0.shape[0] if nodes0.shape[1] != self.dimensions: raise ValueError(f'Given dimension does not match coordinates') if self.timestep_start != 0: # check if nodes0 corresponds to timestep_start nodes_file = join( self.dir_csm, f'CSM_Time{self.timestep_start}Surface{mp_id}Nodes.dat') nodes = np.loadtxt(nodes_file, skiprows=1) # first line is a header n_nodes = nodes.shape[0] if n_nodes != n_nodes0: raise ValueError( f'Number of interface nodes has changed for {mp_name}') # get geometrical node coordinates ids = np.arange( n_nodes0 ) # Abaqus does not use node ids but maintains the output order coords_tmp = np.zeros( (n_nodes0, 3)) # z-coordinate mandatory: 0.0 for 2D coords_tmp[:, :self.dimensions] = nodes0 x0 = coords_tmp[:, 0] y0 = coords_tmp[:, 1] z0 = coords_tmp[:, 2] # create ModelPart self.model.create_model_part(mp_name, x0, y0, z0, ids) # check whether the input ModelParts and output ModelParts have proper overlap for surfaceID in self.surfaceIDs: for item in self.settings['interface_input']: mp_name = item['model_part'] if surfaceID in mp_name: mp_in = self.model.get_model_part(mp_name) break for item in self.settings['interface_output']: mp_name = item['model_part'] if surfaceID in mp_name: mp_out = self.model.get_model_part(mp_name) break tools.check_bounding_box(mp_in, mp_out) # create Interfaces self.interface_input = data_structure.Interface( self.settings['interface_input'], self.model) self.interface_output = data_structure.Interface( self.settings['interface_output'], self.model) # time self.init_time = self.init_time self.run_time = 0.0 # debug self.debug = False # set on True to save copy of input and output files in every iteration