⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 homotopy.cpp

📁 利用C
💻 CPP
字号:
// Copyright (C) 2005-2008 Anders Logg.// Licensed under the GNU LGPL Version 2.1.//// Modified by Garth N. Wells, 2006.//// First added:  2005// Last changed: 2008-04-22#include <stdio.h>#include <limits>#include <dolfin/common/constants.h>#include <dolfin/log/dolfin_log.h>#include <dolfin/math/dolfin_math.h>#include <dolfin/parameter/parameters.h>#include "ComplexODE.h"#include "HomotopyJacobian.h"#include "HomotopyODE.h"#include "Homotopy.h"using namespace dolfin;//-----------------------------------------------------------------------------Homotopy::Homotopy(uint n)  : tol(0), n(n), M(0), maxiter(0), maxpaths(0), maxdegree(0),    divtol(0), monitor(false), random(false),     filename(""), mi(0), ci(0), tmp(0), x(2*n),    degree_adjusted("Adjusting degree of equation, maximum reached."){  message("Creating homotopy for system of size %d.", n);    // We should not solve the dual problem  dolfin_set("ODE solve dual problem", false);  // System is implicit  dolfin_set("ODE implicit", true);  // Get divergence tolerance  divtol = dolfin_get("homotopy divergence tolerance");  // Check if we should monitor the homotopy  monitor = dolfin_get("homotopy monitoring");  // Get type of initial data (random or morgan)  random = dolfin_get("homotopy randomize");  if ( random )    message("Using random initial system for homotopy.");  // Get maximum number of iterations  maxiter = dolfin_get("ODE maximum iterations");  // Get maximum number of paths  maxpaths = dolfin_get("homotopy maximum size");  message("Maximum number of homotopy paths is %d.", maxpaths);  // Get maximum degree for a single equation  maxdegree = dolfin_get("homotopy maximum degree");  message("Maximum degree for a single equations is %d.", maxdegree);  // Get filename  filename = static_cast<std::string>(dolfin_get("homotopy solution file name"));  FILE* fp = fopen(filename.c_str(), "w");  fclose(fp);  // FIXME: Maybe this should be a parameter?  tol = dolfin_get("homotopy solution tolerance");    // Initialize array mi  mi = new uint[n];  for (uint i = 0; i < n; i++)    mi[i] = 0;  // Initialize array ci  ci = new complex[n];  for (uint i = 0; i < n; i++)    ci[i] = 0.0;  // Randomize vector ci  randomize();}//-----------------------------------------------------------------------------Homotopy::~Homotopy(){  if ( mi ) delete [] mi;  if ( ci ) delete [] ci;  if ( tmp ) delete [] tmp;    for (unsigned int i = 0; i < zs.size(); i++)    delete [] zs[i];}//-----------------------------------------------------------------------------void Homotopy::solve(){  // Compute the total number of paths  M = countPaths();  message("Total number of paths is %d.", M);  if ( M > maxpaths )    message("Computing only %d paths as requested.", maxpaths);  char filename[64];  uint num_roots = 0;  for (uint m = 0; m < M; m++)  {    message("\nComputing path number %d out of %d.", m + 1, M);    // Change name of output file for each path    sprintf(filename, "solution_%u.py", m);    dolfin_set("ODE solution file name", filename);    // Compute the component paths from global path number    computePath(m);    // Create and solve ODE    // FIXME: what T should be used for HomotopyODE?    HomotopyODE ode(*this, n, 1.0);    ode.solve();    // Use Newton's method to find the solution    if ( ode.state() == HomotopyODE::endgame )    {      message("Homotopy path converged, using Newton's method to improve solution.");      if ( computeSolution(ode) )      {	num_roots += 1;	saveSolution();      }    }    message("Number of solutions so far: %d (%d dropped).",		zs.size(), num_roots - zs.size());    // Check if we reached the maximum number of paths    if ( m == (maxpaths - 1) )    {      message("Maximum number of paths reached, stopping.");      break;    }  }  message("\nTotal number of solutions found: %d (%d dropped).",	      zs.size(), num_roots - zs.size());}//-----------------------------------------------------------------------------const Array<complex*>& Homotopy::solutions() const{  return zs;}//-----------------------------------------------------------------------------void Homotopy::z0(complex z[]){  for (uint i = 0; i < n; i++)  {    const real pp = static_cast<real>(adjustedDegree(i));    const real mm = static_cast<real>(mi[i]);    const complex c = ci[i];        // Pick root number m of equation z_i^(p + 1) = c_i    real r = std::pow(std::abs(c), 1.0/(pp + 1.0));    real a = std::arg(c) / (pp + 1.0);    z[i] = std::polar(r, a + mm/(pp + 1.0)*2.0*DOLFIN_PI);  }}//-----------------------------------------------------------------------------void Homotopy::G(const complex z[], complex y[]){  // Implement default starting system if not supplied by user  // Compute G_i(z_i) = z_i^(p_i + 1) - c_i  for (uint i = 0; i < n; i++)  {    const uint p = adjustedDegree(i);    const complex zi = z[i];    complex tmp = zi;    for (uint j = 0; j < p; j++)      tmp *= zi;    y[i] = tmp - ci[i];  }}//-----------------------------------------------------------------------------void Homotopy::JG(const complex z[], const complex x[], complex y[]){  // Implement default starting system if not supplied by user    // Compute (G'(z)*x)_i = (p_i + 1) z_i^p_i x_i  for (uint i = 0; i < n; i++)  {    const uint p = adjustedDegree(i);    const complex zi = z[i];    complex tmp = static_cast<complex>(p + 1);    for (uint j = 0; j < p ; j++)      tmp *= zi;        y[i] = tmp * x[i];  }}//-----------------------------------------------------------------------------void Homotopy::modify(complex z[]){  // Do nothing}//-----------------------------------------------------------------------------bool Homotopy::verify(const complex z[]){  // Initialize temporary array  if ( !tmp )    tmp = new complex[n];  // Evaluate y = F(z)  F(z, tmp);  // Check size of y  real Fmax = 0.0;  for (unsigned int i = 0; i < n; i++)    Fmax = std::max(Fmax, std::abs(tmp[i]));    return Fmax < 2.0*tol;}//-----------------------------------------------------------------------------dolfin::uint Homotopy::adjustedDegree(uint i){  uint q = degree(i);  if ( q > maxdegree )  {    degree_adjusted();    q = maxdegree;  }  return q;}//-----------------------------------------------------------------------------dolfin::uint Homotopy::countPaths(){  uint product = 1;  for (uint i = 0; i < n; i++)  {    if ( (adjustedDegree(i) + 1) * product <= product )    {      const int max_paths = std::numeric_limits<int>::max();      error("Reached maximum number of homotopy paths (%d).", max_paths);    }        product *= (adjustedDegree(i) + 1);  }  return product;}//-----------------------------------------------------------------------------void Homotopy::computePath(uint m){  // The path number for each component can vary between 0 and p_i + 1,  // and we need to compute the local path number for a given component  // from the global path number which varies between 0 and the product of  // all p_i + 1. This algorithm is copied from FFC (compiler.multiindex).    uint posvalue = M;  uint sum = m;  for (uint i = 0; i < n; i++)  {    const uint dim = adjustedDegree(i) + 1;    posvalue /= dim;    const uint digit = sum / posvalue;    mi[i] = digit;    sum -= digit * posvalue;  }}//-----------------------------------------------------------------------------bool Homotopy::computeSolution(HomotopyODE& ode){  // Create right-hand side and increment vector  uBlasVector F(2*n), dx(2*n);  // Create matrix-free Jacobian  HomotopyJacobian J(ode, x);    cout << "Starting point:     x = ";  x.disp();  // Solve system using Newton's method  for (uint iter = 0; iter < maxiter; iter++)  {    // Evaluate right-hand side at current x    feval(F, ode);    // Check convergence    real r = F.norm(linf);    //cout << "r = " << r << ": x = "; x.disp();    if ( r < tol )    {      cout << "Solution converged: x = ";      x.disp();      return true;    }    // Solve linear system    solver.solve(J, dx, F);    // Subtract increment    x -= dx;  }  warning("Solution did not converge.");  return false;}//-----------------------------------------------------------------------------void Homotopy::saveSolution(){  // Copy values to complex array  complex* z = new complex[n];  for (uint i = 0; i < n; i++)    z[i] = complex(x[2*i], x[2*i + 1]);  // Allow user to modify solution  modify(z);  // Check if solution is valid  if ( !verify(z) )  {    message("Verification of solution failed, dropping solution.");    delete [] z;    return;  }  // Save solution  message("Solution verified, keeping solution.");  zs.push_back(z);  // Save solution to file  FILE* fp = fopen(filename.c_str(), "a");  for (uint i = 0; i < n; i++)    fprintf(fp, "%.15e %.15e ", z[i].real(), z[i].imag());  fprintf(fp, "\n");  fclose(fp);}//-----------------------------------------------------------------------------void Homotopy::randomize(){  // Choose values for c  for (uint i = 0; i < n; i++)  {    if ( random )    {      // Randomize each c in the unit circle      const real r = rand();      const real a = 2.0*DOLFIN_PI*rand();      const complex c = std::polar(r, a);      ci[i] = c;    }    else    {      // Choice from Morgan's paper      const complex c(0.00143289 + static_cast<real>(i), 0.983727);      ci[i] = c;    }  }  //ci[0] = complex(-2.831791604946104e-02, -6.860112583567136e-01);  //ci[1] = complex(8.464610889887528e-02, 7.660579271509420e-02);  // Write to file  FILE* fp = fopen("initialsystem.data", "w");  for (uint i = 0; i < n; i++)    fprintf(fp, "%.15e %.15e ", ci[i].real(), ci[i].imag());  fprintf(fp, "\n");  fclose(fp);}//-----------------------------------------------------------------------------void Homotopy::feval(uBlasVector& F, ComplexODE& ode){  // Reuse the right-hand side of the ODE so we don't have to reimplement  // the mapping from complex to real numbers  // Evaluate F at current x  ode.f(x, 0.0, F);}//-----------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -