def rbf_interp(fem_coords,exp_coords,data,interp_direc): import scipy.interpolate as sp from code_settings import pipeline_files pf = pipeline_files() interp_method = pf.interp_method if (interp_direc == 0): ref_coords = fem_coords int_coords = exp_coords interpolated_data = np.zeros(int_coords.shape) else: ref_coords = exp_coords int_coords = fem_coords interpolated_data = np.zeros(int_coords.shape) for i in range(ref_coords.shape[0]): rbfi_x = sp.Rbf(ref_coords[i,:,0],ref_coords[i,:,1],ref_coords[i,:,2],data[i,:,0],method = interp_method) rbfi_y = sp.Rbf(ref_coords[i,:,0],ref_coords[i,:,1],ref_coords[i,:,2],data[i,:,1],method = interp_method) rbfi_z = sp.Rbf(ref_coords[i,:,0],ref_coords[i,:,1],ref_coords[i,:,2],data[i,:,2],method = interp_method) interpolated_data[i,:,0] = rbfi_x(int_coords[i,:,0],int_coords[i,:,1],int_coords[i,:,2]) interpolated_data[i,:,1] = rbfi_y(int_coords[i,:,0],int_coords[i,:,1],int_coords[i,:,2]) interpolated_data[i,:,2] = rbfi_z(int_coords[i,:,0],int_coords[i,:,1],int_coords[i,:,2]) return interpolated_data
def filepaths(*args): from code_settings import pipeline_files pf = pipeline_files() output = [] for i in range(len(args)): # Marc's .t16 output file for the "Numerical" FE model if ( args[i] ) == "fem_out": # Command to call with function to obtain the filepath specified below output.append( pf.crnt_fldr("fwd") + '/' + pf.sub_folder + '/' + pf.nm_t16) # The file created from the "Numerical" simulation, which contains the indentation level for each increment elif (args[i]) == "pointfem": output.append(pf.crnt_fldr("fwd") + '/' + "pointfem") # Marc's .t16 output file for the "Experimental" FE model elif (args[i]) == "exp_out": output.append( pf.crnt_fldr("fwd") + '/' + pf.sub_folder + '/' + pf.exp_t16) # The file created from the "Experimental" simulation, which contains the indentation level for each increment elif (args[i]) == "pointexp": output.append( pf.crnt_fldr("fwd") + '/' + pf.sub_folder + '/' + "cyl_diag/pointexp") # The input file for the "Numerical" model elif (args[i]) == "fem_dat": output.append( pf.crnt_fldr("fwd") + '/' + pf.sub_folder + '/' + pf.nm_dat) # The input file for the "Experimental" model elif (args[i]) == "exp_dat": output.append( pf.crnt_fldr("fwd") + '/' + pf.sub_folder + '/' + pf.exp_dat) # The status file for the "Numerical" model, to obtain the EXIT CODE elif (args[i]) == "fem_sts": output.append( pf.crnt_fldr("fwd") + '/' + pf.sub_folder + '/' + pf.nm_sts) # Filepath to store and obtain the procedure file to control the "Numerical" model simulations elif (args[i]) == "mat_proc_path": output.append(pf.crnt_fldr("fwd") + '/' + "mat.proc") # The name of the procedure file, incase it needs changing and don't want to go through the whole pipeline (OPTIONAL) elif (args[i]) == "mat_proc_file": output.append("mat.proc") # Filtepath and folder where to OBTAIN / STORE the data after DOT completed the optimisation elif (args[i]) == "path1": output.append( pf.crnt_fldr("fwd") + '/' + pf.sub_folder + '/' + "ResultsSQP") # Marc Mentat version 2019 elif (args[i]) == "2019": output.append( "C:/Program Files/MSC.Software/Marc/2019.0.0/mentat2019/binmentat.bat" ) # Marc Mentat version 2020 elif (args[i]) == "2020": output.append( "C:/Program Files/MSC.Software/Marc/2020.0.0/mentat2020/bin/mentat.bat" ) # ------------------------------------------------------------------------------------------------------------------- # In case two optimisation algorithms are tested: # - During the first algorithm optimisation name the folder as desired; here is was named "ResultsSQP" # with the SQP part refering to the optimisation algorithm. # - Before going to the next algorithm, set path1 to second algorithm's results and set path2 to the # first algorithm's results. # - ex. 1st algorithm run: # > path1 = ..../ResultsSQP # 2nd algorithm run: # > path1 = ..../ResultsSLP # > path2 = ..../ResultsSQP # NB !!!!!! - Remember to change the main_code file and the graphs file elif (args[i]) == "path2": output.append( pf.crnt_fldr("fwd") + '/' + pf.sub_folder + '/' + "ResultsSLP") # Filtepath and folder where to OBTAIN / STORE the data after DOT completed the optimisation (OPTIONAL) elif (args[i]) == "path3": output.append(pf.crnt_fldr("fwd") + '/' + pf.sub_folder) # ------------------------------------------------------------------------------------------------------------------- # Filepath to access the "Numerical" model, to be used to create the procedure file where MARC will then open this # FE model for analysis. elif (args[i]) == "mat_app_path": output.append(r'*open_model ' + pf.crnt_fldr("bwd") + '\\' + pf.sub_folder + '\\' + pf.nm_mud) if len(output) > 1: output = tuple(output) return (output) else: return (output[0])
# Francè Bresler # 12 February 2020 # ----------------------------------------------------------------------------------------------------------------- import numpy as np import pandas as pd import os from py_post import * from py_mentat import * import scipy.interpolate as sp import os import csv import time from functions import read_dat_node_number, read_dat_element_number, get_node_position, rbf_interp from code_settings import pipeline_files pf = pipeline_files() # // In this file the RBF_int function interpolates the nodal data from the "NUM" model to the same nodal locations of the # "EXP" model to obtain the same number nodes for both data sets. This is done by first obtaining the locations of each # node at each increment for the y-displacement of the indentor in both the "NUM" and "EXP" data. Since # the "NUM" data needs to fit the "EXP" data, the "EXP" data's node coordinates are used. Also both "NUM" and "EXP" data are # obtained through Marc which is an iterative solver, therefore at each solving increment of the indentor's y-displacement, there # are more than one sub-increment with the last sub-increment at that solver increment is the sub-increment which contains the # converged data for the level,thus only the last sub-incremental data are used. # After the data has been organised into the indentor increments, for the specific number of nodes presents in the "NUM" # and "Exp" data respectively, the interpolation can start. First the "NUM" data is linearly interpolated to the missing increments # for the "EXP" data's indentor displacements. There after Radial basis functions (RBF) are used to interpolate the current # level's "NUM" data to the nodal locations of the "EXP" data. # - fname1 = NUM output file (.t16 file) # - fname2 = NUM indentor level/increment output file # - fname3 = EXP output file (.t16 file)
def dotcall(self, x, xl, xu, nCons): # Reset nInit nInit = 0 #Initailize all array types nDvar = x.shape[0] ctDVAR = ct.c_double * nDvar ctCONS = ct.c_double * nCons ctRPRM = ct.c_double * 20 ctIPRM = ct.c_int * 20 #Initialize all arrays RPRM = ctRPRM(*(self.nmRPRM)) #Tells dot to use defaults IPRM = ctIPRM(*(self.nmIPRM)) #Tells dot to use defaults X = ctDVAR(*(x)) #Initial values XL = ctDVAR(*(xl)) #Lower bounds XU = ctDVAR(*(xu)) #Upper bounds G = ctCONS(*([0.0] * nCons)) #Constraints #Initialize constants METHOD = ct.c_int64(self.nMethod) NDV = ct.c_int64(nDvar) NCON = ct.c_int64(nCons) IPRINT = ct.c_int64(self.nPrint) MINMAX = ct.c_int64(self.nMinMax) INFO = ct.c_int64(self.nInfo) OBJ = ct.c_double(0.0) MAXINT = ct.c_int64(self.nMaxInt) # Call DOT510 NRWK = ct.c_int64() NRWKMN = ct.c_int64() NRIWD = ct.c_int64() NRWKMX = ct.c_int64() NRIWK = ct.c_int64() NSTORE = ct.c_int64() NGMAX = ct.c_int64() IERR = ct.c_int64() self.dotlib.DOT510(B(NDV), B(NCON), B(METHOD), B(NRWK), B(NRWKMN), B(NRIWD), B(NRWKMX), B(NRIWK), B(NSTORE), B(NGMAX), B(XL), B(XU), B(MAXINT), B(IERR)) ctRWK = ct.c_double * NRWKMX.value ctIWK = ct.c_int64 * NRIWK.value IWK = ctIWK(*([0] * NRIWK.value)) WK = ctRWK(*([0.0] * NRWKMX.value)) # Call DOT # // Here the original dot.py code was edited for personal use. The code can be adjusted as suited to the user. # // The iterations and objective lists were created as my own counter and is not necessary. These lists were # however used in this pipeline. itera = 0 iterations = [] objective = [] while (True): self.dotlib.DOT(B(INFO), B(METHOD), B(IPRINT), B(NDV), B(NCON), B(X), B(XL), B(XU), B(OBJ), B(MINMAX), B(G), B(RPRM), B(IPRM), B(WK), B(NRWKMX), B(IWK), B(NRIWK)) iterations.append(itera) objective.append(OBJ.value) itera = itera + 1 if (INFO.value == 0): # if the optimisation converged, enter loop import ast # // Open the "iterations" text file to obtain the current design point/ starting point form the list # obtained by the LHC function filec = open("iterations.txt", "r") it = int(filec.readline()) filec.close # // path1 = filepaths("path1") # // Read what the original starting point was of this optimisation run. filen = "starting_points.txt" filp = os.path.join(path1, filen) start = open(filp, 'r') xxx = ast.literal_eval(start.readlines()[it]) start.close() xxx = nm.array(xxx) xc = nm.array(X) print(xxx) print(xc) xa = xc * xxx # the final design point from dot is multiplied with the starting point to obtain the print( xa ) # material coefficient values, since the current values are the unbiased values. from functions import append_val, expdata, fem_orig_data, final_points # call the output functions needed if len(X) == 3: xf = [ xa[0], xa[1], xa[2] ] # store the optimised point in a form easily written to a text file elif len(X) == 2: xf = [xa[0], xa[1]] time.sleep(1) append_val( xf, iterations, objective ) # Writes out the iteration file to show how it converged final_points( xf) # store the optimised point in a separate file time.sleep(1) from functions import material2d, material3d #, material3d_ogden if len(X) == 3: material3d( xa ) # Create new procedure file for the optimised point elif len(X) == 2: material2d(xa) time.sleep(1) filem = "mat.proc" from code_settings import pipeline_files pf = pipeline_files() p = subprocess.Popen( [filepaths(pf.mentat_version), filem], bufsize=2048) # Start MSC Marc and load the procedure # file which will open the correct NUMERICAL model and change the material properties, start Marc # solver and to save the post file for the current DOT increment, close Marc and continue with the # code below p.wait() time.sleep(5) # Ensure that Marc file converged sts = filepaths("fem_sts") conver = pd.read_csv(sts, header=None, sep=' ', names=list(range(11)), keep_default_na=False) # open sts file of the optimisation NUMERICAL model, it contains the exit code from Marc. time.sleep(1) c = int(conver.iloc[-3, -1]) if c == 3004: g = -1 # 3004 says the FEM converged and the constraint is satisfied else: g = 1 # Any other exit number says the FEM did not converge and therefore the constraint # was not satisfied. This is a fail save to ensure the optimised point does adhere to the constraints. xv = xa time.sleep(1) from functions import violated_constr violated_constr( xv, c ) # This function saves the parameters which caused non-convergence and # also what the exit number was print(g) from RBF import RBF_int # call the RBF function fname1, fname2, fname3, fname4, fnamef, fnamee = filepaths( "fem_out", "pointfem", "exp_out", "pointexp", "fem_dat", "exp_dat") # // All the data after interpolation ce, de, fci, fdi, fvr, nne, nnf, dm = RBF_int( fname1, fname2, fname3, fname4, fnamef, fnamee, g) time.sleep(1) # // expdata( ce, de, fvr, nne) # Store the experimental data for the starting point fem_orig_data( fci, fdi, nnf, nne ) # Store the ouput data for the optimised point's simulation time.sleep(1) from functions import objectfunc objectfunc(objective, iterations) rem = filepaths("mat_proc_path") os.remove(rem) # os.remove('../Cylinder/mat.proc') break else: # if the optimisation procedure haven't converged yet fname1 = filepaths("fem_out") os.remove( fname1 ) #delete the current DOT optimisation increment's NUMERICAL data self.evaluate(X, OBJ, G, self.nmParam) # // rslt = nm.empty(2 + nDvar, float) rslt[0] = OBJ.value rslt[1] = 0.0 if len(G) > 0: rslt[1] = max(G) for i in range(nDvar): rslt[2 + i] = X[i] return rslt