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

📄 frozen_soil.c

📁 本人独自开发的土壤计算及分析工具
💻 C
字号:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <vicNl.h>

#define MAXIT 1000

static char vcid[] = "$Id: frozen_soil.c,v 4.2.2.3 2004/09/22 00:40:33 vicadmin Exp $";

void setup_frozen_soil(soil_con_struct   *soil_con,
		       layer_data_struct *layer_wet,
		       layer_data_struct *layer_dry,
		       layer_data_struct *layer,
		       energy_bal_struct  energy,
		       int                rec,
		       int                veg,
		       int                Nnodes,
		       double             mu,
		       double            *kappa,
		       double            *Cs,
		       double            *moist) {
/**********************************************************************
  setup_frozen_soil	Keith Cherkauer		July 27, 1998

  This subroutine prepares the data arrays needed to solve the soil
  thermal fluxes through all soil thermal nodes.

  soil_con_struct    soil_con   soil parameter structure
  layer_data_struct *layer_wet  soil variables for wet fraction
  layer_data_struct *layer_dry  soil variables for dry fraction
  layer_data_struct *layer      average soil variables
  energy_bal_struct  energy     energy balance structure
  int                rec        record number
  int                veg        vegetation type number
  int                Nnodes     number of soil thermal nodes 
  double             mu         fraction of grid cell that received precip
  double            *kappa      soil layer thermal conductivity (W/m/K)
  double            *Cs         soil layer heat capacity (J/m^3/K)
  double            *moist      soil layer moisture (mm)
  
  Modifications
  04-Jun-04 Added descriptive error message to beginning of screen dump
	    in error_print_solve_T_profile.			TJB
  21-Sep-04 Added ErrorString to store error messages from
	    root_brent.						TJB

**********************************************************************/
  extern option_struct options;
#if LINK_DEBUG
  extern debug_struct  debug;
#endif

  int nidx;

  for(nidx=0;nidx<Nnodes;nidx++) {
    moist[nidx] = energy.moist[nidx];
    kappa[nidx] = energy.kappa_node[nidx];
    Cs[nidx]    = energy.Cs_node[nidx];
  }

}

void finish_frozen_soil_calcs(energy_bal_struct *energy,
			      layer_data_struct *layer_wet,
			      layer_data_struct *layer_dry,
			      layer_data_struct *layer,
			      soil_con_struct   *soil_con,
			      int                Nnodes,
			      int                veg,
			      double             mu,
			      double            *T,
			      double            *kappa,
			      double            *Cs,
			      double            *moist) {
/******************************************************************
  finish_frozen_soil_calcs      Keith Cherkauer      July 27, 1998

  This subroutine redistributes soil properties based on the 
  thermal solutions found for the current time step.

  Modifications:
  3-12-03 Modified so that soil layer ice content is only 
          calculated if the frozen soil algorithm is implemented 
          and active in the current grid cell.               KAC

******************************************************************/

  extern option_struct options;
#if LINK_DEBUG
  extern debug_struct  debug;
#endif

  char    ErrorString[MAXSTRING];
  int     i, j;
  int     index;
  double  fdepth;
  double  tdepth;
  double  unfrozen;
  double  frozen;
  double  old_fdepth[MAX_LAYERS];
  double  old_tdepth[MAX_LAYERS];
  double *tmp_ptr;

  find_0_degree_fronts(energy, soil_con->dz_node, T, Nnodes);

  /** Store Layer Temperature Values **/
  for(i=0;i<Nnodes;i++) energy->T[i] = T[i];

  if(energy->Nfrost>0) energy->frozen = TRUE;
  else energy->frozen = FALSE;

  /** Redistribute Soil Properties for New Frozen Soil Layer Size **/
  if(soil_con->FS_ACTIVE && options.FROZEN_SOIL)
    estimate_layer_ice_content(layer_wet, soil_con->dz_node, energy->T,
			       soil_con->max_moist_node, 
#if QUICK_FS
			       soil_con->ufwc_table_node,
#else
			       soil_con->expt_node, soil_con->bubble_node, 
#endif
			       soil_con->depth, soil_con->max_moist, 
#if QUICK_FS
			       soil_con->ufwc_table_layer,
#else
			       soil_con->expt, soil_con->bubble, 
#endif
			       soil_con->bulk_density,
			       soil_con->soil_density, soil_con->quartz,
			       soil_con->layer_node_fract, Nnodes, 
			       options.Nlayer, soil_con->FS_ACTIVE);
  if(options.DIST_PRCP && soil_con->FS_ACTIVE && options.FROZEN_SOIL)
    estimate_layer_ice_content(layer_dry, soil_con->dz_node, energy->T,
			       soil_con->max_moist_node, 
#if QUICK_FS
			       soil_con->ufwc_table_node,
#else
			       soil_con->expt_node, soil_con->bubble_node, 
#endif
			       soil_con->depth, soil_con->max_moist, 
#if QUICK_FS
			       soil_con->ufwc_table_layer,
#else
			       soil_con->expt, soil_con->bubble, 
#endif
			       soil_con->bulk_density, soil_con->soil_density, 
			       soil_con->quartz, soil_con->layer_node_fract, 
			       Nnodes, options.Nlayer, soil_con->FS_ACTIVE);

#if LINK_DEBUG
  if(debug.PRT_BALANCE && debug.DEBUG) {
    printf("After Moisture Redistribution\n");
    write_layer(layer,veg,options.Nlayer,soil_con->depth);
  } 
#endif
  
}

