Exemple #1
0
class FenicsReducedFunctional(ReducedFunctional):
    """
    This class implements a reduced functional that operators on FEniCS Functions
    instead of numpy.arrays for the controls.

    Following parameters are expected:

    :ivar functional: a :class:`PrototypeFunctional` class.
    :ivar controls: a (optionally list of) :class:`dolfin_adjoint.DolfinAdjointControl` object.
    :ivar solver: a :class:`Solver` object.

    This class has a parameter attribute for further adjustments.
    """

    def __init__(self, functional, controls, solver):

        self.solver = solver
        if not isinstance(solver, Solver):
            raise ValueError, "solver argument of wrong type."

        self._functional = functional
        if not isinstance(functional, PrototypeFunctional):
            raise ValueError, "invalid functional argument."

        # Hidden attributes
        self._solver_params = solver.parameters
        self._problem_params = solver.problem.parameters
        self._time_integrator = None

        # Controls
        self.controls = enlisting.enlist(controls)

        # Conform to dolfin-adjoint API
        self.scale = 1
        self.eval_cb_pre = lambda *args: None
        self.eval_cb_post = lambda *args: None
        self.derivative_cb_pre = lambda *args: None
        self.derivative_cb_post = lambda *args: None
        self.replay_cb = lambda *args: None
        self.hessian_cb = lambda *args: None
        self.cache = None
        self.current_func_value = None
        self.hessian = None
        self.functional = Functional(None)


    def evaluate(self, annotate=True):
        """ Computes the functional value by running the forward model. """

        log(INFO, 'Start evaluation of j')
        timer = Timer("j evaluation")

        farm = self.solver.problem.parameters.tidal_farm

        # Configure dolfin-adjoint
        adj_reset()
        parameters["adjoint"]["record_all"] = True

        # Solve the shallow water system and integrate the functional of
        # interest.
        final_only = (not self.solver.problem._is_transient or
                      self._problem_params.functional_final_time_only)
        self.time_integrator = TimeIntegrator(self.solver.problem,
                                              self._functional, final_only)

        for sol in self.solver.solve(annotate=annotate):
            self.time_integrator.add(sol["time"], sol["state"], sol["tf"],
                                     sol["is_final"])

        j = self.time_integrator.integrate()

        timer.stop()

        log(INFO, 'Runtime: %f s.' % timer.elapsed()[0])
        log(INFO, 'j = %e.' % float(j))

        return j


    def __call__(self, value):
        """ Evaluates the reduced functional for the given control value.

        Args:
            value: The point in control space where to perform the Taylor test. Must be of the same type as the Control (e.g. Function, Constant or lists of latter).

        Returns:
            float: The functional value.
        """

        value = enlisting.enlist(value)
        # Update the control values.
        # Note that we do not update the control values on the tape,
        # because OpenTidalFarm reannotates the tape in each iteration.
	for c, v in zip(self.controls, value):
            vec = c.coeff.vector()
            if vec.id() == v.vector().id():
                continue
            vec.zero()
            vec.axpy(1, v.vector())

        return self.evaluate()


    def derivative(self, forget=False, **kwargs):
        """ Computes the first derivative of the functional with respect to its
        controls by solving the adjoint equations. """

        log(INFO, 'Start evaluation of dj')
        timer = Timer("dj evaluation")

        self.functional = self.time_integrator.dolfin_adjoint_functional(self.solver.state)
        dj = compute_gradient(self.functional, self.controls, forget=forget, **kwargs)
        parameters["adjoint"]["stop_annotating"] = False

        log(INFO, "Runtime: " + str(timer.stop()) + " s")

        return enlisting.enlist(dj)
