expand extended preprocessor + first implementation of Petsc interface

time-shift
Michel Juillard 2015-08-27 10:00:27 +02:00
parent 154980ec8c
commit c9f771973d
8 changed files with 832 additions and 12 deletions

View File

@ -0,0 +1,25 @@
include ${PETSC_DIR}/lib/petsc/conf/variables
include ${PETSC_DIR}/lib/petsc/conf/rules
CFLAGS = ${PETSC_CC_INCLUDES} -I. -I..
CPPFLAGS = ${PETSC_CC_INCLUDES} -I. -I..
all: main_tao_1
main_tao_1: main_tao_1.o pf_jacobian.o example1.o example1_steadystate.o example1_first_derivatives.o example1_residuals.o
${CLINKER} -o main_tao_1 main_tao_1.o example1.o example1_steadystate.o example1_residuals.o example1_first_derivatives.o ${PETSC_LIB} -lstdc++ -lm
snes_1: snes_1.o example1.o example1_steadystate.o example1_first_derivatives.o example1_residuals.o
${CLINKER} -o snes_1 snes_1.o example1.o example1_steadystate.o example1_residuals.o example1_first_derivatives.o ${PETSC_LIB} -lstdc++ -lm
main_tao_1.o: main_tao_1.cc main_tao.h ../dynare_cpp_driver.hh
snes_1.o: snes_1.cc main_tao.h ../dynare_cpp_driver.hh
pf_jacobian.o: pf_jacobian.cc main_tao.h
example1.o: example1.cc ../dynare_cpp_driver.hh
example1_steadystate.o: example1_steadystate.cc
example1_residuals.o: example1_residuals.c
example1_first_derivatives.o: example1_first_derivatives.c
example1.cc: example1.mod
/home/michel/dynare/git/master/matlab/preprocessor64/dynare_m example1.mod output=first language=C++
example1_residuals.c: example1.mod
/home/michel/dynare/git/master/matlab/preprocessor64/dynare_m example1.mod output=first language=C++

View File

@ -1,5 +1,5 @@
// Example 1 from Collard's guide to Dynare
var y, c, k, a, h, b;
var h, c, y, k, a, b;
varexo e, u;
parameters beta, rho, alpha, delta, theta, psi, tau;
@ -15,11 +15,11 @@ theta = 2.95;
phi = 0.1;
model;
c*theta*h^(1+psi)=(1-alpha)*y;
k = beta*(((exp(b)*c)/(exp(b(+1))*c(+1)))
*(exp(b(+1))*alpha*y(+1)+(1-delta)*k));
y = exp(a)*(k(-1)^alpha)*(h^(1-alpha));
k = exp(b)*(y-c)+(1-delta)*k(-1);
c*theta*exp(h)^(1+psi)=(1-alpha)*y;
exp(k) = beta*(((exp(b)*c)/(exp(b(+1))*c(+1)))
*(exp(b(+1))*alpha*y(+1)+(1-delta)*exp(k)));
y = exp(a)*(exp(k(-1))^alpha)*(exp(h)^(1-alpha));
exp(k) = exp(b)*(y-c)+(1-delta)*exp(k(-1));
a = rho*a(-1)+tau*b(-1) + e;
b = tau*a(-1)+rho*b(-1) + u;
end;
@ -30,10 +30,10 @@ b = 0;
k_h = ((1-beta*(1-delta))/(beta*alpha))^(1/(alpha-1));
y_h = k_h^alpha;
c_h = y_h - delta*k_h;
h = (y_h*(1-alpha)/(c_h*theta))^(1/(1+psi));
k = k_h*h;
c = c_h*h;
y = y_h*h;
h = log((y_h*(1-alpha)/(c_h*theta))^(1/(1+psi)));
k = log(k_h*exp(h));
c = c_h*exp(h);
y = y_h*exp(h);
end;
shocks;

685
others/cpp/tests/snes_1.cc Normal file
View File

@ -0,0 +1,685 @@
#include <iostream>
#include "../dynare_cpp_driver.hh"
#include <petscdm.h>
#include <petscdmda.h>
#include <petscsnes.h>
#include "main_tao.h"
DynareInfo *preprocessorOutput(void);
PetscErrorCode FormFunction(SNES snes,Vec y,Vec f,void *ctx);
PetscErrorCode FormJacobian(SNES snes,Vec y,Mat J, Mat B,void *ctx);
PetscErrorCode Monitor(SNES,PetscInt,PetscReal,void*);
PetscErrorCode PreCheck(SNESLineSearch,Vec,Vec,PetscBool*,void*);
PetscErrorCode PostCheck(SNESLineSearch,Vec,Vec,Vec,PetscBool*,PetscBool*,void*);
PetscErrorCode PostSetSubKSP(SNESLineSearch,Vec,Vec,Vec,PetscBool*,PetscBool*,void*);
PetscErrorCode MatrixFreePreconditioner(PC,Vec,Vec);
static char help[] = "Testing";
/*
User-defined context for monitoring
*/
typedef struct {
PetscViewer viewer;
} MonitorCtx;
/*
User-defined context for checking candidate iterates that are
determined by line search methods
*/
typedef struct {
Vec last_step; /* previous iterate */
PetscReal tolerance; /* tolerance for changes between successive iterates */
AppCtx *user;
} StepCheckCtx;
typedef struct {
PetscInt its0; /* num of prevous outer KSP iterations */
} SetSubKSPCtx;
#undef __FUNCT__
#define __FUNCT__ "main"
int main(int argc, char **argv)
{
DynareInfo model_info;
int endo_nbr = model_info.get_endo_nbr();
int exo_nbr = model_info.get_exo_nbr();
double *params = model_info.get_params_data();
// Steady state
double *steady_state = new double[endo_nbr];
int info;
steadystate(NULL,params, steady_state, &info);
vector<int> NNZDerivatives = model_info.get_NNZDerivatives();
AppCtx user; /* user-defined work context */
user.exogenous = new double[exo_nbr];
user.params = params;
user.steady_state = steady_state;
user.periods = 40;
user.first_col = endo_nbr;
user.endo_nbr = endo_nbr;
user.exo_nbr = exo_nbr;
user.row_ptr = new int[endo_nbr+1];
user.nnz = NNZDerivatives[0];
user.col_ptr = new int[NNZDerivatives[0]];
user.val_ptr = new double[NNZDerivatives[0]];
user.initial_values = new double[user.endo_nbr];
user.terminal_values = new double[user.endo_nbr];
for (int i=0; i < user.endo_nbr; ++i)
{
user.initial_values[i] = user.steady_state[i];
user.terminal_values[i] = user.steady_state[i];
}
/* Initialize PETSc */
PetscInitialize(&argc, &argv, (char *)0, help);
PetscErrorCode ierr;
/* Get number of processors */
PetscInt size;
ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);
/* Set periods a multiple of processor nbr */
user.periods = size*ceil((double)user.periods/size);
user.nb_row_x = user.periods + 1;
user.X = new double[user.nb_row_x*user.exo_nbr];
for(double* px=user.X; px < user.X+user.nb_row_x*user.exo_nbr; px++) *px = 0.0;
user.X[1] = 0.01;
user.X[1+user.nb_row_x] = 0.01;
std::cout << size << " " << user.periods << " " << std::endl;
PetscInt N = user.periods*user.endo_nbr;
/* Create DMA */
DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_GHOSTED,N,1,user.endo_nbr,NULL,&user.da);
/* Allocate vector and Jacobian matrix */\
Vec Y, R;
DMCreateGlobalVector(user.da,&Y);
VecDuplicate(Y,&R);
Mat J ;
ierr = MatCreate(PETSC_COMM_WORLD,&J);CHKERRQ(ierr);
ierr = MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,N,N);CHKERRQ(ierr);
ierr = MatSetFromOptions(J);CHKERRQ(ierr);
ierr = MatSetUp(J);CHKERRQ(ierr);
/*
Get local grid boundaries (for 1-dimensional DMDA):
xs, xm - starting grid index, width of local grid (no ghost points)
*/
PetscInt xs, xm, xsg, xmg;
DMDAGetCorners(user.da,&xs,NULL,NULL,&xm,NULL,NULL);
std::cout << xs << " " << xm << std::endl;
DMDAGetGhostCorners(user.da,&xsg,NULL,NULL,&xmg,NULL,NULL);
std::cout << "ghost " << xsg << " " << xmg << std::endl;
/*
Get pointers to vector data
*/
PetscScalar *YY;
DMDAVecGetArray(user.da,Y,&YY);
/*
Compute local vector entries
*/
for (int i=xs; i<xs+xm; i += user.endo_nbr)
for (int j=0; j < user.endo_nbr; j++)
YY[i+j] = steady_state[j];
/*
Restore vectors
*/
DMDAVecRestoreArray(user.da,Y,&YY);
SNES snes;
ierr = SNESCreate(PETSC_COMM_WORLD,&snes);CHKERRQ(ierr);
// SNES snes;
SNESLineSearch linesearch; /* SNESLineSearch context */
MonitorCtx monP; /* monitoring context */
StepCheckCtx checkP; /* step-checking context */
SetSubKSPCtx checkP1;
PetscBool pre_check,post_check,post_setsubksp; /* flag indicating whether we're checking candidate iterates */
PetscReal abstol,rtol,stol,norm;
PetscInt its,maxit,maxf;
PetscBool flg;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Create nonlinear solver context
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ierr = SNESCreate(PETSC_COMM_WORLD,&snes);CHKERRQ(ierr);
/*
Set function evaluation routine and vector. Whenever the nonlinear
solver needs to compute the nonlinear function, it will call this
routine.
- Note that the final routine argument is the user-defined
context that provides application-specific data for the
function evaluation routine.
*/
ierr = SNESSetFunction(snes,R,FormFunction,&user);CHKERRQ(ierr);
/*
Set Jacobian matrix data structure and default Jacobian evaluation
routine. Whenever the nonlinear solver needs to compute the
Jacobian matrix, it will call this routine.
- Note that the final routine argument is the user-defined
context that provides application-specific data for the
Jacobian evaluation routine.
*/
ierr = SNESSetJacobian(snes,J,J,FormJacobian,&user);CHKERRQ(ierr);
/*
Optional allow user provided preconditioner
*/
ierr = PetscOptionsHasName(NULL,"-user_precond",&flg);CHKERRQ(ierr);
if (flg) {
KSP ksp;
PC pc;
ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr);
ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
ierr = PCSetType(pc,PCSHELL);CHKERRQ(ierr);
ierr = PCShellSetApply(pc,MatrixFreePreconditioner);CHKERRQ(ierr);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Customize nonlinear solver; set runtime options
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
Set an optional user-defined monitoring routine
*/
ierr = PetscViewerDrawOpen(PETSC_COMM_WORLD,0,0,0,0,400,400,&monP.viewer);CHKERRQ(ierr);
ierr = SNESMonitorSet(snes,Monitor,&monP,0);CHKERRQ(ierr);
/*
Set names for some vectors to facilitate monitoring (optional)
*/
ierr = PetscObjectSetName((PetscObject)Y,"Approximate Solution");CHKERRQ(ierr);
// ierr = PetscObjectSetName((PetscObject)U,"Exact Solution");CHKERRQ(ierr);
/*
Set SNES/KSP/KSP/PC runtime options, e.g.,
-snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
*/
ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
/*
Set an optional user-defined routine to check the validity of candidate
iterates that are determined by line search methods
*/
ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
ierr = PetscOptionsHasName(NULL,"-post_check_iterates",&post_check);CHKERRQ(ierr);
if (post_check) {
ierr = PetscPrintf(PETSC_COMM_WORLD,"Activating post step checking routine\n");CHKERRQ(ierr);
ierr = SNESLineSearchSetPostCheck(linesearch,PostCheck,&checkP);CHKERRQ(ierr);
ierr = VecDuplicate(Y,&(checkP.last_step));CHKERRQ(ierr);
checkP.tolerance = 1.0;
checkP.user = &user;
ierr = PetscOptionsGetReal(NULL,"-check_tol",&checkP.tolerance,NULL);CHKERRQ(ierr);
}
ierr = PetscOptionsHasName(NULL,"-post_setsubksp",&post_setsubksp);CHKERRQ(ierr);
if (post_setsubksp) {
ierr = PetscPrintf(PETSC_COMM_WORLD,"Activating post setsubksp\n");CHKERRQ(ierr);
ierr = SNESLineSearchSetPostCheck(linesearch,PostSetSubKSP,&checkP1);CHKERRQ(ierr);
}
ierr = PetscOptionsHasName(NULL,"-pre_check_iterates",&pre_check);CHKERRQ(ierr);
if (pre_check) {
ierr = PetscPrintf(PETSC_COMM_WORLD,"Activating pre step checking routine\n");CHKERRQ(ierr);
ierr = SNESLineSearchSetPreCheck(linesearch,PreCheck,&checkP);CHKERRQ(ierr);
}
/*
Print parameters used for convergence testing (optional) ... just
to demonstrate this routine; this information is also printed with
the option -snes_view
*/
ierr = SNESGetTolerances(snes,&abstol,&rtol,&stol,&maxit,&maxf);CHKERRQ(ierr);
ierr = PetscPrintf(PETSC_COMM_WORLD,"atol=%g, rtol=%g, stol=%g, maxit=%D, maxf=%D\n",(double)abstol,(double)rtol,(double)stol,maxit,maxf);CHKERRQ(ierr);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Evaluate initial guess; then solve nonlinear system
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
Note: The user should initialize the vector, x, with the initial guess
for the nonlinear solver prior to calling SNESSolve(). In particular,
to employ an initial guess of zero, the user should explicitly set
this vector to zero by calling VecSet().
*/
ierr = SNESSolve(snes,NULL,Y);CHKERRQ(ierr);
ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr);
ierr = PetscPrintf(PETSC_COMM_WORLD,"Number of SNES iterations = %D\n",its);CHKERRQ(ierr);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Check solution and clean up
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
Free work space. All PETSc objects should be destroyed when they
are no longer needed.
*/
ierr = PetscViewerDestroy(&monP.viewer);CHKERRQ(ierr);
if (post_check) {ierr = VecDestroy(&checkP.last_step);CHKERRQ(ierr);}
ierr = SNESDestroy(&snes);CHKERRQ(ierr);
ierr = DMDestroy(&user.da);CHKERRQ(ierr);
ierr = MatDestroy(&J);CHKERRQ(ierr);
ierr = VecDestroy(&Y);CHKERRQ(ierr);
ierr = VecDestroy(&R);CHKERRQ(ierr);
ierr = PetscFinalize();CHKERRQ(ierr);
PetscFunctionReturn(0);
}
PetscErrorCode FormFunction(SNES snes,Vec y,Vec f,void *ctx)
{
AppCtx *user = (AppCtx*) ctx;
DM da = user->da;
PetscScalar *yy,*ff;
PetscInt M,ys,ym;
Vec ylocal;
DMGetLocalVector(da,&ylocal);
/*
Scatter ghost points to local vector, using the 2-step process
DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
By placing code between these two statements, computations can
be done while messages are in transition.
*/
DMGlobalToLocalBegin(da,y,INSERT_VALUES,ylocal);
DMGlobalToLocalEnd(da,y,INSERT_VALUES,ylocal);
/*
Get pointers to vector data.
- The vector xlocal includes ghost point; the vectors x and f do
NOT include ghost points.
- Using DMDAVecGetArray() allows accessing the values using global ordering
*/
DMDAVecGetArray(da,ylocal,&yy);
DMDAVecGetArray(da,f,&ff);
/*
Get local grid boundaries (for 1-dimensional DMDA):
ys, ym - starting grid index, width of local grid (no ghost points)
*/
DMDAGetCorners(da,&ys,NULL,NULL,&ym,NULL,NULL);
DMDAGetInfo(da,NULL,&M,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
/*
Set function values for boundary points; define local interior grid point range:
xsi - starting interior grid index
xei - ending interior grid index
*/
if (ys == 0) /* left boundary */
{
PetscReal *y1 = new PetscReal[3*user->endo_nbr];
for (int i=0; i < user->endo_nbr; ++i) y1[i] = user->initial_values[i];
for (int i=0; i < 2*user->endo_nbr; ++i) y1[i+user->endo_nbr] = yy[i];
Residuals(y1, user->X, user->nb_row_x, user->params, user->steady_state, 1, ff);
ys += user->endo_nbr;
ym -= user->endo_nbr;
}
/*
Compute function over locally owned part of the grid (interior points only)
*/
while ( (ym >= user->endo_nbr) && (ys + 2*user->endo_nbr <= M) )
{
int it = ys/user->endo_nbr + 2;
Residuals(yy+ys-user->endo_nbr, user->X, user->nb_row_x, user->params, user->steady_state, it, ff+ys);
ys += user->endo_nbr;
ym -= user->endo_nbr;
}
if ( (ym >= user->endo_nbr) && (ys + 2*user->endo_nbr >= M) )
{
int it = ys/user->endo_nbr + 1;
PetscReal *y1 = new PetscReal[3*user->endo_nbr];
for (int i=0; i < 2*user->endo_nbr; ++i) y1[i] = yy[ys+i-user->endo_nbr];
for (int i=0; i < user->endo_nbr; ++i) y1[i+2*user->endo_nbr] = user->terminal_values[i];
Residuals(y1, user->X, user->nb_row_x, user->params, user->steady_state, it, ff+ys);
}
/*
Restore vectors
*/
DMDAVecRestoreArray(da,ylocal,&yy);
DMDAVecRestoreArray(da,f,&ff);
DMRestoreLocalVector(da,&ylocal);
return(0);
}
PetscErrorCode FormJacobian(SNES snes,Vec y,Mat J, Mat B,void *ctx)
{
AppCtx *user = (AppCtx*) ctx;
DM da = user->da;
PetscScalar *yy;
PetscInt M,ys,ym,ierr;
Vec ylocal;
DMGetLocalVector(da,&ylocal);
/*
Scatter ghost points to local vector, using the 2-step process
DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
By placing code between these two statements, computations can
be done while messages are in transition.
*/
DMGlobalToLocalBegin(da,y,INSERT_VALUES,ylocal);
DMGlobalToLocalEnd(da,y,INSERT_VALUES,ylocal);
/*
Get pointers to vector data.
- The vector xlocal includes ghost point; the vectors x and f do
NOT include ghost points.
- Using DMDAVecGetArray() allows accessing the values using global ordering
*/
DMDAVecGetArray(da,ylocal,&yy);
/*
Get local grid boundaries (for 1-dimensional DMDA):
ys, ym - starting grid index, width of local grid (no ghost points)
*/
DMDAGetCorners(da,&ys,NULL,NULL,&ym,NULL,NULL);
DMDAGetInfo(da,NULL,&M,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
/*
Set function values for boundary points; define local interior grid point range:
xsi - starting interior grid index
xei - ending interior grid index
*/
int row = 0;
if (ys == 0) /* left boundary */
{
PetscReal *y1 = new PetscReal[3*user->endo_nbr];
for (int i=0; i < user->endo_nbr; ++i) y1[i] = user->initial_values[i];
for (int i=0; i < 2*user->endo_nbr; ++i) y1[i+user->endo_nbr] = yy[i];
FirstDerivatives(y1, user->X, user->nb_row_x, user->params, user->steady_state, 1, NULL, user->row_ptr, user->col_ptr, user->val_ptr);
for (int* r=user->row_ptr; r < user->row_ptr+user->endo_nbr; r++)
{
int first_col = 0;
int ncol = 0;
int *pc = user->col_ptr + *r;
while(*(pc) < user->endo_nbr)
{
++first_col;
++pc;
}
while(pc < ((user->col_ptr)+*(r+1)))
{
if (*pc < 3*(user->endo_nbr))
{
++ncol;
*pc -= user->endo_nbr;
}
++pc;
}
ierr = MatSetValues(J,1,&row,ncol,user->col_ptr + *r + first_col,user->val_ptr + *r + first_col,INSERT_VALUES);
CHKERRQ(ierr);
++row;
}
ys += user->endo_nbr;
ym -= user->endo_nbr;
}
/*
Compute function over locally owned part of the grid (interior points only)
*/
while ( (ym >= user->endo_nbr) && (ys + 2*user->endo_nbr <= M) )
{
int it = ys/user->endo_nbr + 2;
FirstDerivatives(yy+ys-user->endo_nbr, user->X, user->nb_row_x, user->params, user->steady_state, it, NULL, user->row_ptr, user->col_ptr, user->val_ptr);
for (int* r=user->row_ptr; r < user->row_ptr+user->endo_nbr; r++)
{
int ncol = 0;
for(int *pc = user->col_ptr + *r; pc < user->col_ptr + *(r+1); ++pc)
if(*pc < 3*user->endo_nbr)
{
*pc += ys - user->endo_nbr;
++ncol;
}
ierr = MatSetValues(J,1,&row,ncol,user->col_ptr + *r,user->val_ptr + *r,INSERT_VALUES);
CHKERRQ(ierr);
++row;
}
ys += user->endo_nbr;
ym -= user->endo_nbr;
}
if ( (ym >= user->endo_nbr) && (ys + 2*user->endo_nbr >= M) )
{
int it = ys/user->endo_nbr + 1;
PetscReal *y1 = new PetscReal[3*user->endo_nbr];
for (int i=0; i < 2*user->endo_nbr; ++i) y1[i] = yy[ys+i-user->endo_nbr];
for (int i=0; i < user->endo_nbr; ++i) y1[i+2*user->endo_nbr] = user->terminal_values[i];
FirstDerivatives(y1, user->X, user->nb_row_x, user->params, user->steady_state, it, NULL, user->row_ptr, user->col_ptr, user->val_ptr);
for (int* r=user->row_ptr; r < user->row_ptr+user->endo_nbr; r++)
{
int *pc = user->col_ptr + *r;
int ncol = 0;
while((*pc < 2*user->endo_nbr) && (pc < user->col_ptr + *(r+1)))
{
++ncol;
*pc += ys - user->endo_nbr;
++pc;
}
ierr = MatSetValues(J,1,&row,ncol,user->col_ptr + *r,user->val_ptr + *r,INSERT_VALUES);
CHKERRQ(ierr);
++row;
}
}
/*
Restore vectors
*/
ierr = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
DMDAVecRestoreArray(da,ylocal,&yy);
DMRestoreLocalVector(da,&ylocal);
ierr = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
return(0);
}
#undef __FUNCT__
#define __FUNCT__ "Monitor"
/*
Monitor - Optional user-defined monitoring routine that views the
current iterate with an x-window plot. Set by SNESMonitorSet().
Input Parameters:
snes - the SNES context
its - iteration number
norm - 2-norm function value (may be estimated)
ctx - optional user-defined context for private data for the
monitor routine, as set by SNESMonitorSet()
Note:
See the manpage for PetscViewerDrawOpen() for useful runtime options,
such as -nox to deactivate all x-window output.
*/
PetscErrorCode Monitor(SNES snes,PetscInt its,PetscReal fnorm,void *ctx)
{
PetscErrorCode ierr;
MonitorCtx *monP = (MonitorCtx*) ctx;
Vec x;
PetscFunctionBeginUser;
ierr = PetscPrintf(PETSC_COMM_WORLD,"iter = %D,SNES Function norm %g\n",its,(double)fnorm);CHKERRQ(ierr);
ierr = SNESGetSolution(snes,&x);CHKERRQ(ierr);
ierr = VecView(x,monP->viewer);CHKERRQ(ierr);
PetscFunctionReturn(0);
}
/* ------------------------------------------------------------------- */
#undef __FUNCT__
#define __FUNCT__ "PreCheck"
/*
PreCheck - Optional user-defined routine that checks the validity of
candidate steps of a line search method. Set by SNESLineSearchSetPreCheck().
Input Parameters:
snes - the SNES context
xcurrent - current solution
y - search direction and length
Output Parameters:
y - proposed step (search direction and length) (possibly changed)
changed_y - tells if the step has changed or not
*/
PetscErrorCode PreCheck(SNESLineSearch linesearch,Vec xcurrent,Vec y, PetscBool *changed_y, void * ctx)
{
PetscFunctionBeginUser;
*changed_y = PETSC_FALSE;
PetscFunctionReturn(0);
}
/* ------------------------------------------------------------------- */
#undef __FUNCT__
#define __FUNCT__ "PostCheck"
/*
PostCheck - Optional user-defined routine that checks the validity of
candidate steps of a line search method. Set by SNESLineSearchSetPostCheck().
Input Parameters:
snes - the SNES context
ctx - optional user-defined context for private data for the
monitor routine, as set by SNESLineSearchSetPostCheck()
xcurrent - current solution
y - search direction and length
x - the new candidate iterate
Output Parameters:
y - proposed step (search direction and length) (possibly changed)
x - current iterate (possibly modified)
*/
PetscErrorCode PostCheck(SNESLineSearch linesearch,Vec xcurrent,Vec y,Vec x,PetscBool *changed_y,PetscBool *changed_x, void * ctx)
{
PetscErrorCode ierr;
PetscInt i,iter,xs,xm;
StepCheckCtx *check;
AppCtx *user;
PetscScalar *xa,*xa_last,tmp;
PetscReal rdiff;
DM da;
SNES snes;
PetscFunctionBeginUser;
*changed_x = PETSC_FALSE;
*changed_y = PETSC_FALSE;
ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
check = (StepCheckCtx*)ctx;
user = check->user;
ierr = SNESGetIterationNumber(snes,&iter);CHKERRQ(ierr);
ierr = SNESLineSearchGetPreCheck(linesearch, NULL, (void**)&check);CHKERRQ(ierr);
/* iteration 1 indicates we are working on the second iteration */
if (iter > 0) {
da = user->da;
ierr = PetscPrintf(PETSC_COMM_WORLD,"Checking candidate step at iteration %D with tolerance %g\n",iter,(double)check->tolerance);CHKERRQ(ierr);
/* Access local array data */
ierr = DMDAVecGetArray(da,check->last_step,&xa_last);CHKERRQ(ierr);
ierr = DMDAVecGetArray(da,x,&xa);CHKERRQ(ierr);
ierr = DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL);CHKERRQ(ierr);
/*
If we fail the user-defined check for validity of the candidate iterate,
then modify the iterate as we like. (Note that the particular modification
below is intended simply to demonstrate how to manipulate this data, not
as a meaningful or appropriate choice.)
*/
for (i=xs; i<xs+xm; i++) {
if (!PetscAbsScalar(xa[i])) rdiff = 2*check->tolerance;
else rdiff = PetscAbsScalar((xa[i] - xa_last[i])/xa[i]);
if (rdiff > check->tolerance) {
tmp = xa[i];
xa[i] = .5*(xa[i] + xa_last[i]);
*changed_x = PETSC_TRUE;
ierr = PetscPrintf(PETSC_COMM_WORLD," Altering entry %D: x=%g, x_last=%g, diff=%g, x_new=%g\n",
i,(double)PetscAbsScalar(tmp),(double)PetscAbsScalar(xa_last[i]),(double)rdiff,(double)PetscAbsScalar(xa[i]));CHKERRQ(ierr);
}
}
ierr = DMDAVecRestoreArray(da,check->last_step,&xa_last);CHKERRQ(ierr);
ierr = DMDAVecRestoreArray(da,x,&xa);CHKERRQ(ierr);
}
ierr = VecCopy(x,check->last_step);CHKERRQ(ierr);
PetscFunctionReturn(0);
}
/* ------------------------------------------------------------------- */
#undef __FUNCT__
#define __FUNCT__ "PostSetSubKSP"
/*
PostSetSubKSP - Optional user-defined routine that reset SubKSP options when hierarchical bjacobi PC is used
e.g,
mpiexec -n 8 ./ex3 -nox -n 10000 -ksp_type fgmres -pc_type bjacobi -pc_bjacobi_blocks 4 -sub_ksp_type gmres -sub_ksp_max_it 3 -post_setsubksp -sub_ksp_rtol 1.e-16
Set by SNESLineSearchSetPostCheck().
Input Parameters:
linesearch - the LineSearch context
xcurrent - current solution
y - search direction and length
x - the new candidate iterate
Output Parameters:
y - proposed step (search direction and length) (possibly changed)
x - current iterate (possibly modified)
*/
PetscErrorCode PostSetSubKSP(SNESLineSearch linesearch,Vec xcurrent,Vec y,Vec x,PetscBool *changed_y,PetscBool *changed_x, void * ctx)
{
PetscErrorCode ierr;
SetSubKSPCtx *check;
PetscInt iter,its,sub_its,maxit;
KSP ksp,sub_ksp,*sub_ksps;
PC pc;
PetscReal ksp_ratio;
SNES snes;
PetscFunctionBeginUser;
ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
check = (SetSubKSPCtx*)ctx;
ierr = SNESGetIterationNumber(snes,&iter);CHKERRQ(ierr);
ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr);
ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
ierr = PCBJacobiGetSubKSP(pc,NULL,NULL,&sub_ksps);CHKERRQ(ierr);
sub_ksp = sub_ksps[0];
ierr = KSPGetIterationNumber(ksp,&its);CHKERRQ(ierr); /* outer KSP iteration number */
ierr = KSPGetIterationNumber(sub_ksp,&sub_its);CHKERRQ(ierr); /* inner KSP iteration number */
if (iter) {
ierr = PetscPrintf(PETSC_COMM_WORLD," ...PostCheck snes iteration %D, ksp_it %d %d, subksp_it %d\n",iter,check->its0,its,sub_its);CHKERRQ(ierr);
ksp_ratio = ((PetscReal)(its))/check->its0;
maxit = (PetscInt)(ksp_ratio*sub_its + 0.5);
if (maxit < 2) maxit = 2;
ierr = KSPSetTolerances(sub_ksp,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,maxit);CHKERRQ(ierr);
ierr = PetscPrintf(PETSC_COMM_WORLD," ...ksp_ratio %g, new maxit %d\n\n",ksp_ratio,maxit);CHKERRQ(ierr);
}
check->its0 = its; /* save current outer KSP iteration number */
PetscFunctionReturn(0);
}
/* ------------------------------------------------------------------- */
/*
MatrixFreePreconditioner - This routine demonstrates the use of a
user-provided preconditioner. This code implements just the null
preconditioner, which of course is not recommended for general use.
Input Parameters:
+ pc - preconditioner
- x - input vector
Output Parameter:
. y - preconditioned vector
*/
PetscErrorCode MatrixFreePreconditioner(PC pc,Vec x,Vec y)
{
PetscErrorCode ierr;
ierr = VecCopy(x,y);CHKERRQ(ierr);
return 0;
}