void solve_T_profile(double *T,
		     double *T0,
		     double *dz,
		     double *kappa,
		     double *Cs,
		     double *moist,
		     double  deltat,
		     double *max_moist,
		     double *bubble,
		     double *expt,
		     double *ice,
		     double *alpha,
		     double *beta,
		     double *gamma,
#if QUICK_FS
		     double ***ufwc_table_node,
#endif
		     int     Nnodes,
		     char   *FIRST_SOLN,
		     char    FIRST_TIME, 
		     int     FS_ACTIVE) {
/**********************************************************************
  This subroutine was written to iteratively solve the soil temperature
  profile using a numerical difference equation.  The solution equation
  is second order in space, and first order in time.
**********************************************************************/

  extern option_struct options;
#if LINK_DEBUG
  extern debug_struct  debug;
#endif
  
  static double A[MAX_NODES];
  static double B[MAX_NODES];
  static double C[MAX_NODES];
  static double D[MAX_NODES];
  static double E[MAX_NODES];

  double *aa, *bb, *cc, *dd, *ee;

  char   Error;
  int    try;
  double maxdiff, diff;
  double oldT;
  double fprime;
  int    j, Done, ItCount;

  if(FIRST_SOLN[0]) {
    FIRST_SOLN[0] = FALSE;
    for(j=1;j<Nnodes-1;j++) {
      A[j] = beta[j-1]*deltat*(kappa[j+1]-kappa[j-1]);
      B[j] = 2.*alpha[j-1]*alpha[j-1]*deltat*kappa[j];
      C[j] = alpha[j-1]*alpha[j-1]*beta[j-1]*Cs[j]*T0[j];
      D[j] = alpha[j-1]*alpha[j-1]*beta[j-1]*ice_density*Lf;
      E[j] = alpha[j-1]*alpha[j-1]*beta[j-1]*Cs[j] 
	+ 4.*kappa[j]*alpha[j-1]*alpha[j-1]*deltat;
    }
    if(options.NOFLUX) {
      j = Nnodes-1;
      A[j] = beta[j-1]*deltat*(kappa[j]-kappa[j-1]);
      B[j] = 2.*alpha[j-1]*alpha[j-1]*deltat*kappa[j];
      C[j] = alpha[j-1]*alpha[j-1]*beta[j-1]*Cs[j]*T0[j];
      D[j] = alpha[j-1]*alpha[j-1]*beta[j-1]*ice_density*Lf;
      E[j] = alpha[j-1]*alpha[j-1]*beta[j-1]*Cs[j] 
	+ 4.*kappa[j]*alpha[j-1]*alpha[j-1]*deltat;
    }
  }
    
  aa = &A[0];
  bb = &B[0];
  cc = &C[0];
  dd = &D[0];
  ee = &E[0];

  for(j=0;j<Nnodes;j++) T[j]=T0[j];

#if QUICK_FS
  Error = calc_soil_thermal_fluxes(Nnodes, T, T0, moist, max_moist, ice, 
				   bubble, expt, alpha, gamma, aa, bb, cc, 
				   dd, ee, ufwc_table_node, FS_ACTIVE);
#else
  Error = calc_soil_thermal_fluxes(Nnodes, T, T0, moist, max_moist, ice, 
				   bubble, expt, alpha, gamma, aa, bb, cc, 
				   dd, ee, FS_ACTIVE);
#endif
  
}
  

