def reset(self): """ Reset environment and setup for new episode. Returns: initial state of reset environment. """ if self.solver_step > 0: mean_accumulated_drag = self.accumulated_drag / self.solver_step mean_accumulated_lift = self.accumulated_lift / self.solver_step if self.verbose > -1: printi("mean accumulated drag on the whole episode: {}".format(mean_accumulated_drag)) if self.inspection_params["show_all_at_reset"]: self.show_drag() self.show_control() self.start_class() next_state = np.transpose(np.array(self.probes_values)) if self.verbose > 0: printiv(next_state) self.episode_number += 1 return(next_state)
def compute_positions_for_plotting(self): # where the pressure probes are self.list_positions_probes_x = [] self.list_positions_probes_y = [] total_number_of_probes = len(self.output_params['locations']) printiv(total_number_of_probes) # get the positions for crrt_probe in self.output_params['locations']: if self.verbose > 2: printiv(crrt_probe) self.list_positions_probes_x.append(crrt_probe[0]) self.list_positions_probes_y.append(crrt_probe[1]) # where the jets are radius_cylinder = self.geometry_params['cylinder_size'] / 2.0 / self.geometry_params['clscale'] self.list_positions_jets_x = [] self.list_positions_jets_y = [] # compute the positions for crrt_jet_angle in self.geometry_params['jet_positions']: crrt_jet_angle_rad = math.pi / 180.0 * crrt_jet_angle crrt_x = radius_cylinder * math.cos(crrt_jet_angle_rad) crrt_y = radius_cylinder * math.sin(crrt_jet_angle_rad) self.list_positions_jets_x.append(crrt_x) self.list_positions_jets_y.append(1.1 * crrt_y)
def generate_mesh(args, template='geometry_2d.template_geo', dim=2): '''Modify template according args and make gmsh generate the mesh''' assert os.path.exists(template) args = args.copy() printiv(template) with open(template, 'r') as f: old = f.readlines() # Chop the file to replace the jet positions split = map(lambda s: s.startswith('DefineConstant'), old).index(True) jet_positions = deg2rad(map(float, args.pop('jet_positions'))) jet_positions = 'jet_positions[] = {%s};\n' % (', '.join( map(str, jet_positions))) body = ''.join([jet_positions] + old[split:]) output = args.pop('output') printiv(output) if not output: output = template assert os.path.splitext(output)[1] == '.geo' with open(output, 'w') as f: f.write(body) args['jet_width'] = deg2rad(args['jet_width']) scale = args.pop('clscale') cmd = 'gmsh -0 %s ' % output list_geometric_parameters = [ 'width', 'jet_radius', 'jet_width', 'box_size', 'length', 'bottom_distance', 'cylinder_size', 'front_distance', 'coarse_distance', 'coarse_size' ] constants = " " for crrt_param in list_geometric_parameters: constants = constants + " -setnumber " + crrt_param + " " + str( args[crrt_param]) # Unrolled model subprocess.call(cmd + constants, shell=True) unrolled = '_'.join([output, 'unrolled']) assert os.path.exists(unrolled) return subprocess.call( ['gmsh -%d -clscale %g %s' % (dim, scale, unrolled)], shell=True)
def reset(self): """ Reset environment and setup for new episode. Returns: initial state of reset environment. """ if self.solver_step > 0: mean_accumulated_drag = self.accumulated_drag / self.solver_step mean_accumulated_lift = self.accumulated_lift / self.solver_step if self.verbose > -1: printi("mean accumulated drag on the whole episode: {}".format(mean_accumulated_drag)) if self.inspection_params["show_all_at_reset"]: self.show_drag() self.show_control() chance = random.random() probability_hard_reset = 0.2 if chance < probability_hard_reset: self.start_class(complete_reset=True) else: self.start_class(complete_reset=False) # print(chance) next_state = np.transpose(np.array(self.probes_values)) if self.verbose > 0: printiv(next_state) self.episode_number += 1 return(next_state)
printi("resume env") environment = resume_env(plot=500, dump=10, single_run=True) deterministic=True printi("define network specs") network_spec = [ dict(type='dense', size=512), dict(type='dense', size=512), ] printi("define agent") printiv(environment.states) printiv(environment.actions) printiv(network_spec) agent = PPOAgent( states=environment.states, actions=environment.actions, network=network_spec, # Agent states_preprocessing=None, actions_exploration=None, reward_preprocessing=None, # MemoryModel update_mode=dict( unit='episodes', # 10 episodes per update
def __init__(self, flow_params, geometry_params, solver_params): # Using very simple IPCS solver mu = Constant(flow_params['mu']) # dynamic viscosity rho = Constant(flow_params['rho']) # density mesh_file = geometry_params['mesh'] printiv(mesh_file) # Load mesh with markers comm = mpi_comm_world() h5 = HDF5File(comm, mesh_file, 'r') mesh = Mesh() h5.read(mesh, 'mesh', False) surfaces = MeshFunction('size_t', mesh, mesh.topology().dim()-1) h5.read(surfaces, 'facet') # These tags should be hardcoded by gmsh during generation inlet_tag = 3 outlet_tag = 2 wall_tag = 1 cylinder_noslip_tag = 4 # Tags 5 and higher are jets # Define function spaces V = VectorFunctionSpace(mesh, 'CG', 2) Q = FunctionSpace(mesh, 'CG', 1) # Define trial and test functions u, v = TrialFunction(V), TestFunction(V) p, q = TrialFunction(Q), TestFunction(Q) u_n, p_n = Function(V), Function(Q) # Starting from rest or are we given the initial state for path, func, name in zip(('u_init', 'p_init'), (u_n, p_n), ('u0', 'p0')): if path in flow_params: comm = mesh.mpi_comm() XDMFFile(comm, flow_params[path]).read_checkpoint(func, name, 0) # assert func.vector().norm('l2') > 0 u_, p_ = Function(V), Function(Q) # Solve into these dt = Constant(solver_params['dt']) # Define expressions used in variational forms U = Constant(0.5)*(u_n + u) n = FacetNormal(mesh) f = Constant((0, 0)) epsilon = lambda u :sym(nabla_grad(u)) sigma = lambda u, p: 2*mu*epsilon(u) - p*Identity(2) # Define variational problem for step 1 F1 = (rho*dot((u - u_n) / dt, v)*dx + rho*dot(dot(u_n, nabla_grad(u_n)), v)*dx + inner(sigma(U, p_n), epsilon(v))*dx + dot(p_n*n, v)*ds - dot(mu*nabla_grad(U)*n, v)*ds - dot(f, v)*dx) a1, L1 = lhs(F1), rhs(F1) # Define variational problem for step 2 a2 = dot(nabla_grad(p), nabla_grad(q))*dx L2 = dot(nabla_grad(p_n), nabla_grad(q))*dx - (1/dt)*div(u_)*q*dx # Define variational problem for step 3 a3 = dot(u, v)*dx L3 = dot(u_, v)*dx - dt*dot(nabla_grad(p_ - p_n), v)*dx inflow_profile = flow_params['inflow_profile'](mesh, degree=2) # Define boundary conditions, first those that are constant in time bcu_inlet = DirichletBC(V, inflow_profile, surfaces, inlet_tag) # No slip bcu_wall = DirichletBC(V, Constant((0, 0)), surfaces, wall_tag) bcu_cyl_wall = DirichletBC(V, Constant((0, 0)), surfaces, cylinder_noslip_tag) # Fixing outflow pressure bcp_outflow = DirichletBC(Q, Constant(0), surfaces, outlet_tag) # Now the expression for the jets # NOTE: they start with Q=0 radius = geometry_params['jet_radius'] width = geometry_params['jet_width'] positions = geometry_params['jet_positions'] bcu_jet = [] jet_tags = range(cylinder_noslip_tag+1, cylinder_noslip_tag+1+len(positions)) jets = [JetBCValue(radius, width, theta0, Q=0, degree=1) for theta0 in positions] for tag, jet in zip(jet_tags, jets): bc = DirichletBC(V, jet, surfaces, tag) bcu_jet.append(bc) bc_symmetry = DirichletBC(V.sub(1), Constant(0), surfaces, 5) # All bcs objects togets bcu = [bcu_inlet, bc_symmetry, bcu_wall, bcu_cyl_wall] + bcu_jet bcp = [bcp_outflow] As = [Matrix() for i in range(3)] bs = [Vector() for i in range(3)] # Assemble matrices assemblers = [SystemAssembler(a1, L1, bcu), SystemAssembler(a2, L2, bcp), SystemAssembler(a3, L3, bcu)] # Apply bcs to matrices (this is done once) for a, A in zip(assemblers, As): a.assemble(A) # Chose between direct and iterative solvers solver_type = solver_params.get('la_solve', 'lu') assert solver_type in ('lu', 'la_solve') if solver_type == 'lu': solvers = map(lambda x: LUSolver("mumps"), range(3)) else: solvers = [KrylovSolver('bicgstab', 'hypre_amg'), # Very questionable preconditioner KrylovSolver('cg', 'hypre_amg'), KrylovSolver('cg', 'hypre_amg')] # Set matrices for once, likewise solver don't change in time for s, A in zip(solvers, As): s.set_operator(A) if solver_type == 'lu': s.parameters['reuse_factorization'] = True # Iterative tolerances else: s.parameters['relative_tolerance'] = 1E-8 s.parameters['monitor_convergence'] = True gtime = 0. # External clock # Things to remeber for evolution self.jets = jets # Keep track of time so that we can query it outside self.gtime, self.dt = gtime, dt # Remember inflow profile function in case it is time dependent self.inflow_profile = inflow_profile self.solvers = solvers self.assemblers = assemblers self.bs = bs self.u_, self.u_n = u_, u_n self.p_, self.p_n= p_, p_n # Rename u_, p_ for to standard names (simplifies processing) u_.rename('velocity', '0') p_.rename('pressure', '0') # Also expose measure for assembly of outputs outside self.ext_surface_measure = Measure('ds', domain=mesh, subdomain_data=surfaces) # Things to remember for easier probe configuration self.viscosity = mu self.density = rho self.normal = n self.cylinder_surface_tags = [cylinder_noslip_tag] + jet_tags
def callifile(module=None, verbose=False, pattern_to_call=None): """Call all the functions in a given module or file. Call only function that can be called without arguments or with default arguments. - module: the module / file on which call all functions. If None (default), take the caller one's. - verbose: True / False (default False) - pattern_to_call: call only functions that fit pattern_to_call. Default None (call all independantly of pattern matching, except a few specific self-recursive names).""" if module is None: frm = inspect.stack()[1] module = inspect.getmodule(frm[0]) if verbose: printi("Apply call_all_function_in_this_file on {}".format(module)) if verbose: if pattern_to_call is not None: printiv(pattern_to_call) all_functions = inspect.getmembers(module, inspect.isfunction) for key, value in all_functions: if verbose: printi("See if should call {} ...".format(key)) # check if can be called without argument ------------------------------ getargspec_output = getargspec(value) number_arguments = len(getargspec_output.args) if getargspec_output.defaults is None: number_default_arguments = 0 else: number_default_arguments = len(getargspec_output.defaults) if (number_arguments > number_default_arguments): if verbose: printi("discard {} because of arguments numbers!".format(key)) continue # check if it is this function ----------------------------------------- if (key == "call_all_function_in_this_file"): if verbose: printi("discard {} because function itself!".format(key)) continue # check if it is from callifile module --------------------------------- if fnmatch.fnmatch(key, "*callifile*"): if verbose: printi("discard {} because match callifile!".format(key)) continue # check if matches pattern --------------------------------------------- if pattern_to_call is not None: if not fnmatch.fnmatch(key, pattern_to_call): if verbose: printi("discard {} because match pattern!".format(key)) continue # if come all the way along, call -------------------------------------- if verbose: printi("Call {} !".format(key)) value()
def print_self(self): printiv(self.some_var)
def f_3(): printi('start f_3') a = 4 printiv(a)
def execute(self, actions=None): if self.verbose > 1: printi("--- call execute ---") if actions is None: if self.verbose > -1: printi("carefull, no action given; by default, no jet!") nbr_jets = len(self.geometry_params["jet_positions"]) actions = np.zeros((nbr_jets, )) if self.verbose > 2: printiv(actions) # to execute several numerical integration steps for _ in range(self.number_steps_execution): # try to force a continuous / smoothe(r) control if "smooth_control" in self.optimization_params: # printiv(self.optimization_params["smooth_control"]) # printiv(actions) # printiv(self.Qs) self.Qs += self.optimization_params["smooth_control"] * (np.array(actions) - self.Qs) else: self.Qs = np.transpose(np.array(actions)) # impose a zero net Qs if "zero_net_Qs" in self.optimization_params: if self.optimization_params["zero_net_Qs"]: self.Qs = self.Qs - np.mean(self.Qs) # evolve one numerical timestep forward self.u_, self.p_ = self.flow.evolve(self.Qs) # displaying information that has to do with the solver itself self.visual_inspection() self.output_data() # we have done one solver step self.solver_step += 1 # sample probes and drag self.probes_values = self.ann_probes.sample(self.u_, self.p_).flatten() self.drag = self.drag_probe.sample(self.u_, self.p_) self.lift = self.lift_probe.sample(self.u_, self.p_) self.recirc_area = self.area_probe.sample(self.u_, self.p_) # write to the history buffers self.write_history_parameters() self.accumulated_drag += self.drag self.accumulated_lift += self.lift # TODO: the next_state may incorporte more information: maybe some time information? next_state = np.transpose(np.array(self.probes_values)) if self.verbose > 2: printiv(next_state) terminal = False if self.verbose > 2: printiv(terminal) reward = self.compute_reward() if self.verbose > 2: printiv(reward) if self.verbose > 1: printi("--- done execute ---") return(next_state, terminal, reward) return area
def output_data(self): if "step" in self.inspection_params: modulo_base = self.inspection_params["step"] if self.solver_step % modulo_base == 0: if self.verbose > 0: printiv(self.solver_step) printiv(self.Qs) printiv(self.probes_values) printiv(self.drag) printiv(self.lift) printiv(self.recirc_area) if "dump" in self.inspection_params: modulo_base = self.inspection_params["dump"] #Sauvegarde du drag dans le csv a la fin de chaque episode self.episode_drags = np.append(self.episode_drags, [self.history_parameters["drag"].get()[-1]]) self.episode_areas = np.append(self.episode_areas, [self.history_parameters["recirc_area"].get()[-1]]) self.episode_lifts = np.append(self.episode_lifts, [self.history_parameters["lift"].get()[-1]]) if(self.last_episode_number != self.episode_number and "single_run" in self.inspection_params and self.inspection_params["single_run"] == False): self.last_episode_number = self.episode_number avg_drag = np.average(self.episode_drags[len(self.episode_drags)//2:]) avg_area = np.average(self.episode_areas[len(self.episode_areas)//2:]) avg_lift = np.average(self.episode_lifts[len(self.episode_lifts)//2:]) name = "output.csv" if(not os.path.exists("saved_models")): os.mkdir("saved_models") if(not os.path.exists("saved_models/"+name)): with open("saved_models/"+name, "w") as csv_file: spam_writer=csv.writer(csv_file, delimiter=";", lineterminator="\n") spam_writer.writerow(["Episode", "AvgDrag", "AvgLift", "AvgRecircArea"]) spam_writer.writerow([self.last_episode_number, avg_drag, avg_lift, avg_area]) else: with open("saved_models/"+name, "a") as csv_file: spam_writer=csv.writer(csv_file, delimiter=";", lineterminator="\n") spam_writer.writerow([self.last_episode_number, avg_drag, avg_lift, avg_area]) self.episode_drags = np.array([]) self.episode_areas = np.array([]) self.episode_lifts = np.array([]) if(os.path.exists("saved_models/output.csv")): if(not os.path.exists("best_model")): shutil.copytree("saved_models", "best_model") else : with open("saved_models/output.csv", 'r') as csvfile: data = csv.reader(csvfile, delimiter = ';') for row in data: lastrow = row last_iter = lastrow[1] with open("best_model/output.csv", 'r') as csvfile: data = csv.reader(csvfile, delimiter = ';') for row in data: lastrow = row best_iter = lastrow[1] if float(best_iter) < float(last_iter): print("best_model updated") if(os.path.exists("best_model")): shutil.rmtree("best_model") shutil.copytree("saved_models", "best_model") if self.solver_step % modulo_base == 0: if not self.initialized_output: self.u_out = File('results/u_out.pvd') self.p_out = File('results/p_out.pvd') self.initialized_output = True if(not self.area_probe is None): self.area_probe.dump(self.area_probe) self.u_out << self.flow.u_ self.p_out << self.flow.p_
def start_class(self): self.solver_step = 0 self.accumulated_drag = 0 self.accumulated_lift = 0 self.initialized_output = False self.resetted_number_probes = False self.area_probe = None self.history_parameters = {} for crrt_jet in range(len(self.geometry_params["jet_positions"])): self.history_parameters["jet_{}".format(crrt_jet)] = RingBuffer(self.size_history) self.history_parameters["number_of_jets"] = len(self.geometry_params["jet_positions"]) for crrt_probe in range(len(self.output_params["locations"])): if self.output_params["probe_type"] == 'pressure': self.history_parameters["probe_{}".format(crrt_probe)] = RingBuffer(self.size_history) elif self.output_params["probe_type"] == 'velocity': self.history_parameters["probe_{}_u".format(crrt_probe)] = RingBuffer(self.size_history) self.history_parameters["probe_{}_v".format(crrt_probe)] = RingBuffer(self.size_history) self.history_parameters["number_of_probes"] = len(self.output_params["locations"]) self.history_parameters["drag"] = RingBuffer(self.size_history) self.history_parameters["lift"] = RingBuffer(self.size_history) self.history_parameters["recirc_area"] = RingBuffer(self.size_history) # ------------------------------------------------------------------------ # remesh if necessary h5_file = '.'.join([self.path_root, 'h5']) msh_file = '.'.join([self.path_root, 'msh']) self.geometry_params['mesh'] = h5_file # Regenerate mesh? if self.geometry_params['remesh']: if self.verbose > 0: printi("Remesh") printi("generate_mesh start...") generate_mesh(self.geometry_params, template=self.geometry_params['template']) if self.verbose > 0: printi("generate_mesh done!") assert os.path.exists(msh_file) convert(msh_file, h5_file) assert os.path.exists(h5_file) # ------------------------------------------------------------------------ # if necessary, load initialization fields if self.n_iter_make_ready is None: if self.verbose > 0: printi("Load initial flow") self.flow_params['u_init'] = 'mesh/u_init.xdmf' self.flow_params['p_init'] = 'mesh/p_init.xdmf' if self.verbose > 0: printi("Load buffer history") with open('mesh/dict_history_parameters.pkl', 'rb') as f: self.history_parameters = pickle.load(f) if not "number_of_probes" in self.history_parameters: self.history_parameters["number_of_probes"] = 0 if not "number_of_jets" in self.history_parameters: self.history_parameters["number_of_jets"] = len(self.geometry_params["jet_positions"]) printi("Warning!! The number of jets was not set in the loaded hdf5 file") if not "lift" in self.history_parameters: self.history_parameters["lift"] = RingBuffer(self.size_history) printi("Warning!! No value for the lift founded") if not "recirc_area" in self.history_parameters: self.history_parameters["recirc_area"] = RingBuffer(self.size_history) printi("Warning!! No value for the recirculation area founded") # if not the same number of probes, reset if not self.history_parameters["number_of_probes"] == len(self.output_params["locations"]): for crrt_probe in range(len(self.output_params["locations"])): if self.output_params["probe_type"] == 'pressure': self.history_parameters["probe_{}".format(crrt_probe)] = RingBuffer(self.size_history) elif self.output_params["probe_type"] == 'velocity': self.history_parameters["probe_{}_u".format(crrt_probe)] = RingBuffer(self.size_history) self.history_parameters["probe_{}_v".format(crrt_probe)] = RingBuffer(self.size_history) self.history_parameters["number_of_probes"] = len(self.output_params["locations"]) printi("Warning!! Number of probes was changed! Probes buffer content reseted") self.resetted_number_probes = True # ------------------------------------------------------------------------ # create the flow simulation object self.flow = FlowSolver(self.flow_params, self.geometry_params, self.solver_params) # ------------------------------------------------------------------------ # Setup probes if self.output_params["probe_type"] == 'pressure': self.ann_probes = PressureProbeANN(self.flow, self.output_params['locations']) elif self.output_params["probe_type"] == 'velocity': self.ann_probes = VelocityProbeANN(self.flow, self.output_params['locations']) else: raise RuntimeError("unknown probe type") # Setup drag measurement self.drag_probe = PenetratedDragProbeANN(self.flow) self.lift_probe = PenetratedLiftProbeANN(self.flow) # ------------------------------------------------------------------------ # No flux from jets for starting self.Qs = np.zeros(len(self.geometry_params['jet_positions'])) # ------------------------------------------------------------------------ # prepare the arrays for plotting positions self.compute_positions_for_plotting() # ------------------------------------------------------------------------ # if necessary, make converge if self.n_iter_make_ready is not None: self.u_, self.p_ = self.flow.evolve(self.Qs) path='' if "dump" in self.inspection_params: path = 'results/area_out.pvd' self.area_probe = RecirculationAreaProbe(self.u_, 0, store_path=path) if self.verbose > 0: printi("Compute initial flow") printiv(self.n_iter_make_ready) for _ in range(self.n_iter_make_ready): self.u_, self.p_ = self.flow.evolve(self.Qs) self.probes_values = self.ann_probes.sample(self.u_, self.p_).flatten() self.drag = self.drag_probe.sample(self.u_, self.p_) self.lift = self.lift_probe.sample(self.u_, self.p_) self.recirc_area = self.area_probe.sample(self.u_, self.p_) self.write_history_parameters() self.visual_inspection() self.output_data() self.solver_step += 1 if self.n_iter_make_ready is not None: encoding = XDMFFile.Encoding_HDF5 mesh = convert(msh_file, h5_file) comm = mesh.mpi_comm() # save field data XDMFFile(comm, 'mesh/u_init.xdmf').write_checkpoint(self.u_, 'u0', 0, encoding) XDMFFile(comm, 'mesh/p_init.xdmf').write_checkpoint(self.p_, 'p0', 0, encoding) # save buffer dict with open('mesh/dict_history_parameters.pkl', 'wb') as f: pickle.dump(self.history_parameters, f, pickle.HIGHEST_PROTOCOL) # ---------------------------------------------------------------------- # if reading from disk, show to check everything ok if self.n_iter_make_ready is None: #Let's start in a random position of the vortex shading if self.optimization_params["random_start"]: rd_advancement = np.random.randint(650) for j in range(rd_advancement): self.flow.evolve(self.Qs) print("Simulated {} iterations before starting the control".format(rd_advancement)) self.u_, self.p_ = self.flow.evolve(self.Qs) path='' if "dump" in self.inspection_params: path = 'results/area_out.pvd' self.area_probe = RecirculationAreaProbe(self.u_, 0, store_path=path) self.probes_values = self.ann_probes.sample(self.u_, self.p_).flatten() self.drag = self.drag_probe.sample(self.u_, self.p_) self.lift = self.lift_probe.sample(self.u_, self.p_) self.recirc_area = self.area_probe.sample(self.u_, self.p_) self.write_history_parameters() # self.visual_inspection() # self.output_data() # self.solver_step += 1 # time.sleep(10) # ---------------------------------------------------------------------- # if necessary, fill the probes buffer if self.resetted_number_probes: printi("Need to fill again the buffer; modified number of probes") for _ in range(self.size_history): self.execute() # ---------------------------------------------------------------------- # ready now #Initialisation du prob de recirculation area #path='' #if "dump" in self.inspection_params: # path = 'results/area_out.pvd' #self.area_probe = RecirculationAreaProbe(self.u_, 0, store_path=path) self.ready_to_use = True