class FenicsReducedFunctional(object):
    """
    Following parameters are expected:

    :ivar functional: a :class:`PrototypeFunctional` class.
    :ivar controls: a (optionally list of) :class:`dolfin_adjoint.DolfinAdjointControl` object.
    :ivar solver: a :class:`Solver` object.

    This class has a parameter attribute for further adjustments.
    """

    def __init__(self, functional, controls, solver):

        self.solver = solver
        if not isinstance(solver, Solver):
            raise ValueError, "solver argument of wrong type."

        self.functional = functional
        if not isinstance(functional, PrototypeFunctional):
            raise ValueError, "invalid functional argument."

        # Hidden attributes
        self._solver_params = solver.parameters
        self._problem_params = solver.problem.parameters
        self._time_integrator = None

        # Controls
        self.controls = enlisting.enlist(controls)

    def evaluate(self, annotate=True):
        """ Return the functional value for the given control values. """

        log(INFO, 'Start evaluation of j')
        timer = dolfin.Timer("j evaluation")

        farm = self.solver.problem.parameters.tidal_farm

        # Configure dolfin-adjoint
        adj_reset()
        dolfin.parameters["adjoint"]["record_all"] = True

        # Solve the shallow water system and integrate the functional of
        # interest.
        final_only = (not self.solver.problem._is_transient or
                      self._problem_params.functional_final_time_only)
        self.time_integrator = TimeIntegrator(self.solver.problem,
                                              self.functional, final_only)

        for sol in self.solver.solve(annotate=annotate):
            self.time_integrator.add(sol["time"], sol["state"], sol["tf"],
                                     sol["is_final"])

        j = self.time_integrator.integrate()

        timer.stop()

        log(INFO, 'Runtime: %f s.' % timer.value())
        log(INFO, 'j = %e.' % float(j))

        return j

    def derivative(self, forget=False, **kwargs):
        """ Computes the first derivative of the functional with respect to its
        controls by solving the adjoint equations. """

        log(INFO, 'Start evaluation of dj')
        timer = dolfin.Timer("dj evaluation")

        J = self.time_integrator.dolfin_adjoint_functional()
        dj = compute_gradient(J, self.controls, forget=forget, **kwargs)
        dolfin.parameters["adjoint"]["stop_annotating"] = False

        log(INFO, "Runtime: " + str(timer.stop()) + " s")

        return dj
class FenicsReducedFunctional(ReducedFunctional):
    """
    Following parameters are expected:

    :ivar functional: a :class:`PrototypeFunctional` class.
    :ivar controls: a (optionally list of) :class:`dolfin_adjoint.DolfinAdjointControl` object.
    :ivar solver: a :class:`Solver` object.

    This class has a parameter attribute for further adjustments.
    """

    def __init__(self, functional, controls, solver):
        self.tic = time.clock()
        
        self.solver = solver
        if not isinstance(solver, Solver):
            raise ValueError, "solver argument of wrong type."

        self.otf_functional = functional
        if not isinstance(functional, PrototypeFunctional):
            raise ValueError, "invalid functional argument."

        # Hidden attributes
        self._solver_params = solver.parameters
        self._problem_params = solver.problem.parameters
        self._time_integrator = None
        
        #Initialise self.prev with j_0 =0
        self.j_prev = 0

        # Controls
        self.controls = enlisting.enlist(controls)
        self.evaluate()
        dolfin_adjoint_functional = self.time_integrator.dolfin_adjoint_functional(self.solver.state)

        super(FenicsReducedFunctional, self).__init__(dolfin_adjoint_functional, controls)

        # Caching variables that store which controls the last forward run was
        # performed
        self.last_m = None
        if self.solver.parameters.dump_period > 0:
            turbine_filename = os.path.join(solver.parameters.output_dir, "turbines.pvd")
            self.turbine_file = File(turbine_filename, "compressed")
        
        

    def evaluate(self, annotate=True):
        """ Return the functional value for the given control values. """

        log(INFO, 'Start evaluation of j')
        timer = dolfin.Timer("j evaluation")

        farm = self.solver.problem.parameters.tidal_farm

        # Configure dolfin-adjoint
        adj_reset()
        dolfin.parameters["adjoint"]["record_all"] = True

        # Solve the shallow water system and integrate the functional of
        # interest.
        final_only = (not self.solver.problem._is_transient or
                      self._problem_params.functional_final_time_only)
        self.time_integrator = TimeIntegrator(self.solver.problem,
                                              self.otf_functional, final_only)

        for sol in self.solver.solve(annotate=annotate):
            self.time_integrator.add(sol["time"], sol["state"], sol["tf"],
                                     sol["is_final"])

        j = self.time_integrator.integrate()
 
        #import ipdb; ipdb.set_trace()
 
 
        # relative step size convergence criteria   
        #if np.abs(j-self.j_prev)/max(np.abs(j),np.abs(self.j_prev),1) <= 10e09:
        #    print "LALALLALALALALALLA"   
        #    #toc = time.clock()
        #    print "Run time:", tic - 3.
        #else:            
        #    self.j_prev=j






        timer.stop()

        log(INFO, 'Runtime: %f s.' % timer.value())
        log(INFO, 'j = %e.' % float(j))

        return j

    def _update_turbine_farm(self):
        """ Update the turbine farm from the flattened parameter array m. """
        farm = self.solver.problem.parameters.tidal_farm

        if farm.turbine_specification.smeared:
            farm._parameters["friction"] = self.controls[0].data().vector()

        #else:
        #    controlled_by = farm.turbine_specification.controls
        #    shift = 0
        #    if controlled_by.friction:
        #        shift = len(farm._parameters["friction"])
        #        farm._parameters["friction"] = m[:shift]
        #    elif controlled_by.dynamic_friction:
        #        shift = len(numpy.reshape(farm._parameters["friction"],-1))
        #        nb_turbines = len(farm._parameters["position"])
        #        farm._parameters["friction"] = (
        #            numpy.reshape(m[:shift], (-1, nb_turbines)).tolist())

        #    if controlled_by.position:
        #        m_pos = m[shift:]
        #        farm._parameters["position"] = (
        #            numpy.reshape(m_pos, (-1,2)).tolist())

        # Update the farm cache.
        farm.update()

    def derivative(self, forget=False, new_optimisation_iteration=True, **kwargs):
        """ Computes the first derivative of the functional with respect to its
        controls by solving the adjoint equations. """
        
        log(INFO, 'Start evaluation of dj')
        timer = dolfin.Timer("dj evaluation") 

        # If any of the parameters changed, the forward model needs to be re-run
        #self.evaluate

        J = self.time_integrator.dolfin_adjoint_functional(self.solver.state)
        #J = self.functional
        dj = compute_gradient(J, self.controls, forget=forget, **kwargs)
        #import ipdb; ipdb.set_trace()
        
        j = self.time_integrator.integrate()
        print "functional value", j
        import ipdb; ipdb.set_trace()
          
        
        
        
 

       
        
        
        dolfin.parameters["adjoint"]["stop_annotating"] = False

        print dj

        log(INFO, "Runtime: " + str(timer.stop()) + " s")

        # We assume that the gradient is computed at and only at the beginning
        # of each new optimisation iteration. Hence, this is the right moment
        # to store the turbine friction field and to increment the optimisation
        # iteration counter.
        if new_optimisation_iteration:
            self.solver.optimisation_iteration += 1
            farm = self.solver.problem.parameters.tidal_farm
            self._update_turbine_farm()
            print "Iteration number:", self.solver.optimisation_iteration
            print "Gradient norm:", np.linalg.norm(dj.vector().array(), np.inf)

            # Set convergence criteria
            eps_dj = 1
            if np.linalg.norm(dj.vector().array(), np.inf) <= eps_dj:
                           
                toc = time.clock()
                print "Run time:", toc- self.tic 
                        
                sys.exit(0)
            else:
                pass            
            

            if (self.solver.parameters.dump_period > 0 and
                farm is not None):
                # A cache hit skips the turbine cache update, so we need
                # trigger it manually.
                #if self._compute_gradient_mem.has_cache(m, forget):
                #    self._update_turbine_farm(m)
                #if farm.turbine_specification.controls.dynamic_friction:
                #    log(WARNING, ("Turbine VTU output not yet implemented for "
                #                  " dynamic turbine control"))
                #else:
                    self.turbine_file << farm.turbine_cache['turbine_field']
                    # Compute the total amount of friction due to turbines
                    if farm.turbine_specification.smeared:
                        log(INFO, "Total amount of friction: %f" %
                            assemble(farm.turbine_cache["turbine_field"]*dx))
        return dj 