int calc_soil_thermal_fluxes(int     Nnodes,
			     double *T,
			     double *T0,
			     double *moist,
			     double *max_moist,
			     double *ice,
			     double *bubble,
			     double *expt,
			     double *alpha,
			     double *gamma,
			     double *A, 
			     double *B, 
			     double *C, 
			     double *D, 
			     double *E,
#if QUICK_FS
			     double ***ufwc_table_node,
#endif
			     char    FS_ACTIVE) {
  
  /** Eventually the nodal ice contents will also have to be updated **/

  extern option_struct options;

  int    Error;
  char   Done;
  int    j;
  int    ItCount;
  double threshold = 1.e-2;	/* temperature profile iteration threshold */
  double maxdiff;
  double diff;
  double oldT;
  double fprime;
  char ErrorString[MAXSTRING];

  Error = 0;
  Done = FALSE;
  ItCount = 0;
  
  while(!Done && Error==0 && ItCount<MAXIT) {
    ItCount++;
    maxdiff=threshold;
    for(j=1;j<Nnodes-1;j++) {
      oldT=T[j];
      
      /**	2nd order variable kappa equation **/
      fprime = (T[j+1]-T[j-1])/alpha[j-1];
      
      if(T[j] >= 0 || !FS_ACTIVE || !options.FROZEN_SOIL) {
	T[j] = (A[j]*(T[j+1]-T[j-1])
		+ B[j]*(T[j+1]+T[j-1]-gamma[j-1]*fprime)
		+ C[j] + D[j]*(0.-ice[j])) / (E[j]);
      }
      else {
#if QUICK_FS
	T[j] = root_brent(T0[j]-(SOIL_DT), T0[j]+(SOIL_DT),
			  ErrorString, soil_thermal_eqn, 
			  T[j+1], T[j-1], T0[j], moist[j], max_moist[j], 
			  ufwc_table_node[j], ice[j], gamma[j-1], fprime, 
			  A[j], B[j], C[j], D[j], E[j]);
#else
	T[j] = root_brent(T0[j]-(SOIL_DT), T0[j]+(SOIL_DT),
			  ErrorString, soil_thermal_eqn, 
			  T[j+1], T[j-1], T0[j], moist[j], max_moist[j], 
			  bubble[j], expt[j], ice[j], gamma[j-1], fprime, 
			  A[j], B[j], C[j], D[j], E[j]);
#endif
	
	if(T[j] <= -9998) 
	  error_solve_T_profile(T[j], T[j+1], T[j-1], T0[j], moist[j], 
				max_moist[j], bubble[j], expt[j], ice[j], 
				gamma[j-1], fprime, A[j], B[j], C[j], D[j], 
				E[j], ErrorString);
      }
      
      diff=fabs(oldT-T[j]);
      if(diff > maxdiff) maxdiff=diff;
    }
    
    if(options.NOFLUX) { 
      /** Solve for bottom temperature if using no flux lower boundary **/
      oldT=T[Nnodes-1];
      
      fprime = (T[Nnodes-1]-T[Nnodes-2])/alpha[Nnodes-2];
      
      j = Nnodes-1;
      
      if(T[j] >= 0 || !FS_ACTIVE || !options.FROZEN_SOIL) {
	T[j] = (A[j]*(T[j]-T[j-1]) + B[j]*(T[j] + T[j-1] - gamma[j-1]*fprime)
		+ C[j] + D[j]*(0.-ice[j])) / E[j];
      }
      else {
#if QUICK_FS
	T[Nnodes-1] = root_brent(T0[Nnodes-1]-SOIL_DT,T0[Nnodes-1]+SOIL_DT,
				 ErrorString, soil_thermal_eqn, T[Nnodes-1],
				 T[Nnodes-2], T0[Nnodes-1], 
				 moist[Nnodes-1], max_moist[Nnodes-1], 
				 ufwc_table_node[Nnodes-1], 
				 ice[Nnodes-1], 
				 gamma[Nnodes-2], fprime, 
				 A[j], B[j], C[j], D[j], E[j]);
#else
	T[Nnodes-1] = root_brent(T0[Nnodes-1]-SOIL_DT,T0[Nnodes-1]+SOIL_DT,
				 ErrorString, soil_thermal_eqn, T[Nnodes-1],
				 T[Nnodes-2], T0[Nnodes-1], 
				 moist[Nnodes-1], max_moist[Nnodes-1], 
				 bubble[j], expt[Nnodes-1], ice[Nnodes-1], 
				 gamma[Nnodes-2], fprime, 
				 A[j], B[j], C[j], D[j], E[j]);
#endif
	
	if(T[j] <= -9998) 
	  error_solve_T_profile(T[Nnodes-1], T[Nnodes-1],
				T[Nnodes-2], T0[Nnodes-1], 
				moist[Nnodes-1], max_moist[Nnodes-1], 
				bubble[Nnodes-1], 
				expt[Nnodes-1], ice[Nnodes-1], 
				gamma[Nnodes-2], fprime, 
				A[j], B[j], C[j], D[j], E[j], ErrorString);
      }
      
      diff=fabs(oldT-T[Nnodes-1]);
      if(diff>maxdiff) maxdiff=diff;
    }
    
    if(maxdiff <= threshold) Done=TRUE;
    
  }
  
  if(!Done && !Error) {
    fprintf(stderr,"ERROR: Temperature Profile Unable to Converge!!!\n");
    fprintf(stderr,"Dumping Profile Temperatures (last, new).\n");
    for(j=0;j<Nnodes;j++) fprintf(stderr,"%f\t%f\n",T0[j],T[j]);
    vicerror("ERROR: Cannot solve temperature profile:\n\tToo Many Iterations in solve_T_profile");
  }

  return (Error);

}

