Source code for basicfem

""" basicfem.py is the main script to execute the Basicfem solver. """

import sys
import os
import numpy as np
import matplotlib.pyplot as plt
from abc import ABCMeta, abstractclassmethod
from lib.solvers import *
from lib.output_utility import *
from lib.solver_input import *

[docs]def main(): """ Main function to read in command line input, processing directories and run respective solvers. The script takes two argument -- an input directory name and an output directory name. The input directory should locate in the local directory and needs to contain necessary txt files for basicfem solvers. It can also be an xlsx file that contains all the required input. The output directory will be generated if not exists, or being overwritten. """ if len(sys.argv) != 3: print("usage: python basicfem.py <input_directory> <output_directory>") print(" <input_directory> can also be a single xlsx file", "with all required input.") sys.exit(1) input_dir = sys.argv[1] input_dir = input_dir.lstrip('./') if not os.path.exists(input_dir): print("Input directory or file does not exist.") sys.exit(1) if os.path.isfile(input_dir): param = read_param(input_dir) else: param = read_param('./' +sys.argv[1] + '/param.txt') cwd = os.getcwd() output_path = cwd + '/' + sys.argv[2] if not os.path.exists(output_path): os.mkdir(output_path) if param is None: param = {} problem_type, scale_factor = set_param_guide() else: problem_type = param['problem_type'] scale_factor = float(param['deformation_scale_factor']) if problem_type.lower() == "truss": input_ = TrussInput2D(input_dir) result = TrussSolver2D(input_) save_data(result.stress,'element_stresses.txt', dir_name=sys.argv[2]) save_data(result.displacements, 'nodal_displacements.txt', dir_name=sys.argv[2]) plot_deformed_shape_1D(result, scale_factor, output_path) elif problem_type.lower() == "frame": input_ = TrussInput2D(input_dir) result = FrameSolver2D(input_) save_data(result.displacements, 'nodal_displacements.txt', dir_name=sys.argv[2]) plot_deformed_shape_1D(result, scale_factor, output_path) elif problem_type.lower() == '2d': input_ = TriangularElementInput(input_dir) result = TriangularElementSolver(input_) plot_deformation_shape_2D(input_.nodal_data, input_.element_data, result.displacements, scale_factor, output_path) if 'contour_over_deformed_mesh' in param: plot_on_deformed_flag = str(param['contour_over_deformed_mesh']) \ .lower() == 'true' plot_contour_batch(result, scale_factor, output_path, plot_on_deformed=plot_on_deformed_flag) else: plot_contour_batch(result, scale_factor, output_path) save_data(result.displacements, 'nodal_displacements', dir_name=sys.argv[2]) save_data(result.stress, 'element_stresses', dir_name=sys.argv[2]) print("Solver process completed.")
[docs]def read_param(param_filename): """ Read the param file to set the solver related parameters. The param file will either be an param.txt file inside the input directory, or the Param page inside the input xlsx file. Parameters ---------- param_filename : str The xlsx file name, or the processed path to the param.txt file. Returns ------- dict The dictionary contains solver related paramters. """ if not os.path.isfile(param_filename): return None if param_filename.endswith('.xls') or param_filename.endswith('.xlsx'): from pandas import read_excel arr = read_excel(param_filename, sheet_name = 'Param').values param = {arr[i,0] : arr[i,1] for i in range(len(arr))} else: f = open(param_filename, 'r') param = {} for line in f: line = line.split('#', 1)[0] line = line.rstrip() if line != '': k, v = line.strip().split('=') param[k.strip()] = v.strip() f.close() return param
[docs]def set_param_guide(): """ Command line prompt to guide the users setting up parameters. In the case when param file does not exist, this function will guide the users to provide the necessary paramters for solver. Note that this guide will keep most of the parameters default, only set those that is needed to be assigned for solver to run. Returns ------- tuple Parameters necessary for the solver. """ print("param file/page does not exists. Please specify:") problem_type = input("Problem type? (`truss`, `frame`, or `2d`): ") while problem_type not in ['truss','frame','2d']: print('Invalid problem type.') problem_type = input("Problem type? (`truss`, `frame`, or `2d`): ") scale_factor = input("Deformation scale factor? (default = 1) ") try: scale_factor = float(scale_factor) except: scale_factor = 1.0 print('No valid input. Deformation scale factor = 1 will be used.') return problem_type, scale_factor
[docs]def plot_contour_batch(fem_result, scale_factor, output_path, plot_on_deformed=True): """ Generate all the contour plot available. Only used for 2d elements. Parameters ---------- fem_result: BaseSolver A Solver object contains the analysis result. scale_factor : float The deformation scale factor assigned in the param. output_path : str The path to the output directory assigned by the user. plot_on_deformed : bool Flag that determines if the contour is plotted on the deformed structures. Default is True. """ if plot_on_deformed: plot_contour(fem_result, "stress", 'xx', 'sigma_xx', scale_factor, output_path) plot_contour(fem_result, "stress", 'yy', 'sigma_yy', scale_factor, output_path) plot_contour(fem_result, "stress", 'xy', 'sigma_xy', scale_factor, output_path) plot_contour(fem_result, "strain", 'xx', 'strain_xx', scale_factor, output_path) plot_contour(fem_result, "strain", 'yy', 'strain_yy', scale_factor, output_path) plot_contour(fem_result, "strain", 'xy', 'strain_xy', scale_factor, output_path) else: plot_contour(fem_result, "stress", 'xx', 'sigma_xx', scale_factor, output_path, False) plot_contour(fem_result, "stress", 'yy', 'sigma_yy', scale_factor, output_path, False) plot_contour(fem_result, "stress", 'xy', 'sigma_xy', scale_factor, output_path, False) plot_contour(fem_result, "strain", 'xx', 'strain_xx', scale_factor, output_path, False) plot_contour(fem_result, "strain", 'yy', 'strain_yy', scale_factor, output_path, False) plot_contour(fem_result, "strain", 'xy', 'strain_xy', scale_factor, output_path, False)
if __name__ == "__main__": main()