def check_exists(key, user_input, else_quit=False): """Checks if the variable was defined by user, i.e., if it's in the global variables""" if key not in user_input and else_quit is True: exit_program("variable '{}' not defined".format(key)) else: return user_input[key]
def get_sim_specific_input(user_input): """returns additional simulation-specific required and optional user input variables""" simulation_type = user_input['simulation_type'] required_user_input = {} optional_user_input = {} if simulation_type == SimType.cyl_rol_bearing.value: required_user_input = {'length_cb1': VarType.real_number, 'e_cb3': VarType.real_number, 'ny_cb3': VarType.real_number, 'diameter_cb3': VarType.real_number, 'type_profile_cb1': VarType.string, 'type_profile_cb2': VarType.string, 'type_profile_cb3': VarType.string, 'number_rollers': VarType.integer, 'diameter_cb2': VarType.real_number} optional_user_input = {'radial_clearance': VarType.real_number, 'res_pol': VarType.integer, 'rot_velocity2': VarType.real_number, 'rms_roughness_cb3': VarType.real_number} elif simulation_type == SimType.deep_gro_ball_bearing.value: pass elif simulation_type == SimType.cyl_rol_thrust_bearing.value: required_user_input = {'length_cb1': VarType.real_number, 'e_cb3': VarType.real_number, 'ny_cb3': VarType.real_number, 'mean_diameter': VarType.real_number, 'type_profile_cb1': VarType.string, 'number_rollers': VarType.integer} optional_user_input = {'rot_velocity2': VarType.real_number} elif simulation_type == SimType.ball_on_disk.value: required_user_input = {'number_balls': VarType.integer, 'sliding_diameter': VarType.real_number, 'diameter_cb2': VarType.real_number, 'rot_velocity2': VarType.real_number} elif simulation_type == SimType.pin_on_disk.value: check_vars({'diameter_cb1': user_input['diameter_cb1'], 'type_profile_cb1': user_input['type_profile_cb1']}) if user_input[ 'type_profile_cb1'] is Profiles.Circle.value and check_exists( 'profile_radius_cb1') is True and \ user_input['diameter_cb1'] != 2 * user_input[ 'profile_radius_cb1']: required_user_input.update({'length_cb1': VarType.real_number}) required_user_input.update({'number_pins': VarType.integer, 'sliding_diameter': VarType.real_number}) elif simulation_type == SimType.four_ball.value: required_user_input = {'diameter_cb2': VarType.real_number} elif simulation_type == SimType.ball_on_three_plates.value: optional_user_input = {'plate_angle': VarType.real_number} elif simulation_type == SimType.ring_on_ring.value: required_user_input = {'length_cb1': VarType.real_number, 'type_profile_cb1': VarType.string, 'type_profile_cb2': VarType.string, 'number_planets': VarType.integer, 'rot_velocity2': VarType.real_number} else: exit_program( "'simulation_type' option '{}' not defined".format(simulation_type)) return required_user_input, optional_user_input
def check_all_required(user_input, required_inputs): """checks if all calculation-specific (mandatory) variables are defined""" for key, value in required_inputs.items(): if key not in user_input: exit_program( "variable '{}' not defined in input file".format(key)) required_inputs.update(get_sim_specific_input(user_input)[0]) check_vars(user_input)
def validate_file_path(path_variable): """Validates file path""" if os.path.isfile(path_variable) is False: exit_program("cannot find file '" + eval(path_variable) + "'" "\nplease specify a valid file path (including file " "extension) in variable '" + path_variable + "'" + "\nthe file path needs to be defined relative to " "'the input file'")
def check_base_required(user_input): """checks if all basic (mandatory) variables are defined""" required_inputs = copy.deepcopy(VarDicts.required_user_input.value) for key, value in required_inputs.items(): if key not in user_input: exit_program( "variable '{}' not defined in input file".format(key)) check_vars(user_input) return required_inputs
def check_bool(key, value, isbool=True): """Checks if the variable is boolean""" if isinstance(value, bool) is not True and isbool is True: exit_program( "variable '{}' with value '{}' should be of type boolean".format( key, value)) elif isinstance(value, bool) is True and isbool is False: exit_program( "variable '{}' with value '{}' (boolean) should not " "be of type boolean".format(key, value))
def check_odd_even(key, value, should_be_odd_or_even=OddEvenCheck.Undefined): """Checks if the variable is odd or even""" if should_be_odd_or_even.value == OddEvenCheck.Odd.value or \ should_be_odd_or_even.value == OddEvenCheck.Even.value: if value % 2 == OddEvenCheck.Odd.value and \ should_be_odd_or_even.value != OddEvenCheck.Odd.value: exit_program("variable '" + value + "' should be an even number") elif value % 2 == OddEvenCheck.Even.value and \ should_be_odd_or_even.value != OddEvenCheck.Even.value: exit_program("variable '{}' should be an odd number".format(key))
def check_sign(key, value, sign_var): """checks if the sign of a numeric variable is as expected""" if (isinstance(value, int) and not isinstance(value, bool)) is False \ and isinstance(value, float) is False: exit_program( "variable '{}' with value '{}' should not be of type {}" .format(key, value, type(value))) if np.sign(value) != sign_var: exit_program("variable '{}' with value '{}' should be {} 0" .format(key, value, {1.0: '<', -1.0: '>'}[np.sign(value)]))
def check_alpha(key, value): """Checks if the string has only alphanumeric characters, except for '_' and '-' """ try: if value[0].isalnum() is False or value[-1].isalnum() is False: if value[0] == '-' or value[-1] == '-': exit_program( "variable '" + key + "' should not start or end with a hyphen '-' ") else: exit_program( "variable '{}' with value '{}' should only contain " "alphanumeric characters and hyphens '-'" .format(key, value)) except TypeError: exit_program( "variable '{}' with value '{}' should be of type string. strings " "need to be enclosed in quotes.". format(key, value)) for character in value: if character.isalnum() is False and character != '-': exit_program( "variable '{}' with value '{}' should only contain " "alphanumeric characters and hyphens '-'". format(key, value))
def setup_ball_on_disk(ui): """Not currently implemented""" exit_program("simulation_type '4' currently not implemented completely.") """ ball = Ball('pin', ui['e_cb1'], ui['ny_cb1'], ui['diameter_cb1'], rms_rough=in_d('rms_roughness_cb1', ui)) ball.make_profile(ui['res_x'], ui['res_y'], ui['global_force'] / ui['number_balls']) disk = Disk('disk', ui['e_cb2'], ui['ny_cb2'], diameter=ui['diameter_cb2'], rot_vel='rot_velocity2', rms_rough=in_d('rms_roughness_cb2', ui)) disk.make_slave_to(ball) tribo_system = BallOnDisk(ui['number_balls'], ui['sliding_diameter'], ball, disk, ui['global_force'], in_d('tribo_system_name', ui)) return ball, disk, tribo_system """ pass
def import_user_input(in_file): """read file input file line by line and try to extract user input. return dictionary with user input""" user_input = {} invalid_input = {} try: with open(in_file) as user_input_file: for line in user_input_file: # if line not empty if line.strip(): # if line is comment, ignore if line.strip()[0] == '#': continue else: # remove trailing comments and whitespace value_pair = line.split('#')[0].strip(' ') # split at '=' and remove whitespace key = value_pair.split('=')[0].strip(' ') value = value_pair.split('=')[1].strip('\n').strip(' ') # value = value.strip("'").strip('"').strip("'") user_input.update({key: value}) if value.startswith("'") or value.startswith('"'): value = value[1:-1] if re.search('[a-zA-Z]', value): user_input.update({key: value}) elif value == 'True': user_input.update({key: True}) if key == 'auto_print': user_input.update({'AUTO_PRINT': 'True'}) elif value == 'False': user_input.update({key: False}) if key == 'auto_print': user_input.update({'AUTO_PRINT': 'False'}) else: try: user_input.update({key: float(value)}) if int(user_input[key]) == user_input[key]: user_input[key] = int(value) except ValueError: invalid_input.update({key: value}) return user_input, invalid_input except FileNotFoundError: exit_program("can't find file {}".format(in_file))
def calc_kinematics(self, rot_vel1, rot_vel2, ui=None, res_dir=None): """Calculate tribosystem kinematics based on rotational velocities of sun and planet(s)""" print_it("calculating kinematics") self.sun.rot_vel = rot_vel1 self.planet.rot_vel = rot_vel2 self.sun.omega = self.sun.rot_vel / 60 self.planet.omega = self.planet.rot_vel / 60 self.sun.vel = self.sun.diameter * math.pi * self.sun.omega self.planet.vel = self.planet.diameter * math.pi * self.planet.omega self.slip = (self.sun.vel - self.planet.vel) / self.sun.vel self.rel_vel = np.ones(self.sun.res_x) * ( self.sun.vel - self.planet.vel) self.sun.footpr_vel = \ 2 * math.pi * self.sun.diameter / 2 * self.sun.omega self.planet.footpr_vel = \ 2 * math.pi * self.planet.diameter / 2 * self.planet.omega try: self.sun.overroll_t_incr = self.sun.delta_y / self.sun.footpr_vel self.planet.overroll_t_incr = \ self.planet.delta_y / self.planet.footpr_vel except ZeroDivisionError: exit_program( 'rotational velocities of sun and planet must not be 0') self.press_zone_len = (self.sun.press > 0).sum(1) * self.sun.delta_y self.sun.overroll_t = np.divide(self.press_zone_len, self.sun.footpr_vel) self.planet.overroll_t = np.divide(self.press_zone_len, self.planet.footpr_vel) self.sun.no_overroll_t = np.divide( (2 * math.pi * (self.sun.diameter / 2) - self.num_planets * self.press_zone_len) / self.num_planets, self.sun.footpr_vel) self.planet.no_overroll_t = np.divide( (2 * math.pi * (self.planet.diameter / 2) - self.press_zone_len), self.planet.footpr_vel)
def validate_contact_body(user_input): """Checks if the user's contact body definition is consistent""" bodies_to_validate = {SimType.cyl_rol_bearing.value: ['cb1', 'cb2', 'cb3'], SimType.cyl_rol_thrust_bearing.value: ['cb1'], SimType.pin_on_disk.value: ['cb1'], SimType.ring_on_ring.value: ['cb1', 'cb2']} for contact_body in bodies_to_validate.get(user_input['simulation_type'], []): type_profile = "type_profile_{}".format(contact_body) if user_input[type_profile] == Profiles.NoProfile.value: pass elif user_input[type_profile] == Profiles.ISO.value: check_vars({"length_" + contact_body: user_input[ "length_" + contact_body]}) elif user_input[type_profile] == Profiles.Circle.value: check_vars( {"length_" + contact_body: user_input["length_" + contact_body], "profile_radius_" + contact_body: user_input[ "profile_radius_" + contact_body]}) elif user_input[type_profile] == Profiles.File.value: validate_file_path(user_input["path_profile_" + contact_body]) else: exit_program("'type_profile' option '{}' is undefined".format( user_input[type_profile]))
def check_python_environment(): """Check if all required python environments are installed before actual calculation is started""" print_it('python: {}'.format(sys.version.replace('\n', ' ')), PrintOpts.lvl1.value) try: import matplotlib as mpl print_it('matplotlib: {}'.format(mpl.__version__), PrintOpts.lvl1.value) except ImportError: print_import_error('matplotlib', PrintOpts.lvl1.value) exit_program('module not found') try: import numexpr print_it('numexpr: {}'.format(numexpr.__version__), PrintOpts.lvl1.value) except ImportError: print_import_error('numexpr', PrintOpts.lvl1.value) exit_program('module not found') try: import numpy print_it('numpy: {}'.format(numpy.__version__), PrintOpts.lvl1.value) except ImportError: print_import_error('numpy', PrintOpts.lvl1.value) exit_program('module not found') try: import scipy print_it('scipy: {}'.format(scipy.__version__), PrintOpts.lvl1.value) except ImportError: print_import_error('scipy', PrintOpts.lvl1.value) exit_program('module not found') try: import jinja2 print_it('jinja2: {}'.format(jinja2.__version__), PrintOpts.lvl1.value) except ImportError: print_import_error('jinja2', PrintOpts.lvl1.value) print_it('this will cause an error if auto_report is True')
def setup_deep_gro_ball_bearing(ui): """Not currently implemented""" exit_program("simulation_type '2' currently undefined")
def check_int(key, value): """Checks if the variable is int""" if isinstance(value, int) is not True: exit_program( "variable '{}' with value '{}' should be of type int".format(key, value))
def create_2d_profile2(diameter, length, type_profile, x_axis, res_x, path_profile=None, circle_radius=None): """creates a 2d profile along x-axis (body length) based on user input""" x_profile = np.zeros(res_x) file_x_axis = None file_x_profile = None if type_profile == Profiles.ISO.value: # problem is that ISO profile is not defined at the end points of the # roller, hence the profile at the end points is calculated based on a # slightly shorter x_axis here. x_axis_slightly_shorter = copy.deepcopy(x_axis) x_axis_slightly_shorter[[0, -1]] = np.multiply([x_axis[0], x_axis[-1]], 0.99999999) x_profile = -0.00035 * diameter * np.log(1 / (1 - np.power( ((2 * x_axis_slightly_shorter) / length), 2))) # x_profile[0] = x_profile[1] * 1.5 # x_profile[-1] = x_profile[-2] * 1.5 elif type_profile == Profiles.Circle.value: x_profile = np.array( abs(circle_radius) - np.sqrt(np.power(circle_radius, 2) - np.power(x_axis, 2))) sign_circle_radius = np.sign(circle_radius) x_profile = -np.multiply(x_profile, sign_circle_radius) elif type_profile == Profiles.File.value: content_text_file = [] try: content_text_file = np.loadtxt(path_profile, delimiter="\t") except ValueError: exit_program( "\nexpecting the file '{}' to be a two column tab-delimited " ".txt-file" "\nwith first column corresponding to length of body and " "second column corresponding to " "profile data".format(path_profile)) # get original x-axis and profile data from file and normalize it x_axis = np.array( content_text_file[:, 0]) - max(np.array(content_text_file[:, 0])) / 2 file_x_axis = x_axis x_profile = np.array(content_text_file[:, 1]) - min( content_text_file[:, 1]) file_x_profile = (x_profile - max(x_profile)) / 1000 x_profile = x_profile - max(x_profile) step = max(1, round(len(content_text_file) / 15000)) # deactivate filter warnings for polynomial fits warnings.simplefilter('ignore', np.RankWarning) try: print_it("fitting measured profile with 3rd grade polynomial", PrintOpts.lvl1.value) start_point_left, start_point_right = fit_profile( x_axis, x_profile, step, 3) x_axis_new = np.array( content_text_file[start_point_left:-start_point_right + 1, 0]) x_profile_new = np.array( x_profile[start_point_left:-start_point_right + 1]) x_axis_new = x_axis_new - min(x_axis_new) x_axis_new -= max(x_axis_new) / 2 print_it("3rd grade polynomial fit successful", PrintOpts.lvl1.value) except ValueError: print_it("3rd grade polynomial fit failed", PrintOpts.lvl1.value) print_it("fitting measured profile with 2nd grade polynomial", PrintOpts.lvl1.value) start_point_left, start_point_right = fit_profile( x_axis, x_profile, step, 2) x_axis_new = np.array( content_text_file[start_point_left:-start_point_right + 1, 0]) x_profile_new = np.array( x_profile[start_point_left:-start_point_right + 1]) x_axis_new = x_axis_new - min(x_axis_new) x_axis_new -= max(x_axis_new) / 2 print_it("2nd grade polynomial fit successful", PrintOpts.lvl1.value) warnings.simplefilter('always', np.RankWarning) # generate profile representation and corresponding x-axis based on # polynomial fit short_x_axis = np.linspace(x_axis_new[0], x_axis_new[-1], res_x) z = np.polyfit(x_axis_new, x_profile_new, find_poly(x_axis_new, x_profile_new)) p = np.poly1d(z) interpolated_x_profile = p(short_x_axis) x_axis = short_x_axis # normalize profile and convert units to millimeter x_profile = (interpolated_x_profile - min(interpolated_x_profile)) x_profile = (x_profile - max(x_profile)) / 1000 delta_x = abs(x_axis[0] - x_axis[1]) return x_axis, x_profile, file_x_axis, file_x_profile, delta_x
def p3can(in_file='USER_INPUT.py', out_dir=None): """ Start a P3CAN simulation run. Parameters ---------- in_file: str, optional The file path of the P3CAN input file. The default value is `USER_INPUT.py`. You can generate `in_file` templates for different tribological systems using the `generate_input_file` function. out_dir: str The directory in which output files will be stored. A folder named `results` will be created in `out_dir`. The `results` folder then contains a simulation-specific folder containing all outputs. Default is the current working directory. Returns ------- sim.res_dir: str The path to the simulation-specific results folder. The path is: `out_dir`/results/<unique simulation name> The unique simulation name is automatically generated by P3CAN. """ if not out_dir: out_dir = os.getcwd() # set-up a simulation sim = Sim(in_file, out_dir) sim.mk_uniq_parameter_id() sim.infl_db_file_hand = make_infl_mat_db(os.path.dirname(sim.res_dir)) tribo_system = None # generate a tribosystem based on user input print_it('initialising contact bodies') if sim.simulation_type == SimType.cyl_rol_bearing.value: roller, ring1, ring2, tribo_system = setup_cyl_rol_bearing(sim.ui) elif sim.simulation_type == SimType.deep_gro_ball_bearing.value: setup_deep_gro_ball_bearing(sim.ui) elif sim.simulation_type == SimType.cyl_rol_thrust_bearing.value: roller, ring1, ring2, tribo_system = setup_cyl_rol_thrust_bearing( sim.ui) elif sim.simulation_type == SimType.ball_on_disk.value: ball, disk, tribo_system = setup_ball_on_disk(sim.ui) elif sim.simulation_type == SimType.pin_on_disk.value: pin, disk, tribo_system = setup_pin_on_disk(sim.ui) elif sim.simulation_type == SimType.four_ball.value: rot_ball, stat_ball, tribo_system = setup_four_ball(sim.ui) elif sim.simulation_type == SimType.ball_on_three_plates.value: ball, plate, tribo_system = setup_ball_on_three_plates(sim.ui) elif sim.simulation_type == SimType.ring_on_ring.value: sun, planet, tribo_system = setup_ring_on_ring(sim.ui) else: exit_program("'simulation_type' option '{}'not defined".format( sim.simulation_type)) # simulate tribosystem tribo_system.calc_load_distribution(sim.ui, sim.res_dir) tribo_system.calc_contact_pressure(sim.ui, sim.res_dir) tribo_system.calc_kinematics(in_d('rot_velocity1', sim.ui, 0), in_d('rot_velocity2', sim.ui, 0), sim.ui, sim.res_dir) tribo_system.calc_pv(sim.ui, sim.res_dir) tribo_system.calc_e_akin(sim.ui, sim.res_dir) # generate output plots and pdf report if sim.auto_plot is True: tribo_system.plot_it(sim.ui, sim.res_dir) if sim.auto_report is True: generate_latex_output(sim, tribo_system, sim.ui, sim.res_dir) # manage the influence matrix cache manage_influ_mat_cache(sim.res_dir) # finish simulation sim.finished() return sim.res_dir