/*--------------------------------------------------------------------------*/
/* ALBERTA:   an Adaptive multi Level finite element toolbox using           */
/*           Bisectioning refinement and Error control by Residual          */
/*           Techniques                                                     */
/*                                                                          */
/* file:     nlprob.c                                                       */
/*                                                                          */
/* description:  solver for an nonlinear elliptic model problem             */
/*                                                                          */
/*               -k \Delta u + \sigma u^4 = f  in \Omega                    */
/*                                      u = g  on \partial \Omega           */
/*                                                                          */
/*               definitions and settings for different problems            */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  authors:   Alfred Schmidt                                               */
/*             Zentrum fuer Technomathematik                                */
/*             Fachbereich 3 Mathematik/Informatik                          */
/*             Universitaet Bremen                                          */
/*             Bibliothekstr. 2                                             */
/*             D-28359 Bremen, Germany                                      */
/*                                                                          */
/*             Kunibert G. Siebert                                          */
/*             Institut fuer Mathematik                                     */
/*             Universitaet Augsburg                                        */
/*             Universitaetsstr. 14                                         */
/*             D-86159 Augsburg, Germany                                    */
/*                                                                          */
/*  http://www.mathematik.uni-freiburg.de/IAM/ALBERTA                        */
/*                                                                          */
/*  (c) by A. Schmidt and K.G. Siebert (1996-2003)                          */
/*                                                                          */
/*--------------------------------------------------------------------------*/

#include "nonlin.h"

static REAL  k = 1.0, sigma = 1.0;

/*--------------------------------------------------------------------------*/
/*  Problem 0:  problem with exact solution                                 */
/*              solution is the `exponential peak'                          */
/*--------------------------------------------------------------------------*/

static REAL u_0(const REAL_D x)
{
  REAL   x2 = SCP_DOW(x,x);
  return(exp(-10.0*x2));
}

static const REAL *grd_u_0(const REAL_D x, REAL_D input)
{
  static REAL_D buffer;
  REAL         *grd = input ? input : buffer;
  REAL          ux = exp(-10.0*SCP_DOW(x,x));
  int           n;

  for (n = 0;  n < DIM_OF_WORLD; n++)
    grd[n] = -20.0*x[n]*ux;

  return(grd);
}

static REAL f_0(const REAL_D x)
{
  REAL  r2 = SCP_DOW(x,x), ux  = exp(-10.0*r2), ux4 = ux*ux*ux*ux;
  return(sigma*ux4 - k*(400.0*r2 - 20.0*DIM_OF_WORLD)*ux);
}

/*--------------------------------------------------------------------------*/
/*  Problem 1:                                                              */
/*  compute a stable and an unstable solution, depending on the inital      */
/*  choice of u_h                                                           */
/*  there is no true solution                                               */
/*--------------------------------------------------------------------------*/

static REAL  U0 = 0.0;

static REAL g_1(const REAL_D x)
{
#if DIM_OF_WORLD == 1
  return(4.0*U0*x[0]*(1.0-x[0]));
#endif
#if DIM_OF_WORLD == 2
  return(16.0*U0*x[0]*(1.0-x[0])*x[1]*(1.0-x[1]));
#endif
#if DIM_OF_WORLD == 3
  return(64.0*U0*x[0]*(1.0-x[0])*x[1]*(1.0-x[1])*x[2]*(1.0-x[2]));
#endif
}

static REAL f_1(const REAL_D x)
{
  return(1.0);
}

/*--------------------------------------------------------------------------*/
/*   Problem 2:                                                             */
/*   physical problem:  heat transport in a thin plate                      */
/*   no true solution known                                                 */
/*--------------------------------------------------------------------------*/


static REAL g2 = 300.0, sigma_uext4 = 0.0;
static REAL g_2(const REAL_D x)
{
  return(g2);
}

static REAL f_2(const REAL_D x)
{
  if (x[0] >= -0.25  &&  x[0] <= 0.25
#if DIM_MAX > 1
      &&  x[1] >= -0.25  &&  x[1] <= 0.25
#endif
  )
    return(150.0 + sigma_uext4);
  else
    return(sigma_uext4);
}

/*--------------------------------------------------------------------------*/
/*  init_problem:                                                           */
/*    initialize k and sigma, adjust function pointers and the read macro   */
/*    triangulation                                                         */
/*--------------------------------------------------------------------------*/

const PROB_DATA *init_problem(void)
{
  FUNCNAME("init_problem");
  static PROB_DATA prob_data;
  int              pn = 2;

  GET_PARAMETER(1, "problem number", "%d", &pn);
  switch (pn)
  {
  case 0:   /*---  problem with known true solution  -----------------------*/
    k = 1.0;
    sigma = 1.0;

    prob_data.g = u_0;
    prob_data.f = f_0;

    prob_data.u = u_0;
    prob_data.grd_u = grd_u_0;

    prob_data.data = read_macro("Macro/macro-big.amc");
    break;
  case 1:   /*---  problem for computing a stable and an unstable sol.  ----*/
    k = 1.0;
    sigma = 1.0;

    prob_data.g = g_1;
    prob_data.f = f_1;

    prob_data.u0 = g_1;
    GET_PARAMETER(1, "U0", "%f", &U0);

    prob_data.data = read_macro("Macro/macro.amc");
    break;
  case 2:   /*---  physical problem  ---------------------------------------*/
    k = 2.0;
    sigma = 5.67e-8;
    sigma_uext4 = sigma*273*273*273*273;

    prob_data.g = g_2;
    prob_data.f = f_2;
    prob_data.data = read_macro("Macro/macro-big.amc");
    break;
  default:
    ERROR_EXIT("no problem defined with problem no. %d\n", pn);
  }
  prob_data.k = k;
  prob_data.sigma = sigma;

  return &prob_data;
}