View File

@ -4467,7 +4467,7 @@ DynamicModel::writeResidualsC(const string &basename, bool cuda) const
deriv_node_temp_terms_t tef_terms;
ostringstream model_output; // Used for storing model equations
writeModelEquations(model_output, oCDynamicModel);
writeModelEquations(model_output, oCDynamic2Model);
mDynamicModelFile << " double lhs, rhs;" << endl
<< endl
@ -4540,6 +4540,106 @@ DynamicModel::writeFirstDerivativesC(const string &basename, bool cuda) const
// using compressed sparse row format (CSR)
void
DynamicModel::writeFirstDerivativesC_csr(const string &basename, bool cuda) const
{
string filename = basename + "_first_derivatives.c";
ofstream mDynamicModelFile, mDynamicMexFile;
mDynamicModelFile.open(filename.c_str(), ios::out | ios::binary);
if (!mDynamicModelFile.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
exit(EXIT_FAILURE);
}
mDynamicModelFile << "/*" << endl
<< " * " << filename << " : Computes first order derivatives of the model for Dynare" << endl
<< " *" << endl
<< " * Warning : this file is generated automatically by Dynare" << endl
<< " * from model " << basename << "(.mod)" << endl
<< " */" << endl
<< "#include <math.h>" << endl;
mDynamicModelFile << "#include <stdlib.h>" << endl;
mDynamicModelFile << "#define max(a, b) (((a) > (b)) ? (a) : (b))" << endl
<< "#define min(a, b) (((a) > (b)) ? (b) : (a))" << endl;
// Write function definition if oPowerDeriv is used
writePowerDerivCHeader(mDynamicModelFile);
mDynamicModelFile << "void FirstDerivatives(const double *y, double *x, int nb_row_x, double *params, double *steady_state, int it_, double *residual, int *row_ptr, int *col_ptr, double *value)" << endl
<< "{" << endl;
int cols_nbr = 3*symbol_table.endo_nbr() + symbol_table.exo_nbr() + symbol_table.exo_det_nbr();
// this is always empty here, but needed by d1->writeOutput
deriv_node_temp_terms_t tef_terms;
// Indexing derivatives in column order
vector<derivative> D;
for (first_derivatives_t::const_iterator it = first_derivatives.begin();
it != first_derivatives.end(); it++)
{
int eq = it->first.first;
int dynvar = it->first.second;
int lag = getLagByDerivID(dynvar);
int symb = getSymbIDByDerivID(dynvar);
SymbolType type = getTypeByDerivID(dynvar);
int col_id;
switch(type)
{
case eEndogenous:
col_id = symb+(lag+1)*symbol_table.endo_nbr();
break;
case eExogenous:
col_id = symb+3*symbol_table.endo_nbr();
break;
case eExogenousDet:
col_id = symb+3*symbol_table.endo_nbr()+symbol_table.exo_nbr();
break;
default:
std::cerr << "This case shouldn't happen" << std::endl;
exit(1);
}
derivative deriv(col_id + eq*cols_nbr,col_id,eq,it->second);
D.push_back(deriv);
}
sort(D.begin(), D.end(), derivative_less_than() );
// writing sparse Jacobian
vector<int> row_ptr(equations.size());
fill(row_ptr.begin(),row_ptr.end(),0.0);
int k = 0;
for(vector<derivative>::const_iterator it = D.begin(); it != D.end(); ++it)
{
row_ptr[it->row_nbr]++;
mDynamicModelFile << "col_ptr[" << k << "] "
<< "=" << it->col_nbr << ";" << endl;
mDynamicModelFile << "value[" << k << "] = ";
// oCstaticModel makes reference to the static variables
it->value->writeOutput(mDynamicModelFile, oCDynamic2Model, temporary_terms, tef_terms);
mDynamicModelFile << ";" << endl;
k++;
}
// row_ptr must point to the relative address of the first element of the row
int cumsum = 0;
mDynamicModelFile << "int row_ptr_data[" << row_ptr.size() + 1 << "] = { 0";
for (vector<int>::iterator it=row_ptr.begin(); it != row_ptr.end(); ++it)
{
cumsum += *it;
mDynamicModelFile << ", " << cumsum;
}
mDynamicModelFile << "};" << endl
<< "int i;" << endl
<< "for (i=0; i < " << row_ptr.size() + 1 << "; i++) row_ptr[i] = row_ptr_data[i];" << endl;
mDynamicModelFile << "}" << endl;
// writePowerDeriv(mDynamicModelFile, true);
mDynamicModelFile.close();
}
void
DynamicModel::writeSecondDerivativesC_csr(const string &basename, bool cuda) const
{

View File

@ -480,6 +480,8 @@ public:
void writeResidualsC(const string &basename, bool cuda) const;
//! Writes C file containing first order derivatives of model evaluated at steady state
void writeFirstDerivativesC(const string &basename, bool cuda) const;
//! Writes C file containing first order derivatives of model evaluated at steady state (conpressed sparse column)
void writeFirstDerivativesC_csr(const string &basename, bool cuda) const;
//! Writes C file containing second order derivatives of model evaluated at steady state (compressed sparse column)
void writeSecondDerivativesC_csr(const string &basename, bool cuda) const;
//! Writes C file containing third order derivatives of model evaluated at steady state (compressed sparse column)

View File

@ -659,6 +659,10 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
i = datatree.getDynJacobianCol(datatree.getDerivID(symb_id, lag)) + ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oCDynamic2Model:
i = symb_id + (lag+1)*datatree.symbol_table.endo_nbr() + ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oCStaticModel:
case oMatlabStaticModel:
case oMatlabStaticModelSparse:
@ -710,6 +714,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
output << "x(it_, " << i << ")";
break;
case oCDynamicModel:
case oCDynamic2Model:
if (lag == 0)
output << "x[it_+" << i << "*nb_row_x]";
else if (lag > 0)
@ -755,6 +760,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
output << "x(it_, " << i << ")";
break;
case oCDynamicModel:
case oCDynamic2Model:
if (lag == 0)
output << "x[it_+" << i << "*nb_row_x]";
else if (lag > 0)

View File

@ -65,6 +65,7 @@ enum ExprNodeOutputType
oMatlabStaticModelSparse, //!< Matlab code, static block decomposed model
oMatlabDynamicModelSparse, //!< Matlab code, dynamic block decomposed model
oCDynamicModel, //!< C code, dynamic model
oCDynamic2Model, //!< C code, dynamic model, alternative numbering of endogenous variables
oCStaticModel, //!< C code, static model
oMatlabOutsideModel, //!< Matlab code, outside model block (for example in initval)
oLatexStaticModel, //!< LaTeX code, static model
@ -87,6 +88,7 @@ enum ExprNodeOutputType
|| (output_type) == oSteadyStateFile)
#define IS_C(output_type) ((output_type) == oCDynamicModel \
|| (output_type) == oCDynamic2Model \
|| (output_type) == oCStaticModel \
|| (output_type) == oCDynamicSteadyStateOperator \
|| (output_type) == oCSteadyStateFile)

View File

@ -972,7 +972,7 @@ ModFile::writeExternalFilesCC(const string &basename, FileOutputType output) con
// dynamic_model.writeResidualsC(basename, cuda);
// dynamic_model.writeParamsDerivativesFileC(basename, cuda);
dynamic_model.writeResidualsC(basename, cuda);
dynamic_model.writeFirstDerivativesC(basename, cuda);
dynamic_model.writeFirstDerivativesC_csr(basename, cuda);
if (output == second)
dynamic_model.writeSecondDerivativesC_csr(basename, cuda);