class FenicsReducedFunctional(ReducedFunctional):
    """
    This class implements a reduced functional that operators on FEniCS Functions
    instead of numpy.arrays for the controls.

    Following parameters are expected:

    :ivar functional: a :class:`PrototypeFunctional` class.
    :ivar controls: a (optionally list of) :class:`dolfin_adjoint.DolfinAdjointControl` object.
    :ivar solver: a :class:`Solver` object.

    This class has a parameter attribute for further adjustments.
    """
    def __init__(self, functional, controls, solver):

        self.solver = solver
        if not isinstance(solver, Solver):
            raise ValueError, "solver argument of wrong type."

        self._functional = functional
        if not isinstance(functional, PrototypeFunctional):
            raise ValueError, "invalid functional argument."

        # Hidden attributes
        self._solver_params = solver.parameters
        self._problem_params = solver.problem.parameters
        self._time_integrator = None

        # Controls
        self.controls = enlisting.enlist(controls)

        # Conform to dolfin-adjoint API
        self.scale = 1
        self.eval_cb_pre = lambda *args: None
        self.eval_cb_post = lambda *args: None
        self.derivative_cb_pre = lambda *args: None
        self.derivative_cb_post = lambda *args: None
        self.replay_cb = lambda *args: None
        self.hessian_cb = lambda *args: None
        self.cache = None
        self.current_func_value = None
        self.hessian = None
        self.functional = Functional(None)

    def evaluate(self, annotate=True):
        """ Computes the functional value by running the forward model. """

        log(INFO, 'Start evaluation of j')
        timer = Timer("j evaluation")

        farm = self.solver.problem.parameters.tidal_farm

        # Configure dolfin-adjoint
        adj_reset()
        parameters["adjoint"]["record_all"] = True

        # Solve the shallow water system and integrate the functional of
        # interest.
        final_only = (not self.solver.problem._is_transient
                      or self._problem_params.functional_final_time_only)
        self.time_integrator = TimeIntegrator(self.solver.problem,
                                              self._functional, final_only)

        for sol in self.solver.solve(annotate=annotate):
            self.time_integrator.add(sol["time"], sol["state"], sol["tf"],
                                     sol["is_final"])

        j = self.time_integrator.integrate()

        timer.stop()

        log(INFO, 'Runtime: %f s.' % timer.elapsed()[0])
        log(INFO, 'j = %e.' % float(j))

        return j

    def __call__(self, value):
        """ Evaluates the reduced functional for the given control value.

        Args:
            value: The point in control space where to perform the Taylor test. Must be of the same type as the Control (e.g. Function, Constant or lists of latter).

        Returns:
            float: The functional value.
        """

        value = enlisting.enlist(value)
        # Update the control values.
        # Note that we do not update the control values on the tape,
        # because OpenTidalFarm reannotates the tape in each iteration.
        for c, v in zip(self.controls, value):
            vec = c.coeff.vector()
            if vec.id() == v.vector().id():
                continue
            vec.zero()
            vec.axpy(1, v.vector())

        return self.evaluate()

    def derivative(self, forget=False, **kwargs):
        """ Computes the first derivative of the functional with respect to its
        controls by solving the adjoint equations. """

        log(INFO, 'Start evaluation of dj')
        timer = Timer("dj evaluation")

        if not hasattr(self, "time_integrator"):
            self.evaluate()
        self.functional = self.time_integrator.dolfin_adjoint_functional(
            self.solver.state)
        dj = compute_gradient(self.functional,
                              self.controls,
                              forget=forget,
                              **kwargs)
        parameters["adjoint"]["stop_annotating"] = False

        log(INFO, "Runtime: " + str(timer.stop()) + " s")

        return enlisting.enlist(dj)
