def main(argv=sys.argv, log_output=True, return_output_fname=False, return_results_dict=False, field=None, lspr_values=None): """ Run a PyGBe problem, write outputs to STDOUT and to log file in problem directory Arguments ---------- log_output : Bool, default True. If False, output is written only to STDOUT and not to a log file. return_output_fname: Bool, default False. If True, function main() returns the name of the output log file. This is used for the regression tests. return_results_dict: Bool, default False. If True, function main() returns the results of the run packed in a dictionary. Used in testing and programmatic use of PyGBe field : Dictionary, defaults to None. If passed, this dictionary will supercede any config file found, useful in programmatically stepping through slight changes in a problem. lspr_values : list, defaults to None If passed, provides values for `electric_field` and `wavelength`, useful to programmatically step through varying wavelengths Returns -------- output_fname : str, if kwarg is True. The name of the log file containing problem output """ args = read_inputs(argv[1:]) configFile, paramfile = find_config_files(args) full_path = os.environ.get('PYGBE_PROBLEM_FOLDER') #check if a custom geometry location has been specified #if it has, add an ENV_VAR to handle it if args.geometry: geo_path = os.path.abspath(args.geometry) if os.path.isdir(geo_path): os.environ['PYGBE_GEOMETRY'] = geo_path else: sys.exit('Invalid geometry prefix provided (Folder not found)') else: geo_path = os.path.join(full_path, 'geometry') #try to expand ~ if present in output path args.output = os.path.expanduser(args.output) #if output path is absolute, use that, otherwise prepend #problem path if not os.path.isdir(args.output): output_dir = os.path.join(full_path, args.output) else: output_dir = args.output # create output directory if it doesn't already exist try: os.makedirs(output_dir) except OSError: pass results_dict = {} timestamp = time.localtime() outputfname = '{:%Y-%m-%d-%H%M%S}-output.log'.format(datetime.now()) results_dict['output_file'] = outputfname if log_output: restore_stdout = sys.stdout sys.stdout = Logger(os.path.join(output_dir, outputfname)) # Time stamp print('Run started on:') print('\tDate: {}/{}/{}'.format(timestamp.tm_year, timestamp.tm_mon, timestamp.tm_mday)) print('\tTime: {}:{}:{}'.format(timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec)) print('\tPyGBe version: {}'.format(pygbe.__version__)) TIC = time.time() print('Config file: {}'.format(configFile)) print('Parameter file: {}'.format(paramfile)) print('Geometry folder: {}'.format(geo_path)) print('Running in: {}'.format(full_path)) results_dict['config_file'] = configFile results_dict['param_file'] = paramfile results_dict['geo_file'] = geo_path results_dict['full_path'] = full_path ### Read parameters param = Parameters() precision = read_parameters(param, paramfile) param.Nm = (param.P + 1) * (param.P + 2) * ( param.P + 3) // 6 # Number of terms in Taylor expansion param.BlocksPerTwig = int(numpy.ceil(param.NCRIT / float(param.BSZ)) ) # CUDA blocks that fit per twig HAS_GPU = check_for_nvcc() if param.GPU == 1 and not HAS_GPU: print('\n\n\n\n') print('{:-^{}}'.format('No GPU DETECTED', 60)) print("Your param file has `GPU = 1` but CUDA was not detected.\n" "Continuing using CPU. If you do not want this, use Ctrl-C\n" "to stop the program and check that your CUDA installation\n" "is on your $PATH") print('{:-^{}}'.format('No GPU DETECTED', 60)) print('\n\n\n\n') param.GPU = 0 ### Generate array of fields if field: field_array = initialize_field(configFile, param, field) else: field_array = initialize_field(configFile, param) ### Generate array of surfaces and read in elements surf_array = initialize_surface(field_array, configFile, param) ### Read electric field and its wavelength. if lspr_values: electric_field, wavelength = lspr_values else: electric_field, wavelength = read_electric_field(param, configFile) ### Fill surface class time_sort = 0. for i in range(len(surf_array)): time_sort += surf_array[i].fill_surface(param) ### Output setup summary param.N = 0 param.Neq = 0 for s in surf_array: N_aux = len(s.triangle) param.N += N_aux if s.surf_type in ['dirichlet_surface', 'neumann_surface', 'asc_surface']: param.Neq += N_aux else: param.Neq += 2 * N_aux print('\nTotal elements : {}'.format(param.N)) print('Total equations: {}'.format(param.Neq)) results_dict['total_elements'] = param.N results_dict['N_equation'] = param.Neq results_dict = print_summary(surf_array, field_array, param, results_dict) ### Precomputation ind0 = IndexConstant() computeIndices(param.P, ind0) precomputeTerms(param.P, ind0) ### Load CUDA code if param.GPU == 1: kernel = kernels(param.BSZ, param.Nm, param.K_fine, param.P, precision) else: kernel = 1 ### Generate interaction list print('Generate interaction list') tic = time.time() generateList(surf_array, field_array, param) toc = time.time() list_time = toc - tic ### Transfer data to GPU print('Transfer data to GPU') tic = time.time() if param.GPU == 1: dataTransfer(surf_array, field_array, ind0, param, kernel) toc = time.time() transfer_time = toc - tic timing = Timing() ### Generate RHS print('Generate RHS') tic = time.time() if param.GPU == 0: F = generateRHS(field_array, surf_array, param, kernel, timing, ind0, electric_field) elif param.GPU == 1: F = generateRHS_gpu(field_array, surf_array, param, kernel, timing, ind0, electric_field) toc = time.time() rhs_time = toc - tic setup_time = toc - TIC print('List time : {}s'.format(list_time)) print('Data transfer time : {}s'.format(transfer_time)) print('RHS generation time: {}s'.format(rhs_time)) print('-'*30) print('Total setup time : {}s'.format(setup_time)) # Check if there is a complex dielectric if any([numpy.iscomplexobj(f.E) for f in field_array]): complex_diel = True else: complex_diel = False ### Solve tic = time.time() print('Solve') # Initializing phi dtype according to the problem we are solving. if complex_diel: phi = numpy.zeros(param.Neq, dtype=numpy.complex) else: raise ValueError('Dielectric should be complex for LSPR problems') phi, iteration = gmres_mgs(surf_array, field_array, phi, F, param, ind0, timing, kernel) toc = time.time() results_dict['iterations'] = iteration solve_time = toc - tic print('Solve time : {}s'.format(solve_time)) phifname = '{:%Y-%m-%d-%H%M%S}-phi_{}.txt'.format(datetime.now(), wavelength) results_dict['solve_time'] = solve_time numpy.savetxt(os.path.join(output_dir, phifname), phi) # Put result phi in corresponding surfaces s_start = 0 for surf in surf_array: s_start = surf.fill_phi(phi, s_start) #Calculate extinction cross section for lspr problems if abs(electric_field) > 1e-12: ###Calculating the dipole moment dipole_moment(surf_array, electric_field) print('\nCalculate extinction cross section (Cext)') tic = time.time() Cext, surf_Cext = extinction_cross_section(surf_array, numpy.array([1,0,0]), numpy.array([0,0,1]), wavelength, electric_field) toc = time.time() print('Time Cext: {}s'.format(toc - tic)) print('\nWavelength: {:.2f} nm'.format(wavelength/10)) print('Incoming Electric Field: {:.4f} e/(Ang^2 eps_0)'.format(electric_field)) print('\nCext per surface') for i in range(len(Cext)): print('Surface {}: {} nm^2'.format(surf_Cext[i], Cext[i])) results_dict['time_Cext'] = toc - tic results_dict['surf_Cext'] = surf_Cext results_dict['wavelength'] = wavelength results_dict['E_field'] = electric_field results_dict['Cext_list'] = Cext results_dict['Cext_0'] = Cext[0] #We do convergence analysis in the main sphere else: raise ValueError('electric_field should not be zero to calculate' 'the extinction cross section') results_dict['total_time'] = (toc - TIC) results_dict['version'] = pygbe.__version__ output_pickle = outputfname.split('-') output_pickle.pop(-1) output_pickle.append('resultspickle_'+str(wavelength)) output_pickle = '-'.join(output_pickle) with open(os.path.join(output_dir, output_pickle), 'wb') as f: pickle.dump(results_dict, f, 2) try: with open(os.path.join(output_dir, output_pickle), 'rb') as f: pickle.load(f) except EOFError: print('Error writing the pickle file, the results will be unreadable') pass #reset stdout so regression tests, etc, don't get logged into the output #file that they themselves are trying to read if log_output: sys.stdout = restore_stdout if return_results_dict: return results_dict if return_output_fname and log_output: return outputfname
def main(argv=sys.argv, log_output=True, return_output_fname=False): """ Run a PyGBe problem, write outputs to STDOUT and to log file in problem directory Arguments ---------- log_output : Bool, default True. If False, output is written only to STDOUT and not to a log file. return_output_fname: Bool, default False. If True, function main() returns the name of the output log file. This is used for the regression tests. Returns -------- output_fname : str, if kwarg is True. The name of the log file containing problem output """ args = read_inputs(argv[1:]) configFile, paramfile = find_config_files(args) full_path = os.environ.get('PYGBE_PROBLEM_FOLDER') #check if a custom geometry location has been specified #if it has, add an ENV_VAR to handle it if args.geometry: geo_path = os.path.abspath(args.geometry) if os.path.isdir(geo_path): os.environ['PYGBE_GEOMETRY'] = geo_path else: sys.exit('Invalid geometry prefix provided (Folder not found)') else: geo_path = os.path.join(full_path, 'geometry') #try to expand ~ if present in output path args.output = os.path.expanduser(args.output) #if output path is absolute, use that, otherwise prepend #problem path if not os.path.isdir(args.output): output_dir = os.path.join(full_path, args.output) else: output_dir = args.output #create output directory if it doesn't already exist try: os.makedirs(output_dir) except OSError: pass results_dict = {} timestamp = time.localtime() outputfname = '{:%Y-%m-%d-%H%M%S}-output.log'.format(datetime.now()) results_dict['output_file'] = outputfname if log_output: sys.stdout = Logger(os.path.join(output_dir, outputfname)) ### Time stamp print 'Run started on:' print '\tDate: %i/%i/%i' % (timestamp.tm_year, timestamp.tm_mon, timestamp.tm_mday) print '\tTime: %i:%i:%i' % (timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec) TIC = time.time() print('Config file: {}'.format(configFile)) print('Parameter file: {}'.format(paramfile)) print('Geometry folder: {}'.format(geo_path)) print('Running in: {}'.format(full_path)) results_dict['config_file'] = configFile results_dict['param_file'] = paramfile results_dict['geo_file'] = geo_path results_dict['full_path'] = full_path ### Read parameters param = Parameters() precision = readParameters(param, paramfile) param.Nm = (param.P + 1) * (param.P + 2) * ( param.P + 3) / 6 # Number of terms in Taylor expansion param.BlocksPerTwig = int(numpy.ceil(param.NCRIT / float(param.BSZ)) ) # CUDA blocks that fit per twig HAS_GPU = check_for_nvcc() if param.GPU == 1 and not HAS_GPU: print('\n\n\n\n') print('{:-^{}}'.format('No GPU DETECTED', 60)) print("Your param file has `GPU = 1` but CUDA was not detected.\n" "Continuing using CPU. If you do not want this, use Ctrl-C\n" "to stop the program and check that your CUDA installation\n" "is on your $PATH") print('{:-^{}}'.format('No GPU DETECTED', 60)) print('\n\n\n\n') param.GPU = 0 time.sleep(3) ### Generate array of fields field_array = initializeField(configFile, param) ### Generate array of surfaces and read in elements surf_array = initializeSurf(field_array, configFile, param) ### Fill surface class time_sort = 0. for i in range(len(surf_array)): time_sort += fill_surface(surf_array[i], param) ### Output setup summary param.N = 0 param.Neq = 0 for s in surf_array: N_aux = len(s.triangle) param.N += N_aux if s.surf_type == 'dirichlet_surface' or s.surf_type == 'neumann_surface' or s.surf_type == 'asc_surface': param.Neq += N_aux else: param.Neq += 2 * N_aux print '\nTotal elements : %i' % param.N print 'Total equations: %i' % param.Neq results_dict['total_elements'] = param.N results_dict['N_equation'] = param.Neq results_dict = print_summary(surf_array, field_array, param, results_dict) ### Precomputation ind0 = IndexConstant() computeIndices(param.P, ind0) precomputeTerms(param.P, ind0) ### Load CUDA code if param.GPU == 1: kernel = kernels(param.BSZ, param.Nm, param.K_fine, param.P, precision) else: kernel = 1 ### Generate interaction list print 'Generate interaction list' tic = time.time() generateList(surf_array, field_array, param) toc = time.time() list_time = toc - tic ### Transfer data to GPU print 'Transfer data to GPU' tic = time.time() if param.GPU == 1: dataTransfer(surf_array, field_array, ind0, param, kernel) toc = time.time() transfer_time = toc - tic timing = Timing() ### Generate RHS print 'Generate RHS' tic = time.time() if param.GPU == 0: F = generateRHS(field_array, surf_array, param, kernel, timing, ind0) elif param.GPU == 1: F = generateRHS_gpu(field_array, surf_array, param, kernel, timing, ind0) toc = time.time() rhs_time = toc - tic setup_time = toc - TIC print 'List time : %fs' % list_time print 'Data transfer time : %fs' % transfer_time print 'RHS generation time: %fs' % rhs_time print '------------------------------' print 'Total setup time : %fs\n' % setup_time tic = time.time() ### Solve print 'Solve' phi = numpy.zeros(param.Neq) phi = gmres_mgs(surf_array, field_array, phi, F, param, ind0, timing, kernel) toc = time.time() solve_time = toc - tic print 'Solve time : %fs' % solve_time phifname = '{:%Y-%m-%d-%H%M%S}-phi.txt'.format(datetime.now()) results_dict['solve_time'] = solve_time numpy.savetxt(os.path.join(output_dir, phifname), phi) # Put result phi in corresponding surfaces fill_phi(phi, surf_array) ### Calculate solvation energy print '\nCalculate Esolv' tic = time.time() E_solv = calculateEsolv(surf_array, field_array, param, kernel) toc = time.time() print 'Time Esolv: %fs' % (toc - tic) ii = -1 for f in param.E_field: parent_type = surf_array[field_array[f].parent[0]].surf_type if parent_type != 'dirichlet_surface' and parent_type != 'neumann_surface': ii += 1 print 'Region %i: Esolv = %f kcal/mol = %f kJ/mol' % ( f, E_solv[ii], E_solv[ii] * 4.184) results_dict['E_solv_kcal'] = E_solv[ii] results_dict['E_solv_kJ'] = E_solv[ii] * 4.184 ### Calculate surface energy print '\nCalculate Esurf' tic = time.time() E_surf = calculateEsurf(surf_array, field_array, param, kernel) toc = time.time() ii = -1 for f in param.E_field: parent_type = surf_array[field_array[f].parent[0]].surf_type if parent_type == 'dirichlet_surface' or parent_type == 'neumann_surface': ii += 1 print 'Region %i: Esurf = %f kcal/mol = %f kJ/mol' % ( f, E_surf[ii], E_surf[ii] * 4.184) results_dict['E_surf_kcal'] = E_surf[ii] results_dict['E_surf_kJ'] = E_surf[ii] * 4.184 print 'Time Esurf: %fs' % (toc - tic) ### Calculate Coulombic interaction print '\nCalculate Ecoul' tic = time.time() i = -1 E_coul = [] for f in field_array: i += 1 if f.coulomb == 1: print 'Calculate Coulomb energy for region %i' % i E_coul.append(coulombEnergy(f, param)) print 'Region %i: Ecoul = %f kcal/mol = %f kJ/mol' % ( i, E_coul[-1], E_coul[-1] * 4.184) results_dict['E_coul_kcal'] = E_coul[-1] results_dict['E_coul_kJ'] = E_coul[-1] * 4.184 toc = time.time() print 'Time Ecoul: %fs' % (toc - tic) ### Output summary print '\n--------------------------------' print 'Totals:' print 'Esolv = %f kcal/mol' % sum(E_solv) print 'Esurf = %f kcal/mol' % sum(E_surf) print 'Ecoul = %f kcal/mol' % sum(E_coul) print '\nTime = %f s' % (toc - TIC) results_dict['total_time'] = (toc - TIC) output_pickle = outputfname.split('-') output_pickle.pop(-1) output_pickle.append('resultspickle') output_pickle = '-'.join(output_pickle) with open(os.path.join(output_dir, output_pickle), 'wb') as f: pickle.dump(results_dict, f) #reset stdout so regression tests, etc, don't get logged into the output #file that they themselves are trying to read sys.stdout = sys.__stdout__ if return_output_fname and log_output: return outputfname
def main(argv=sys.argv, log_output=True, return_output_fname=False, return_results_dict=False, field=None): """ Run a PyGBe problem, write outputs to STDOUT and to log file in problem directory Arguments ---------- log_output : Bool, default True. If False, output is written only to STDOUT and not to a log file. return_output_fname: Bool, default False. If True, function main() returns the name of the output log file. This is used for the regression tests. return_results_dict: Bool, default False. If True, function main() returns the results of the run packed in a dictionary. Used in testing and programmatic use of PyGBe field : Dictionary, defaults to None. If passed, this dictionary will supercede any config file found, useful in programmatically stepping through slight changes in a problem Returns -------- output_fname : str, if kwarg is True. The name of the log file containing problem output """ args = read_inputs(argv[1:]) configFile, paramfile = find_config_files(args) full_path = os.environ.get('PYGBE_PROBLEM_FOLDER') #check if a custom geometry location has been specified #if it has, add an ENV_VAR to handle it if args.geometry: geo_path = os.path.abspath(args.geometry) if os.path.isdir(geo_path): os.environ['PYGBE_GEOMETRY'] = geo_path else: sys.exit('Invalid geometry prefix provided (Folder not found)') else: geo_path = os.path.join(full_path, 'geometry') #try to expand ~ if present in output path args.output = os.path.expanduser(args.output) #if output path is absolute, use that, otherwise prepend #problem path if not os.path.isdir(args.output): output_dir = os.path.join(full_path, args.output) else: output_dir = args.output # create output directory if it doesn't already exist try: os.makedirs(output_dir) except OSError: pass results_dict = {} timestamp = time.localtime() outputfname = '{:%Y-%m-%d-%H%M%S}-output.log'.format(datetime.now()) results_dict['output_file'] = outputfname if log_output: restore_stdout = sys.stdout sys.stdout = Logger(os.path.join(output_dir, outputfname)) # Time stamp print('Run started on:') print('\tDate: {}/{}/{}'.format(timestamp.tm_year, timestamp.tm_mon, timestamp.tm_mday)) print('\tTime: {}:{}:{}'.format(timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec)) print('\tPyGBe version: {}'.format(pygbe.__version__)) TIC = time.time() print('Config file: {}'.format(configFile)) print('Parameter file: {}'.format(paramfile)) print('Geometry folder: {}'.format(geo_path)) print('Running in: {}'.format(full_path)) results_dict['config_file'] = configFile results_dict['param_file'] = paramfile results_dict['geo_file'] = geo_path results_dict['full_path'] = full_path ### Read parameters param = Parameters() precision = read_parameters(param, paramfile) param.Nm = (param.P + 1) * (param.P + 2) * ( param.P + 3) // 6 # Number of terms in Taylor expansion param.BlocksPerTwig = int(numpy.ceil( param.NCRIT / float(param.BSZ))) # CUDA blocks that fit per twig HAS_GPU = check_for_nvcc() if param.GPU == 1 and not HAS_GPU: print('\n\n\n\n') print('{:-^{}}'.format('No GPU DETECTED', 60)) print("Your param file has `GPU = 1` but CUDA was not detected.\n" "Continuing using CPU. If you do not want this, use Ctrl-C\n" "to stop the program and check that your CUDA installation\n" "is on your $PATH") print('{:-^{}}'.format('No GPU DETECTED', 60)) print('\n\n\n\n') param.GPU = 0 ### Generate array of fields if field: field_array = initialize_field(configFile, param, field) else: field_array = initialize_field(configFile, param) ### Generate array of surfaces and read in elements surf_array = initialize_surface(field_array, configFile, param) ### Fill surface class time_sort = 0. for i in range(len(surf_array)): time_sort += surf_array[i].fill_surface(param) ### Output setup summary param.N = 0 param.Neq = 0 for s in surf_array: N_aux = len(s.triangle) param.N += N_aux if s.surf_type in [ 'dirichlet_surface', 'neumann_surface', 'asc_surface' ]: param.Neq += N_aux else: param.Neq += 2 * N_aux print('\nTotal elements : {}'.format(param.N)) print('Total equations: {}'.format(param.Neq)) results_dict['total_elements'] = param.N results_dict['N_equation'] = param.Neq results_dict = print_summary(surf_array, field_array, param, results_dict) ### Precomputation ind0 = IndexConstant() computeIndices(param.P, ind0) precomputeTerms(param.P, ind0) ### Load CUDA code if param.GPU == 1: kernel = kernels(param.BSZ, param.Nm, param.K_fine, param.P, precision) else: kernel = 1 ### Generate interaction list print('Generate interaction list') tic = time.time() generateList(surf_array, field_array, param) toc = time.time() list_time = toc - tic ### Transfer data to GPU print('Transfer data to GPU') tic = time.time() if param.GPU == 1: dataTransfer(surf_array, field_array, ind0, param, kernel) toc = time.time() transfer_time = toc - tic timing = Timing() ### Generate RHS print('Generate RHS') tic = time.time() if param.GPU == 0: F = generateRHS(field_array, surf_array, param, kernel, timing, ind0) elif param.GPU == 1: F = generateRHS_gpu(field_array, surf_array, param, kernel, timing, ind0) toc = time.time() rhs_time = toc - tic setup_time = toc - TIC print('List time : {}s'.format(list_time)) print('Data transfer time : {}s'.format(transfer_time)) print('RHS generation time: {}s'.format(rhs_time)) print('-' * 30) print('Total setup time : {}s'.format(setup_time)) # Check if there is a complex dielectric if any([numpy.iscomplexobj(f.E) for f in field_array]): complex_diel = True else: complex_diel = False ### Solve tic = time.time() print('Solve') # Initializing phi dtype according to the problem we are solving. if not complex_diel: phi = numpy.zeros(param.Neq) else: raise ValueError( 'Dielectric should be real for solvation energy problems') phi, iteration = gmres_mgs(surf_array, field_array, phi, F, param, ind0, timing, kernel) toc = time.time() results_dict['iterations'] = iteration solve_time = toc - tic print('Solve time : {}s'.format(solve_time)) phifname = '{:%Y-%m-%d-%H%M%S}-phi.txt'.format(datetime.now()) results_dict['solve_time'] = solve_time numpy.savetxt(os.path.join(output_dir, phifname), phi) # Put result phi in corresponding surfaces s_start = 0 for surf in surf_array: s_start = surf.fill_phi(phi, s_start) # Calculate solvation energy print('Calculate Esolv') tic = time.time() E_solv = calculate_solvation_energy(surf_array, field_array, param, kernel) toc = time.time() print('Time Esolv: {}s'.format(toc - tic)) ii = -1 for i, f in enumerate(field_array): if f.pot == 1: parent_type = surf_array[f.parent[0]].surf_type if parent_type != 'dirichlet_surface' and parent_type != 'neumann_surface': ii += 1 print('Region {}: Esolv = {} kcal/mol = {} kJ/mol'.format( i, E_solv[ii], E_solv[ii] * 4.184)) # Calculate surface energy print('\nCalculate Esurf') tic = time.time() E_surf = calculate_surface_energy(surf_array, field_array, param, kernel) toc = time.time() ii = -1 for f in param.E_field: parent_type = surf_array[field_array[f].parent[0]].surf_type if parent_type == 'dirichlet_surface' or parent_type == 'neumann_surface': ii += 1 print('Region {}: Esurf = {} kcal/mol = {} kJ/mol'.format( f, E_surf[ii], E_surf[ii] * 4.184)) print('Time Esurf: {}s'.format(toc - tic)) ### Calculate Coulombic interaction print('\nCalculate Ecoul') tic = time.time() i = -1 E_coul = [] for f in field_array: i += 1 if f.coulomb == 1: print('Calculate Coulomb energy for region {}'.format(i)) E_coul.append(coulomb_energy(f, param)) print('Region {}: Ecoul = {} kcal/mol = {} kJ/mol'.format( i, E_coul[-1], E_coul[-1] * 4.184)) toc = time.time() print('Time Ecoul: {}s'.format(toc - tic)) ### Output summary print('\n' + '-' * 30) print('Totals:') print('Esolv = {} kcal/mol'.format(sum(E_solv))) print('Esurf = {} kcal/mol'.format(sum(E_surf))) print('Ecoul = {} kcal/mol'.format(sum(E_coul))) print('\nTime = {} s'.format(toc - TIC)) results_dict['E_solv_kcal'] = sum(E_solv) results_dict['E_solv_kJ'] = sum(E_solv) * 4.184 results_dict['E_surf_kcal'] = sum(E_surf) results_dict['E_surf_kJ'] = sum(E_surf) * 4.184 results_dict['E_coul_kcal'] = sum(E_coul) results_dict['E_coul_kJ'] = sum(E_coul) * 4.184 results_dict['total_time'] = (toc - TIC) results_dict['version'] = pygbe.__version__ output_pickle = outputfname.split('-') output_pickle.pop(-1) output_pickle.append('resultspickle') output_pickle = '-'.join(output_pickle) with open(os.path.join(output_dir, output_pickle), 'wb') as f: pickle.dump(results_dict, f, 2) try: with open(os.path.join(output_dir, output_pickle), 'rb') as f: pickle.load(f) except EOFError: print('Error writing the pickle file, the results will be unreadable') pass #reset stdout so regression tests, etc, don't get logged into the output #file that they themselves are trying to read if log_output: sys.stdout = restore_stdout if return_results_dict: return results_dict if return_output_fname and log_output: return outputfname
def main(argv=sys.argv, log_output=True, return_output_fname=False, return_results_dict=False, field=None): """ Run a PyGBe problem, write outputs to STDOUT and to log file in problem directory Arguments ---------- log_output : Bool, default True. If False, output is written only to STDOUT and not to a log file. return_output_fname: Bool, default False. If True, function main() returns the name of the output log file. This is used for the regression tests. return_results_dict: Bool, default False. If True, function main() returns the results of the run packed in a dictionary. Used in testing and programmatic use of PyGBe field : Dictionary, defaults to None. If passed, this dictionary will supercede any config file found, useful in programmatically stepping through slight changes in a problem Returns -------- output_fname : str, if kwarg is True. The name of the log file containing problem output """ args = read_inputs(argv[1:]) configFile, paramfile = find_config_files(args) full_path = os.environ.get('PYGBE_PROBLEM_FOLDER') #check if a custom geometry location has been specified #if it has, add an ENV_VAR to handle it if args.geometry: geo_path = os.path.abspath(args.geometry) if os.path.isdir(geo_path): os.environ['PYGBE_GEOMETRY'] = geo_path else: sys.exit('Invalid geometry prefix provided (Folder not found)') else: geo_path = os.path.join(full_path, 'geometry') #try to expand ~ if present in output path args.output = os.path.expanduser(args.output) #if output path is absolute, use that, otherwise prepend #problem path if not os.path.isdir(args.output): output_dir = os.path.join(full_path, args.output) else: output_dir = args.output # create output directory if it doesn't already exist try: os.makedirs(output_dir) except OSError: pass results_dict = {} timestamp = time.localtime() outputfname = '{:%Y-%m-%d-%H%M%S}-output.log'.format(datetime.now()) results_dict['output_file'] = outputfname if log_output: restore_stdout = sys.stdout sys.stdout = Logger(os.path.join(output_dir, outputfname)) # Time stamp print('Run started on:') print('\tDate: {}/{}/{}'.format(timestamp.tm_year, timestamp.tm_mon, timestamp.tm_mday)) print('\tTime: {}:{}:{}'.format(timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec)) print('\tPyGBe version: {}'.format(pygbe.__version__)) TIC = time.time() print('Config file: {}'.format(configFile)) print('Parameter file: {}'.format(paramfile)) print('Geometry folder: {}'.format(geo_path)) print('Running in: {}'.format(full_path)) results_dict['config_file'] = configFile results_dict['param_file'] = paramfile results_dict['geo_file'] = geo_path results_dict['full_path'] = full_path ### Read parameters param = Parameters() precision = read_parameters(param, paramfile) param.Nm = (param.P + 1) * (param.P + 2) * ( param.P + 3) // 6 # Number of terms in Taylor expansion param.BlocksPerTwig = int(numpy.ceil(param.NCRIT / float(param.BSZ)) ) # CUDA blocks that fit per twig HAS_GPU = check_for_nvcc() if param.GPU == 1 and not HAS_GPU: print('\n\n\n\n') print('{:-^{}}'.format('No GPU DETECTED', 60)) print("Your param file has `GPU = 1` but CUDA was not detected.\n" "Continuing using CPU. If you do not want this, use Ctrl-C\n" "to stop the program and check that your CUDA installation\n" "is on your $PATH") print('{:-^{}}'.format('No GPU DETECTED', 60)) print('\n\n\n\n') param.GPU = 0 ### Generate array of fields if field: field_array = initialize_field(configFile, param, field) else: field_array = initialize_field(configFile, param) ### Generate array of surfaces and read in elements surf_array = initialize_surface(field_array, configFile, param) ### Fill surface class time_sort = 0. for i in range(len(surf_array)): time_sort += surf_array[i].fill_surface(param) ### Output setup summary param.N = 0 param.Neq = 0 for s in surf_array: N_aux = len(s.triangle) param.N += N_aux if s.surf_type in ['dirichlet_surface', 'neumann_surface', 'asc_surface']: param.Neq += N_aux else: param.Neq += 2 * N_aux print('\nTotal elements : {}'.format(param.N)) print('Total equations: {}'.format(param.Neq)) results_dict['total_elements'] = param.N results_dict['N_equation'] = param.Neq results_dict = print_summary(surf_array, field_array, param, results_dict) ### Precomputation ind0 = IndexConstant() computeIndices(param.P, ind0) precomputeTerms(param.P, ind0) ### Load CUDA code if param.GPU == 1: kernel = kernels(param.BSZ, param.Nm, param.K_fine, param.P, precision) else: kernel = 1 ### Generate interaction list print('Generate interaction list') tic = time.time() generateList(surf_array, field_array, param) toc = time.time() list_time = toc - tic ### Transfer data to GPU print('Transfer data to GPU') tic = time.time() if param.GPU == 1: dataTransfer(surf_array, field_array, ind0, param, kernel) toc = time.time() transfer_time = toc - tic timing = Timing() ### Generate RHS print('Generate RHS') tic = time.time() if param.GPU == 0: F = generateRHS(field_array, surf_array, param, kernel, timing, ind0) elif param.GPU == 1: F = generateRHS_gpu(field_array, surf_array, param, kernel, timing, ind0) toc = time.time() rhs_time = toc - tic setup_time = toc - TIC print('List time : {}s'.format(list_time)) print('Data transfer time : {}s'.format(transfer_time)) print('RHS generation time: {}s'.format(rhs_time)) print('-'*30) print('Total setup time : {}s'.format(setup_time)) # Check if there is a complex dielectric if any([numpy.iscomplexobj(f.E) for f in field_array]): complex_diel = True else: complex_diel = False ### Solve tic = time.time() print('Solve') # Initializing phi dtype according to the problem we are solving. if not complex_diel: phi = numpy.zeros(param.Neq) else: raise ValueError('Dielectric should be real for solvation energy problems') phi, iteration = gmres_mgs(surf_array, field_array, phi, F, param, ind0, timing, kernel) toc = time.time() results_dict['iterations'] = iteration solve_time = toc - tic print('Solve time : {}s'.format(solve_time)) phifname = '{:%Y-%m-%d-%H%M%S}-phi.txt'.format(datetime.now()) results_dict['solve_time'] = solve_time numpy.savetxt(os.path.join(output_dir, phifname), phi) # Put result phi in corresponding surfaces s_start = 0 for surf in surf_array: s_start = surf.fill_phi(phi, s_start) # Calculate solvation energy print('\nCalculate Solvation Energy (E_solv)') tic = time.time() E_solv = calculate_solvation_energy(surf_array, field_array, param, kernel) toc = time.time() print('Time E_solv: {}s'.format(toc - tic)) ii = -1 for i, f in enumerate(field_array): if f.pot == 1: parent_type = surf_array[f.parent[0]].surf_type if parent_type != 'dirichlet_surface' and parent_type != 'neumann_surface': ii += 1 print('Region {}: E_solv = {} kcal/mol = {} kJ/mol'.format(i, E_solv[ii], E_solv[ii] * 4.184)) # Calculate surface energy print('\nCalculate Surface Energy (E_surf)') tic = time.time() E_surf = calculate_surface_energy(surf_array, field_array, param, kernel) toc = time.time() ii = -1 for f in param.E_field: parent_type = surf_array[field_array[f].parent[0]].surf_type if parent_type == 'dirichlet_surface' or parent_type == 'neumann_surface': ii += 1 print('Region {}: E_surf = {} kcal/mol = {} kJ/mol'.format( f, E_surf[ii], E_surf[ii] * 4.184)) print('Time E_surf: {}s'.format(toc - tic)) ### Calculate Coulombic interaction print('\nCalculate Coulomb Energy (E_coul)') tic = time.time() i = -1 E_coul = [] for f in field_array: i += 1 if f.coulomb == 1: print('Calculate Coulomb energy for region {}'.format(i)) E_coul.append(coulomb_energy(f, param)) print('Region {}: E_coul = {} kcal/mol = {} kJ/mol'.format( i, E_coul[-1], E_coul[-1] * 4.184)) toc = time.time() print('Time E_coul: {}s'.format(toc - tic)) ### Output summary print('\n'+'-'*30) print('Totals:') print('E_solv = {} kcal/mol'.format(sum(E_solv))) print('E_surf = {} kcal/mol'.format(sum(E_surf))) print('E_coul = {} kcal/mol'.format(sum(E_coul))) print('\nTime = {} s'.format(toc - TIC)) results_dict['E_solv_kcal'] = sum(E_solv) results_dict['E_solv_kJ'] = sum(E_solv) * 4.184 results_dict['E_surf_kcal'] = sum(E_surf) results_dict['E_surf_kJ'] = sum(E_surf) * 4.184 results_dict['E_coul_kcal'] = sum(E_coul) results_dict['E_coul_kJ'] = sum(E_coul) * 4.184 results_dict['total_time'] = (toc - TIC) results_dict['version'] = pygbe.__version__ output_pickle = outputfname.split('-') output_pickle.pop(-1) output_pickle.append('resultspickle') output_pickle = '-'.join(output_pickle) with open(os.path.join(output_dir, output_pickle), 'wb') as f: pickle.dump(results_dict, f, 2) try: with open(os.path.join(output_dir, output_pickle), 'rb') as f: pickle.load(f) except EOFError: print('Error writing the pickle file, the results will be unreadable') pass #reset stdout so regression tests, etc, don't get logged into the output #file that they themselves are trying to read if log_output: sys.stdout = restore_stdout if return_results_dict: return results_dict if return_output_fname and log_output: return outputfname