double error_solve_T_profile (double Tj, ...) {

  va_list ap;

  double error;

  va_start(ap,Tj);
  error = error_print_solve_T_profile(Tj, ap);
  va_end(ap);

  return error;

}

double error_print_solve_T_profile(double T, va_list ap) {

  double TL;
  double TU;
  double T0;
  double moist;
  double max_moist;
  double bubble;
  double expt;
  double ice0;
  double gamma;
  double fprime;
  double A;
  double B;
  double C;
  double D;
  double E;
  char *ErrorString;

  TL        = (double) va_arg(ap, double);
  TU        = (double) va_arg(ap, double);
  T0        = (double) va_arg(ap, double);
  moist     = (double) va_arg(ap, double);
  max_moist = (double) va_arg(ap, double);
  bubble    = (double) va_arg(ap, double);
  expt      = (double) va_arg(ap, double);
  ice0      = (double) va_arg(ap, double);
  gamma     = (double) va_arg(ap, double);
  fprime    = (double) va_arg(ap, double);
  A         = (double) va_arg(ap, double);
  B         = (double) va_arg(ap, double);
  C         = (double) va_arg(ap, double);
  D         = (double) va_arg(ap, double);
  E         = (double) va_arg(ap, double);
  ErrorString = (char*) va_arg(ap, char *);
  
  fprintf(stderr, "%s", ErrorString);
  fprintf(stderr, "ERROR: solve_T_profile failed to converge to a solution in root_brent.  Variable values will be dumped to the screen, check for invalid values.\n");

  fprintf(stderr,"TL\t%f\n",TL);
  fprintf(stderr,"TU\t%f\n",TU);
  fprintf(stderr,"T0\t%f\n",T0);
  fprintf(stderr,"moist\t%f\n",moist);
  fprintf(stderr,"max_moist\t%f\n",max_moist);
  fprintf(stderr,"bubble\t%f\n",bubble);
  fprintf(stderr,"expt\t%f\n",expt);
  fprintf(stderr,"ice0\t%f\n",ice0);
  fprintf(stderr,"gamma\t%f\n",gamma);
  fprintf(stderr,"fprime\t%f\n",fprime);
  fprintf(stderr,"A\t%f\n",A);
  fprintf(stderr,"B\t%f\n",B);
  fprintf(stderr,"C\t%f\n",C);
  fprintf(stderr,"D\t%f\n",D);
  fprintf(stderr,"E\t%f\n",E);

  vicerror("Finished dumping values for solve_T_profile.\nTry increasing SOIL_DT to get model to complete cell.\nThen check output for instabilities.\n");
  
  return(0.0);

}

#undef MAXIT

⌨️ 快捷键说明

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