def __init__(self, gb): self.gb = gb # -- flow -- # self.discr_flow = Flow(gb) shape = self.discr_flow.shape() self.flux_pressure = np.zeros(shape) # -- temperature -- # self.discr_temperature = Heat(gb) # -- solute and precipitate -- # self.discr_solute_advection_diffusion = Transport(gb) self.discr_solute_precipitate_reaction = Reaction(gb) # -- porosity -- # self.discr_porosity = Porosity(gb) # -- fracture aperture -- # self.discr_fracture_aperture = FractureAperture( gb, "fracture_aperture") # -- layer porosity and aperture -- # self.discr_layer_porosity = Porosity(gb, "layer_porosity") self.discr_layer_aperture = LayerAperture(gb, "layer_aperture") # the actual time of the simulation self.time = 0
def __init__(self, gb): self.gb = gb # -- flow -- # self.discr_flow = Flow(gb) shape = self.discr_flow.shape() self.flux_pressure = np.zeros(shape) # -- temperature -- # self.discr_temperature = Heat(gb) shape = self.discr_temperature.shape() self.temperature = np.zeros(shape) self.temperature_old = np.zeros(shape) # -- solute and precipitate -- # self.discr_solute_advection_diffusion = Transport(gb) self.discr_solute_precipitate_reaction = Reaction(gb) shape = self.discr_solute_advection_diffusion.shape() self.solute = np.zeros(shape) self.precipitate = np.zeros(shape) self.solute_old = np.zeros(shape) self.precipitate_old = np.zeros(shape) # -- porosity -- # self.discr_porosity = Porosity(gb) shape = self.discr_porosity.shape() self.porosity = np.zeros(shape) self.porosity_old = np.zeros(shape) self.porosity_star = np.zeros(shape) # -- aperture -- # self.discr_aperture = Aperture(gb) shape = self.discr_aperture.shape() self.aperture = np.zeros(shape) self.aperture_old = np.zeros(shape) self.aperture_star = np.zeros(shape) # -- composite variables -- # self.porosity_aperture_times_solute = np.zeros(shape) self.porosity_aperture_times_precipitate = np.zeros(shape)
def initialize(self, filename=None): """Initialize the Heat model. Parameters ---------- filename : str, optional Path to name of input file. """ if filename is None: self._model = Heat() elif isinstance(filename, types.StringTypes): with open(filename, "r") as file_obj: self._model = Heat.from_file_like(file_obj.read()) else: self._model = Heat.from_file_like(filename) self._values = {"plate_surface__temperature": self._model.temperature} self._var_units = {"plate_surface__temperature": "K"} self._grids = {0: ["plate_surface__temperature"]} self._grid_type = {0: "uniform_rectilinear_grid"}
def initialize(self, filename=None): """Initialize the Heat model. Parameters ---------- filename : str, optional Path to name of input file. """ if filename is None: self._model = Heat() elif isinstance(filename, types.StringTypes): with open(filename, 'r') as file_obj: self._model = Heat.from_file_like(file_obj.read()) else: self._model = Heat.from_file_like(filename) self._values = { 'plate_surface__temperature': self._model.temperature, } self._var_units = {'plate_surface__temperature': 'K'} self._grids = {0: ['plate_surface__temperature']} self._grid_type = {0: 'uniform_rectilinear_grid'}
class BmiHeat(Bmi): """Solve the heat equation for a 2D plate.""" _name = "The 2D Heat Equation" _input_var_names = ("plate_surface__temperature",) _output_var_names = ("plate_surface__temperature",) def __init__(self): """Create a BmiHeat model that is ready for initialization.""" self._model = None self._values = {} self._var_units = {} self._grids = {} self._grid_type = {} def initialize(self, filename=None): """Initialize the Heat model. Parameters ---------- filename : str, optional Path to name of input file. """ if filename is None: self._model = Heat() elif isinstance(filename, types.StringTypes): with open(filename, "r") as file_obj: self._model = Heat.from_file_like(file_obj.read()) else: self._model = Heat.from_file_like(filename) self._values = {"plate_surface__temperature": self._model.temperature} self._var_units = {"plate_surface__temperature": "K"} self._grids = {0: ["plate_surface__temperature"]} self._grid_type = {0: "uniform_rectilinear_grid"} def update(self): """Advance model by one time step.""" self._model.advance_in_time() def update_frac(self, time_frac): """Update model by a fraction of a time step. Parameters ---------- time_frac : float Fraction fo a time step. """ time_step = self.get_time_step() self._model.time_step = time_frac * time_step self.update() self._model.time_step = time_step def update_until(self, then): """Update model until a particular time. Parameters ---------- then : float Time to run model until. """ n_steps = (then - self.get_current_time()) / self.get_time_step() for _ in xrange(int(n_steps)): self.update() self.update_frac(n_steps - int(n_steps)) def finalize(self): """Finalize model.""" self._model = None def get_var_type(self, var_name): """Data type of variable. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- str Data type. """ return str(self.get_value_ref(var_name).dtype) def get_var_units(self, var_name): """Get units of variable. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- str Variable units. """ return self._var_units[var_name] def get_var_nbytes(self, var_name): """Get units of variable. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- int Size of data array in bytes. """ return self.get_value_ref(var_name).nbytes def get_var_grid(self, var_name): """Grid id for a variable. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- int Grid id. """ for grid_id, var_name_list in self._grids.items(): if var_name in var_name_list: return grid_id def get_grid_rank(self, grid_id): """Rank of grid. Parameters ---------- grid_id : int Identifier of a grid. Returns ------- int Rank of grid. """ return len(self.get_grid_shape(grid_id)) def get_grid_size(self, grid_id): """Size of grid. Parameters ---------- grid_id : int Identifier of a grid. Returns ------- int Size of grid. """ return np.prod(self.get_grid_shape(grid_id)) def get_value_ref(self, var_name): """Reference to values. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- array_like Value array. """ return self._values[var_name] def get_value(self, var_name): """Copy of values. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- array_like Copy of values. """ return self.get_value_ref(var_name).copy() def get_value_at_indices(self, var_name, indices): """Get values at particular indices. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. indices : array_like Array of indices. Returns ------- array_like Values at indices. """ return self.get_value_ref(var_name).take(indices) def set_value(self, var_name, src): """Set model values. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. src : array_like Array of new values. """ val = self.get_value_ref(var_name) val[:] = src def set_value_at_indices(self, var_name, src, indices): """Set model values at particular indices. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. src : array_like Array of new values. indices : array_like Array of indices. """ val = self.get_value_ref(var_name) val.flat[indices] = src def get_component_name(self): """Name of the component.""" return self._name def get_input_var_names(self): """Get names of input variables.""" return self._input_var_names def get_output_var_names(self): """Get names of output variables.""" return self._output_var_names def get_grid_shape(self, grid_id): """Number of rows and columns of uniform rectilinear grid.""" var_name = self._grids[grid_id][0] return self.get_value_ref(var_name).shape def get_grid_spacing(self, grid_id): """Spacing of rows and columns of uniform rectilinear grid.""" return self._model.spacing def get_grid_origin(self, grid_id): """Origin of uniform rectilinear grid.""" return self._model.origin def get_grid_type(self, grid_id): """Type of grid.""" return self._grid_type[grid_id] def get_start_time(self): """Start time of model.""" return 0.0 def get_end_time(self): """End time of model.""" return np.finfo("d").max def get_current_time(self): """Current time of model.""" return self._model.time def get_time_step(self): """Time step of model.""" return self._model.time_step
class BmiHeat(Bmi): """Solve the heat equation for a 2D plate.""" _name = 'The 2D Heat Equation' _input_var_names = ('plate_surface__temperature', ) _output_var_names = ('plate_surface__temperature', ) def __init__(self): """Create a BmiHeat model that is ready for initialization.""" self._model = None self._values = {} self._var_units = {} self._grids = {} self._grid_type = {} def initialize(self, filename=None): """Initialize the Heat model. Parameters ---------- filename : str, optional Path to name of input file. """ if filename is None: self._model = Heat() elif isinstance(filename, types.StringTypes): with open(filename, 'r') as file_obj: self._model = Heat.from_file_like(file_obj.read()) else: self._model = Heat.from_file_like(filename) self._values = { 'plate_surface__temperature': self._model.temperature, } self._var_units = {'plate_surface__temperature': 'K'} self._grids = {0: ['plate_surface__temperature']} self._grid_type = {0: 'uniform_rectilinear_grid'} def update(self): """Advance model by one time step.""" self._model.advance_in_time() def update_frac(self, time_frac): """Update model by a fraction of a time step. Parameters ---------- time_frac : float Fraction fo a time step. """ time_step = self.get_time_step() self._model.time_step = time_frac * time_step self.update() self._model.time_step = time_step def update_until(self, then): """Update model until a particular time. Parameters ---------- then : float Time to run model until. """ n_steps = (then - self.get_current_time()) / self.get_time_step() for _ in xrange(int(n_steps)): self.update() self.update_frac(n_steps - int(n_steps)) def finalize(self): """Finalize model.""" self._model = None def get_var_type(self, var_name): """Data type of variable. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- str Data type. """ return str(self.get_value_ref(var_name).dtype) def get_var_units(self, var_name): """Get units of variable. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- str Variable units. """ return self._var_units[var_name] def get_var_nbytes(self, var_name): """Get units of variable. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- int Size of data array in bytes. """ return self.get_value_ref(var_name).nbytes def get_var_grid(self, var_name): """Grid id for a variable. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- int Grid id. """ for grid_id, var_name_list in self._grids.items(): if var_name in var_name_list: return grid_id def get_grid_rank(self, grid_id): """Rank of grid. Parameters ---------- grid_id : int Identifier of a grid. Returns ------- int Rank of grid. """ return len(self.get_grid_shape(grid_id)) def get_grid_size(self, grid_id): """Size of grid. Parameters ---------- grid_id : int Identifier of a grid. Returns ------- int Size of grid. """ return np.prod(self.get_grid_shape(grid_id)) def get_value_ref(self, var_name): """Reference to values. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- array_like Value array. """ return self._values[var_name] def get_value(self, var_name): """Copy of values. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. Returns ------- array_like Copy of values. """ return self.get_value_ref(var_name).copy() def get_value_at_indices(self, var_name, indices): """Get values at particular indices. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. indices : array_like Array of indices. Returns ------- array_like Values at indices. """ return self.get_value_ref(var_name).take(indices) def set_value(self, var_name, src): """Set model values. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. src : array_like Array of new values. """ val = self.get_value_ref(var_name) val[:] = src def set_value_at_indices(self, var_name, src, indices): """Set model values at particular indices. Parameters ---------- var_name : str Name of variable as CSDMS Standard Name. src : array_like Array of new values. indices : array_like Array of indices. """ val = self.get_value_ref(var_name) val.flat[indices] = src def get_component_name(self): """Name of the component.""" return self._name def get_input_var_names(self): """Get names of input variables.""" return self._input_var_names def get_output_var_names(self): """Get names of output variables.""" return self._output_var_names def get_grid_shape(self, grid_id): """Number of rows and columns of uniform rectilinear grid.""" var_name = self._grids[grid_id][0] return self.get_value_ref(var_name).shape def get_grid_spacing(self, grid_id): """Spacing of rows and columns of uniform rectilinear grid.""" return self._model.spacing def get_grid_origin(self, grid_id): """Origin of uniform rectilinear grid.""" return self._model.origin def get_grid_type(self, grid_id): """Type of grid.""" return self._grid_type[grid_id] def get_start_time(self): """Start time of model.""" return 0. def get_end_time(self): """End time of model.""" #Changed by JLG from #return np.finfo('d').max #to the line below. return 100. def get_current_time(self): """Current time of model.""" return self._model.time def get_time_step(self): """Time step of model.""" return self._model.time_step
def __init__(self): name = 'Antoine-Laurent de Lavoisier' story = "Brought about a rennaissance in chemistry by discovering the Law of Conservation of Mass, inventing our system of naming with Berthollet, working with Laplace on calorimetry, and understanding combustion with his wife." year = 1780 heat = Heat() super(Lavoisier, self).__init__(name, year, story, heat)
def __init__(self): name = 'Alessandro Volta' story = 'Constructed the first electrical battery and founded electrochemistry with the invention of galvonic cells.' year = 1800 heat = Heat() super(AlessandroVolta, self).__init__(name, year, story, heat)
def __init__(self): name = 'Robert Boyle' story = "Founder of modern chemistry. Boyle's law states that the volume and pressure of a gas are inversely proportional when the temperature is constant. So when the pressure goes up, the volume goes down, and vice versa." year = 1662 heat = Heat() super(RobertBoyle, self).__init__(name, year, story, heat)
def __init__(self): name = 'Sir Francis Bacon' story = 'Developed the scientific method.' year = 1605 heat = Heat() super(SirFrancisBacon, self).__init__(name, year, story, heat)
def __init__(self): name = 'Jābir ibn Hayyān (Geber)' story = 'Father of chemistry: introduced a systematic classification of chemical substances, and provided instructions for deriving an inorganic compound (sal ammoniac or ammonium chloride) from organic substances (such as plants, blood, and hair) by chemical means. Declared there were 6 idealized elements: air, earth, fire, water, sulphur (combustability), and mercury (metallic properties).' year = 800 heat = Heat() super(Geber, self).__init__(name, year, story, heat)
def __init__(self): story = 'Declared that matter is composed of indivisible and indestructible particles called "atomos"' heat = Heat() super(Democritus, self).__init__('Democritus', -380, story, heat)
class Scheme(object): # ------------------------------------------------------------------------------# def __init__(self, gb): self.gb = gb # -- flow -- # self.discr_flow = Flow(gb) shape = self.discr_flow.shape() self.flux_pressure = np.zeros(shape) # -- temperature -- # self.discr_temperature = Heat(gb) shape = self.discr_temperature.shape() self.temperature = np.zeros(shape) self.temperature_old = np.zeros(shape) # -- solute and precipitate -- # self.discr_solute_advection_diffusion = Transport(gb) self.discr_solute_precipitate_reaction = Reaction(gb) shape = self.discr_solute_advection_diffusion.shape() self.solute = np.zeros(shape) self.precipitate = np.zeros(shape) self.solute_old = np.zeros(shape) self.precipitate_old = np.zeros(shape) # -- porosity -- # self.discr_porosity = Porosity(gb) shape = self.discr_porosity.shape() self.porosity = np.zeros(shape) self.porosity_old = np.zeros(shape) self.porosity_star = np.zeros(shape) # -- aperture -- # self.discr_aperture = Aperture(gb) shape = self.discr_aperture.shape() self.aperture = np.zeros(shape) self.aperture_old = np.zeros(shape) self.aperture_star = np.zeros(shape) # -- composite variables -- # self.porosity_aperture_times_solute = np.zeros(shape) self.porosity_aperture_times_precipitate = np.zeros(shape) # ------------------------------------------------------------------------------# def compute_flow(self): A, b = self.discr_flow.matrix_rhs() return sps.linalg.spsolve(A, b) # ------------------------------------------------------------------------------# def compute_temperature(self, porosity_star, aperture_star): # compute the matrices A, M, b = self.discr_temperature.matrix_rhs() # compute the effective thermal capacity, keeping in mind that the fracture # contains only water rc_w = self.discr_temperature.data["rc_w"] rc_s = self.discr_temperature.data["rc_s"] c_star = rc_w * (porosity_star + aperture_star) + rc_s * (1 - porosity_star) c_old = rc_w * (self.porosity_old + self.aperture_old) + rc_s * (1 - self.porosity_old) # the mass term which considers the contribution from the effective thermal capacity M_star = M * sps.diags(c_star, 0) M_old = M * sps.diags(c_old, 0) # compute the new temperature return sps.linalg.spsolve(M_star + A, M_old * self.temperature_old + b) # ------------------------------------------------------------------------------# def compute_solute_precipitate_advection_diffusion(self, porosity_star, aperture_star): # compute the matrices A, M, b = self.discr_solute_advection_diffusion.matrix_rhs() # the mass term which considers both the porosity and aperture contribution M_star = M * sps.diags(porosity_star + aperture_star, 0) M_old = M * sps.diags(self.porosity_old + self.aperture_old, 0) # compute the new solute return sps.linalg.spsolve(M_star + A, M_old * self.solute_old + b) # ------------------------------------------------------------------------------# def compute_solute_precipitate_rection(self, solute_half, precipitate_half): # the dof associated to the porous media and fractures, are the first dof = self.gb.num_cells() # temporary solution vectors solute = np.zeros(self.discr_solute_advection_diffusion.shape()) precipitate = np.zeros(self.discr_solute_advection_diffusion.shape()) # compute the new solute and precipitate solute[:dof], precipitate[:dof] = self.discr_solute_precipitate_reaction.step( solute_half[:dof], precipitate_half[:dof], self.temperature[:dof]) return solute, precipitate # ------------------------------------------------------------------------------# def set_old_variables(self): self.temperature_old = self.temperature.copy() self.solute_old = self.solute.copy() self.precipitate_old = self.precipitate.copy() self.porosity_old = self.porosity.copy() self.aperture_old = self.aperture.copy() # ------------------------------------------------------------------------------# def set_data(self, param): # set the initial condition assembler = self.discr_solute_advection_diffusion.assembler dof = np.cumsum(np.append(0, np.asarray(assembler.full_dof))) for (g, _), bi in assembler.block_dof.items(): #g = pair[0] if isinstance(g, pp.Grid): dof_loc = slice(dof[bi], dof[bi+1]) data = param["temperature"]["initial"] self.temperature[dof_loc] = data(g, param, param["tol"]) data = param["solute_advection_diffusion"]["initial_solute"] self.solute[dof_loc] = data(g, param, param["tol"]) data = param["solute_advection_diffusion"]["initial_precipitate"] self.precipitate[dof_loc] = data(g, param, param["tol"]) data = param["porosity"]["initial"] self.porosity[dof_loc] = data(g, param, param["tol"]) data = param["aperture"]["initial"] self.aperture[dof_loc] = data(g, param, param["tol"]) # set the old variables self.set_old_variables() # save the initial porosity and aperture self.discr_porosity.extract(self.porosity, "porosity_initial") self.discr_aperture.extract(self.aperture, "aperture_initial") # extract the initialized variables, useful for setting the data self.extract() # set now the data for each scheme self.discr_flow.set_data(param["flow"], param["time"]) self.discr_temperature.set_data(param["temperature"], param["time"]) self.discr_solute_advection_diffusion.set_data(param["solute_advection_diffusion"], param["time"]) self.discr_solute_precipitate_reaction.set_data(param["solute_precipitate_reaction"], param["time"]) self.discr_porosity.set_data(param["porosity"]) self.discr_aperture.set_data(param["aperture"]) # ------------------------------------------------------------------------------# def extract(self): self.discr_flow.extract(self.flux_pressure) self.discr_temperature.extract(self.temperature, "temperature") self.discr_solute_advection_diffusion.extract(self.solute, "solute") self.discr_solute_advection_diffusion.extract(self.precipitate, "precipitate") self.discr_porosity.extract(self.porosity, "porosity") self.discr_porosity.extract(self.porosity_old, "porosity_old") self.discr_aperture.extract(self.aperture, "aperture") self.discr_aperture.extract(self.aperture_old, "aperture_old") self.discr_solute_advection_diffusion.extract(self.porosity_aperture_times_solute, "porosity_aperture_times_solute") self.discr_solute_advection_diffusion.extract(self.porosity_aperture_times_precipitate, "porosity_aperture_times_precipitate") # ------------------------------------------------------------------------------# def vars_to_save(self): name = ["solute", "precipitate", "porosity", "aperture", "temperature"] name += ["porosity_aperture_times_solute", "porosity_aperture_times_precipitate"] return name + [self.discr_flow.pressure, self.discr_flow.P0_flux] # ------------------------------------------------------------------------------# def one_step_splitting_scheme(self): # the dof associated to the porous media and fractures, are the first dof = slice(0, self.gb.num_cells()) # POINT 1) extrapolate the precipitate to get a better estimate of porosity precipitate_star = 2*self.precipitate - self.precipitate_old # POINT 2) compute the porosity and aperture star porosity_star = self.discr_porosity.step(self.porosity_old, precipitate_star, self.precipitate_old) self.discr_porosity.extract(porosity_star, "porosity_star") aperture_star = self.discr_aperture.step(self.aperture_old, precipitate_star, self.precipitate_old) self.discr_aperture.extract(aperture_star, "aperture_star") # -- DO THE FLOW PART -- # # POINT 3) update the data from the previous time step self.discr_flow.update_data() # POINT 4) solve the flow part self.flux_pressure = self.compute_flow() self.discr_flow.extract(self.flux_pressure) # -- DO THE HEAT PART -- # # POINT 5) set the flux and update the data from the previous time step self.discr_temperature.set_flux(self.discr_flow.flux, self.discr_flow.mortar) self.discr_temperature.update_data() # POINT 5) solve the temperature part self.temperature = self.compute_temperature(porosity_star, aperture_star) # -- DO THE TRANSPORT PART -- # # set the flux and update the data from the previous time step self.discr_solute_advection_diffusion.set_flux(self.discr_flow.flux, self.discr_flow.mortar) self.discr_solute_advection_diffusion.update_data() # POINT 6) solve the advection and diffusion part to get the intermediate solute solution solute_half = self.compute_solute_precipitate_advection_diffusion(porosity_star, aperture_star) # POINT 7) Since in the advection-diffusion step we have accounted for porosity changes using # phi_star, the new solute concentration accounts for the change in pore volume, thus, the # precipitate needs to be updated accordingly factor = np.zeros(self.porosity_old.size) factor[dof] = (self.porosity_old[dof] + self.aperture_old[dof]) / (porosity_star[dof] + aperture_star[dof]) precipitate_half = self.precipitate_old * factor # POINT 8) solve the reaction part solute_star_star, precipitate_star_star = self.compute_solute_precipitate_rection(solute_half, precipitate_half) # -- DO THE POROSITY PART -- # # POINT 9) solve the porosity and aperture part with the true concentration of precipitate self.porosity = self.discr_porosity.step(self.porosity, precipitate_star_star, self.precipitate_old) self.aperture = self.discr_aperture.step(self.aperture, precipitate_star_star, self.precipitate_old) # POINT 10) finally, we correct the concentrations to account for the difference between the extrapolated # and "true" new porosity to ensure mass conservation factor = np.zeros(self.porosity_old.size) factor[dof] = (porosity_star[dof] + aperture_star[dof]) / (self.porosity[dof] + self.aperture[dof]) self.solute = solute_star_star * factor self.precipitate = precipitate_star_star * factor # set the old variables self.set_old_variables() # compute composite variables factor = self.porosity + self.aperture self.porosity_aperture_times_solute = factor * self.solute self.porosity_aperture_times_precipitate = factor * self.precipitate # extract all the variables, useful for exporting self.extract()
nrow = 20 dz = 10 file_like = StringIO( """ shape: [{nrow},] spacing: [{dz},] kappa: {kappa} k: {k} Qm: {Qm} """.format( kappa=kappa, k=k, Qm=Qm, nrow=nrow, dz=dz, ) ) # Create an instance of the Heat model, initialize it from the file. h = Heat() h.initialize(file_like) # set the initial temperature based on our linear fit. model_z = np.arange(0, nrow * dz, dz) T_init = fit.intercept_[0] + fit.coef_[0][0] * model_z h.set_value("temperature", T_init) # override the default timestep to use 1 day. h.timestep = seconds_per_day # run the model forward in time forced by the surface temperature. while h.get_current_time() < duration_years * seconds_per_year: # calculate the time to run until. run_until = min([h.get_current_time() + seconds_per_year, duration_years*seconds_per_year])
class Scheme(object): # ------------------------------------------------------------------------------# def __init__(self, gb): self.gb = gb # -- flow -- # self.discr_flow = Flow(gb) shape = self.discr_flow.shape() self.flux_pressure = np.zeros(shape) # -- temperature -- # self.discr_temperature = Heat(gb) # -- solute and precipitate -- # self.discr_solute_advection_diffusion = Transport(gb) self.discr_solute_precipitate_reaction = Reaction(gb) # -- porosity -- # self.discr_porosity = Porosity(gb) # -- fracture aperture -- # self.discr_fracture_aperture = FractureAperture( gb, "fracture_aperture") # -- layer porosity and aperture -- # self.discr_layer_porosity = Porosity(gb, "layer_porosity") self.discr_layer_aperture = LayerAperture(gb, "layer_aperture") # the actual time of the simulation self.time = 0 # ------------------------------------------------------------------------------# def compute_precipitate_temperature_star(self): for g, d in self.gb: d[pp.STATE]["precipitate_star"] = 2 * d[ pp.STATE]["precipitate"] - d[pp.STATE]["precipitate_old"] d[pp.STATE]["temperature_star"] = 2 * d[ pp.STATE]["temperature"] - d[pp.STATE]["temperature_old"] # ------------------------------------------------------------------------------# def compute_porosity_aperture_star(self): dim_max = self.gb.dim_max() # only the rock matrix has the variable porosity for g in self.gb.grids_of_dimension(dim_max): d = self.gb.node_props(g) d[pp.STATE]["porosity_star"] = self.discr_porosity.step( d[pp.STATE]["porosity_old"], d[pp.STATE]["precipitate_star"], d[pp.STATE]["precipitate_old"]) # only the fracture and the layer have the variable aperture for g in self.gb.grids_of_dimension(dim_max - 1): d = self.gb.node_props(g) if "fracture" in g.name: d[pp.STATE][ "fracture_aperture_star"] = self.discr_fracture_aperture.step( d[pp.STATE]["fracture_aperture_old"], d[pp.STATE]["precipitate_star"], d[pp.STATE]["precipitate_old"]) if "layer" in g.name: d[pp.STATE]["layer_aperture_star"] = d[ pp.STATE]["layer_aperture_old"] d[pp.STATE][ "layer_porosity_star"] = self.discr_layer_porosity.step( d[pp.STATE]["layer_porosity_old"], d[pp.STATE]["precipitate_star"], d[pp.STATE]["precipitate_old"]) # ------------------------------------------------------------------------------# def compute_flow(self): A, b = self.discr_flow.matrix_rhs() x = sps.linalg.spsolve(A, b) if not np.all(np.isfinite(x)): raise ValueError self.discr_flow.extract(x) # ------------------------------------------------------------------------------# def compute_temperature(self): A, b = self.discr_temperature.matrix_rhs() x = sps.linalg.spsolve(A, b) if not np.all(np.isfinite(x)): raise ValueError self.discr_temperature.extract(x, "temperature") # ------------------------------------------------------------------------------# def compute_solute_precipitate_advection_diffusion(self): A, b = self.discr_solute_advection_diffusion.matrix_rhs() x = sps.linalg.spsolve(A, b) if not np.all(np.isfinite(x)): raise ValueError self.discr_solute_advection_diffusion.extract(x, "solute_half") # ------------------------------------------------------------------------------# def correct_precipitate_with_star(self): for g, d in self.gb: vol_star = d[pp.STATE]["porosity_star"] + d[pp.STATE]["fracture_aperture_star"] +\ d[pp.STATE]["layer_porosity_star"] vol_old = d[pp.STATE]["porosity_old"] + d[pp.STATE]["fracture_aperture_old"] + \ d[pp.STATE]["layer_porosity_old"] d[pp.STATE]["precipitate_half"] = d[ pp.STATE]["precipitate_old"] * (vol_old / vol_star) # ------------------------------------------------------------------------------# def compute_solute_precipitate_rection(self): for g, d in self.gb: d[pp.STATE]["solute_star_star"], d[pp.STATE]["precipitate_star_star"] = \ self.discr_solute_precipitate_reaction.step(d[pp.STATE]["solute_half"], d[pp.STATE]["precipitate_half"], d[pp.STATE]["temperature"]) # ------------------------------------------------------------------------------# def compute_porosity_aperture(self): dim_max = self.gb.dim_max() # only the rock matrix has the variable porosity for g in self.gb.grids_of_dimension(dim_max): d = self.gb.node_props(g) d[pp.STATE]["porosity"] = self.discr_porosity.step( d[pp.STATE]["porosity"], d[pp.STATE]["precipitate_star_star"], d[pp.STATE]["precipitate_old"]) # only the fracture and the layer have the variable aperture for g in self.gb.grids_of_dimension(dim_max - 1): d = self.gb.node_props(g) if "fracture" in g.name: d[pp.STATE][ "fracture_aperture"] = self.discr_fracture_aperture.step( d[pp.STATE]["fracture_aperture"], d[pp.STATE]["precipitate_star_star"], d[pp.STATE]["precipitate_old"]) if "layer" in g.name: flux_fracture = np.zeros(g.num_cells) solute_fracture = np.zeros(g.num_cells) porosity = np.zeros(g.num_cells) for e, d_e in self.gb.edges_of_node(g): g_m = d_e["mortar_grid"] g_l, g_h = self.gb.nodes_of_edge(e) if g_h.dim < self.gb.dim_max(): # save the flux from the fracture flux_fracture = -g_m.master_to_mortar_avg().T * d_e[ pp.STATE][self.discr_flow.mortar] / g.cell_volumes d_fracture = self.gb.node_props(g_l if "fracture" in g_l.name else g_h) solute_fracture = g_m.slave_to_mortar_avg( ) * d_fracture[pp.STATE]["solute"] else: cell_cell = g_m.mortar_to_master_int( ).T * g_h.cell_faces # the cells are already ordered according to the layer ordering of the cells given by the mortar # map interface_cells = cell_cell.indices d_h = self.gb.node_props(g_h) porosity = d_h[pp.STATE]["porosity"][interface_cells] temperature = d_h[ pp.STATE]["temperature"][interface_cells] lmbda = self.discr_solute_precipitate_reaction.data[ "lambda"](temperature) d[pp.STATE]["layer_aperture"] = self.discr_layer_aperture.step( flux_fracture, porosity, lmbda, self.time, solute_fracture) d[pp.STATE]["layer_porosity"] = self.discr_layer_porosity.step( d[pp.STATE]["layer_porosity"], d[pp.STATE]["precipitate_star_star"], d[pp.STATE]["precipitate_old"]) # ------------------------------------------------------------------------------# def correct_precipitate_solute(self): for g, d in self.gb: vol_star = d[pp.STATE]["porosity_star"] + d[pp.STATE]["fracture_aperture_star"] +\ d[pp.STATE]["layer_porosity_star"] vol = d[pp.STATE]["porosity"] + d[pp.STATE]["fracture_aperture"] + \ d[pp.STATE]["layer_porosity"] d[pp.STATE]["solute"] = d[pp.STATE]["solute_star_star"] * ( vol_star / vol) d[pp.STATE]["precipitate"] = d[ pp.STATE]["precipitate_star_star"] * (vol_star / vol) # ------------------------------------------------------------------------------# def set_old_variables(self): for g, d in self.gb: d[pp.STATE]["temperature_old"] = d[pp.STATE]["temperature"].copy() d[pp.STATE]["solute_old"] = d[pp.STATE]["solute"].copy() d[pp.STATE]["precipitate_old"] = d[pp.STATE]["precipitate"].copy() d[pp.STATE]["porosity_old"] = d[pp.STATE]["porosity"].copy() d[pp.STATE]["fracture_aperture_old"] = d[ pp.STATE]["fracture_aperture"].copy() d[pp.STATE]["layer_aperture_old"] = d[ pp.STATE]["layer_aperture"].copy() d[pp.STATE]["layer_porosity_old"] = d[ pp.STATE]["layer_porosity"].copy() # ------------------------------------------------------------------------------# def set_data(self, param): for g, d in self.gb: data = param["temperature"]["initial"] d[pp.STATE]["temperature"] = data(g, param, param["tol"]) d[pp.STATE]["temperature_star"] = d[pp.STATE]["temperature"].copy() data = param["solute_advection_diffusion"]["initial_solute"] d[pp.STATE]["solute"] = data(g, param, param["tol"]) data = param["solute_advection_diffusion"]["initial_precipitate"] d[pp.STATE]["precipitate"] = data(g, param, param["tol"]) d[pp.STATE]["precipitate_star"] = d[pp.STATE]["precipitate"].copy() data = param["porosity"]["initial"] d[pp.STATE]["porosity_initial"] = data(g, param, param["tol"]) d[pp.STATE]["porosity_star"] = d[ pp.STATE]["porosity_initial"].copy() d[pp.STATE]["porosity"] = d[pp.STATE]["porosity_initial"].copy() data = param["fracture_aperture"]["initial"] d[pp.STATE]["fracture_aperture_initial"] = data( g, param, param["tol"]) d[pp.STATE]["fracture_aperture_star"] = d[ pp.STATE]["fracture_aperture_initial"].copy() d[pp.STATE]["fracture_aperture"] = d[ pp.STATE]["fracture_aperture_initial"].copy() data = param["layer_aperture"]["initial"] d[pp.STATE]["layer_aperture_initial"] = data( g, param, param["tol"]) d[pp.STATE]["layer_aperture_star"] = d[ pp.STATE]["layer_aperture_initial"].copy() d[pp.STATE]["layer_aperture"] = d[ pp.STATE]["layer_aperture_initial"].copy() data = param["layer_porosity"]["initial"] d[pp.STATE]["layer_porosity_initial"] = data( g, param, param["tol"]) d[pp.STATE]["layer_porosity_star"] = d[ pp.STATE]["layer_porosity_initial"].copy() d[pp.STATE]["layer_porosity"] = d[ pp.STATE]["layer_porosity_initial"].copy() vol = d[pp.STATE]["porosity"] + d[pp.STATE]["fracture_aperture"] +\ d[pp.STATE]["layer_aperture"] * d[pp.STATE]["layer_porosity"] d[pp.STATE]["porosity_aperture_times_solute"] = vol * d[ pp.STATE]["solute"] d[pp.STATE]["porosity_aperture_times_precipitate"] = vol * d[ pp.STATE]["precipitate"] d[pp.STATE]["pressure"] = np.zeros(g.num_cells) d[pp.STATE]["P0_darcy_flux"] = np.zeros((3, g.num_cells)) for e, d in self.gb.edges(): d[pp.STATE][self.discr_flow.mortar] = np.zeros( d["mortar_grid"].num_cells) # set the old variables self.set_old_variables() # extract the initialized variables, useful for setting the data ###self.extract() # set now the data for each scheme self.discr_flow.set_data(param["flow"], param["time"]) self.discr_temperature.set_data(param["temperature"], param["time"]) self.discr_solute_advection_diffusion.set_data( param["solute_advection_diffusion"], param["time"]) self.discr_solute_precipitate_reaction.set_data( param["solute_precipitate_reaction"], param["time"]) self.discr_porosity.set_data(param["porosity"]) self.discr_fracture_aperture.set_data(param["fracture_aperture"]) self.discr_layer_aperture.set_data(param["layer_aperture"], param["time"]) self.discr_layer_porosity.set_data(param["layer_porosity"]) # ------------------------------------------------------------------------------# def compute_composite_variables(self): for g, d in self.gb: vol = d[pp.STATE]["porosity"] + d[pp.STATE]["fracture_aperture"] +\ d[pp.STATE]["layer_aperture"] * d[pp.STATE]["layer_porosity"] d[pp.STATE]["porosity_aperture_times_solute"] = vol * d[ pp.STATE]["solute"] d[pp.STATE]["porosity_aperture_times_precipitate"] = vol * d[ pp.STATE]["precipitate"] # ------------------------------------------------------------------------------# def vars_to_save(self): name = [ "solute", "precipitate", "porosity", "fracture_aperture", "layer_aperture", "layer_porosity", "temperature" ] name += [ "porosity_aperture_times_solute", "porosity_aperture_times_precipitate", "fracture", "layer" ] return name + [self.discr_flow.pressure, self.discr_flow.P0_flux] # ------------------------------------------------------------------------------# def one_step_splitting_scheme(self, time): # save the time of the current step self.time = time # POINT 1) extrapolate the precipitate to get a better estimate of porosity self.compute_precipitate_temperature_star() # POINT 2) compute the porosity and aperture star for both the fracture and layer self.compute_porosity_aperture_star() # -- DO THE FLOW PART -- # # POINT 3) update the data from the previous time step self.discr_flow.update_data() # POINT 4) solve the flow part self.compute_flow() # -- DO THE HEAT PART -- # # set the flux and update the data from the previous time step self.discr_temperature.set_flux(self.discr_flow.flux, self.discr_flow.mortar) self.discr_temperature.update_data() # POINT 5) solve the temperature part self.compute_temperature() # -- DO THE TRANSPORT PART -- # # set the flux and update the data from the previous time step self.discr_solute_advection_diffusion.set_flux(self.discr_flow.flux, self.discr_flow.mortar) self.discr_solute_advection_diffusion.update_data() # POINT 6) solve the advection and diffusion part to get the intermediate solute solution self.compute_solute_precipitate_advection_diffusion() # POINT 7) Since in the advection-diffusion step we have accounted for porosity changes using # phi_star and aperture_star, the new solute concentration accounts for the change in pore volume, thus, the # precipitate needs to be updated accordingly self.correct_precipitate_with_star() # POINT 8) solve the reaction part self.compute_solute_precipitate_rection() # -- DO THE POROSITY PART -- # # POINT 9) solve the porosity and aperture (fracture and layer) part with the true concentration of precipitate self.compute_porosity_aperture() # POINT 10) finally, we correct the concentrations to account for the difference between the extrapolated # and "true" new porosity to ensure mass conservation self.correct_precipitate_solute() # set the old variables self.set_old_variables() # compute composite variables self.compute_composite_variables()
# simple python code to run the heat module under local bmi-python from __future__ import absolute_import, division, print_function import numpy as np import yaml import matplotlib.pyplot as plt from heat import Heat from bmi_heat import BmiHeat if __name__ == '__main__': # Verify that this code is running print("Running runheat.py") # Create a bmi-heat object bheat = Heat() """ # Write out the temperature array, so I can re-read it later bheat._temperature.tofile("bheat_inittemp.dat") """ # Read in the temperature array, so it's consistent bheat._temperature = np.fromfile("bheat_inittemp.dat").reshape(10,20) # Write out a quick 10x20 floating point array bheat._temperature.astype('float32').tofile("tempcheck.dat") # Create an array with the output of the heat run harr = np.zeros((100, 10, 20)) harr[0, :, :] = bheat._temperature