Exemple #5
0
class FenicsReducedFunctional(object):
    """
    Following parameters are expected:

    :ivar functional: a :class:`PrototypeFunctional` class.
    :ivar controls: a (optionally list of) :class:`dolfin_adjoint.DolfinAdjointControl` object.
    :ivar solver: a :class:`Solver` object.

    This class has a parameter attribute for further adjustments.
    """
    def __init__(self, functional, controls, solver):

        self.solver = solver
        if not isinstance(solver, Solver):
            raise ValueError, "solver argument of wrong type."

        self.functional = functional
        if not isinstance(functional, PrototypeFunctional):
            raise ValueError, "invalid functional argument."

        # Hidden attributes
        self._solver_params = solver.parameters
        self._problem_params = solver.problem.parameters
        self._time_integrator = None

        # Controls
        self.controls = enlisting.enlist(controls)

    def evaluate(self, annotate=True):
        """ Return the functional value for the given control values. """

        log(INFO, 'Start evaluation of j')
        timer = dolfin.Timer("j evaluation")

        farm = self.solver.problem.parameters.tidal_farm

        # Configure dolfin-adjoint
        adj_reset()
        dolfin.parameters["adjoint"]["record_all"] = True

        # Solve the shallow water system and integrate the functional of
        # interest.
        final_only = (not self.solver.problem._is_transient
                      or self._problem_params.functional_final_time_only)
        self.time_integrator = TimeIntegrator(self.solver.problem,
                                              self.functional, final_only)

        for sol in self.solver.solve(annotate=annotate):
            self.time_integrator.add(sol["time"], sol["state"], sol["tf"],
                                     sol["is_final"])

        j = self.time_integrator.integrate()

        timer.stop()

        log(INFO, 'Runtime: %f s.' % timer.elapsed()[0])
        log(INFO, 'j = %e.' % float(j))

        return j

    def derivative(self, forget=False, **kwargs):
        """ Computes the first derivative of the functional with respect to its
        controls by solving the adjoint equations. """

        log(INFO, 'Start evaluation of dj')
        timer = dolfin.Timer("dj evaluation")

        J = self.time_integrator.dolfin_adjoint_functional()
        dj = compute_gradient(J, self.controls, forget=forget, **kwargs)
        dolfin.parameters["adjoint"]["stop_annotating"] = False

        log(INFO, "Runtime: " + str(timer.stop()) + " s")

        return dj