Changeset 21721


Ignore:
Timestamp:
05/18/17 14:11:53 (8 years ago)
Author:
jbondzio
Message:

CHG: more consistent treatment of englacial water content drainage

Location:
issm/trunk-jpl/src/c
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk-jpl/src/c/analyses/EnthalpyAnalysis.cpp

    r21718 r21721  
    55#include "../modules/modules.h"
    66#include "../solutionsequences/solutionsequences.h"
     7#include "../cores/cores.h"
    78
    89/*Model processing*/
     
    980981void           EnthalpyAnalysis::DrainWaterfraction(FemModel* femmodel){/*{{{*/
    981982        /*Drain excess water fraction in ice column: */
    982         for(int i=0;i<femmodel->elements->Size();i++){
    983                 Element* element=xDynamicCast<Element*>(femmodel->elements->GetObjectByOffset(i));
    984                 DrainWaterfractionIcecolumn(element);
    985         }
    986 }/*}}}*/
    987 void           EnthalpyAnalysis::DrainWaterfraction(Element* element, IssmDouble* pdrainrate_element){/*{{{*/
    988 
    989         /* Check if ice in element */
    990         if(!element->IsIceInElement()) return;
    991 
    992         /*Intermediaries*/
    993         int iv,is,vertexdown,vertexup,numsegments;     
    994         IssmDouble dt, height_element;
    995         IssmDouble rho_water, rho_ice;
    996         int numvertices = element->GetNumberOfVertices();
    997 
    998         IssmDouble* xyz_list = NULL;
    999         IssmDouble* enthalpies = xNew<IssmDouble>(numvertices);
    1000         IssmDouble* pressures = xNew<IssmDouble>(numvertices);
    1001         IssmDouble* temperatures = xNew<IssmDouble>(numvertices);
    1002         IssmDouble* waterfractions = xNew<IssmDouble>(numvertices);
    1003         IssmDouble* deltawaterfractions = xNew<IssmDouble>(numvertices);
    1004         int        *pairindices   = NULL;
     983        ComputeWaterfractionDrainage(femmodel);
     984        DrainageUpdateWatercolumn(femmodel);
     985        DrainageUpdateEnthalpy(femmodel);
     986}/*}}}*/
     987void                            EnthalpyAnalysis::ComputeWaterfractionDrainage(FemModel* femmodel){/*{{{*/
     988
     989        int i,k,numnodes;
     990        IssmDouble dt;
     991        Element* element= NULL;
     992
     993        femmodel->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
     994
     995        for(i=0;i<femmodel->elements->Size();i++){
     996                element=xDynamicCast<Element*>(femmodel->elements->GetObjectByOffset(i));
     997                numnodes=element->GetNumberOfNodes();
     998                IssmDouble* waterfractions= xNew<IssmDouble>(numnodes);
     999                IssmDouble* drainage= xNew<IssmDouble>(numnodes);
     1000
     1001                element->GetInputListOnNodes(waterfractions,WaterfractionEnum);
     1002                for(k=0; k<numnodes;k++){
     1003                        drainage[k]=DrainageFunctionWaterfraction(waterfractions[k], dt);
     1004                }
     1005                element->AddInput(WaterfractionDrainageEnum,drainage,element->GetElementType());
     1006
     1007                xDelete<IssmDouble>(waterfractions);
     1008                xDelete<IssmDouble>(drainage);
     1009        }
     1010}/*}}}*/
     1011void                            EnthalpyAnalysis::DrainageUpdateWatercolumn(FemModel* femmodel){/*{{{*/
     1012
     1013        int i,k,numnodes, numbasalnodes;
     1014        IssmDouble dt;
     1015        int* basalnodeindices=NULL;
     1016        Element* element= NULL;
    10051017       
    1006         rho_ice=element->GetMaterialParameter(MaterialsRhoIceEnum);
    1007         rho_water=element->GetMaterialParameter(MaterialsRhoSeawaterEnum);
    1008 
    1009         element->GetVerticesCoordinates(&xyz_list);
    1010         element->GetInputListOnVertices(enthalpies,EnthalpyEnum);
    1011         element->GetInputListOnVertices(pressures,PressureEnum);
    1012 
    1013         element->FindParam(&dt,TimesteppingTimeStepEnum);
    1014         for(iv=0;iv<numvertices;iv++){
    1015                 element->EnthalpyToThermal(&temperatures[iv],&waterfractions[iv], enthalpies[iv],pressures[iv]);
    1016                 deltawaterfractions[iv]=DrainageFunctionWaterfraction(waterfractions[iv], dt);
    1017         }
    1018        
    1019         /*drain waterfraction, feed updated variables back into model*/
    1020         for(iv=0;iv<numvertices;iv++){
    1021                 if(reCast<bool,IssmDouble>(dt))
    1022                         waterfractions[iv]-=deltawaterfractions[iv]*dt;
    1023                 else
    1024                         waterfractions[iv]-=deltawaterfractions[iv];
    1025                 element->ThermalToEnthalpy(&enthalpies[iv], temperatures[iv], waterfractions[iv], pressures[iv]);
    1026         }
    1027         element->AddInput(EnthalpyEnum,enthalpies,P1Enum);
    1028         element->AddInput(WaterfractionEnum,waterfractions,P1Enum);
    1029 
    1030         /*return meltwater column equivalent to drained water*/
    1031         element->VerticalSegmentIndices(&pairindices,&numsegments);
    1032         for(is=0;is<numsegments;is++){
    1033                 vertexdown = pairindices[is*2+0];
    1034                 vertexup   = pairindices[is*2+1];
    1035                 height_element=fabs(xyz_list[vertexup*3+2]-xyz_list[vertexdown*3+2]);
    1036                 pdrainrate_element[is]=(deltawaterfractions[vertexdown]+deltawaterfractions[vertexup])/2.*height_element; // return water equivalent of drainage
    1037                 _assert_(pdrainrate_element[is]>=0.);
    1038         }
    1039 
    1040         /*Clean up and return*/
    1041         xDelete<int>(pairindices);
    1042         xDelete<IssmDouble>(xyz_list);
    1043         xDelete<IssmDouble>(enthalpies);
    1044         xDelete<IssmDouble>(pressures);
    1045         xDelete<IssmDouble>(temperatures);
    1046         xDelete<IssmDouble>(waterfractions);
    1047         xDelete<IssmDouble>(deltawaterfractions);
    1048 }/*}}}*/
    1049 void           EnthalpyAnalysis::DrainWaterfractionIcecolumn(Element* element){/*{{{*/
    1050 
    1051         /* Check if ice in element */
    1052         if(!element->IsIceInElement()) return;
    1053 
    1054         /* Only drain waterfraction of ice column from element at base*/
    1055         if(!element->IsOnBase()) return; //FIXME: allow freeze on for floating elements
    1056 
    1057         /* Intermediaries*/
    1058         int is,numsegments;
    1059         int *pairindices   = NULL;
    1060 
    1061         int numnodes=element->GetNumberOfNodes();
    1062         element->VerticalSegmentIndices(&pairindices,&numsegments);
    1063 
    1064         IssmDouble* drainrate_column  = xNew<IssmDouble>(numsegments);
    1065         IssmDouble* drainrate_element = xNew<IssmDouble>(numsegments);
    1066 
    1067         for(is=0;is<numsegments;is++)   drainrate_column[is]=0.;
    1068         Element* elementi = element;
    1069         for(;;){
    1070                 for(is=0;is<numsegments;is++)   drainrate_element[is]=0.;
    1071                 DrainWaterfraction(elementi,drainrate_element); // TODO: make sure every vertex is only drained once
    1072                 for(is=0;is<numsegments;is++)   drainrate_column[is]+=drainrate_element[is];
    1073 
    1074                 if(elementi->IsOnSurface()) break;
    1075                 elementi=elementi->GetUpperElement();                   
    1076         }
    1077 
    1078         /* add drained water to water column*/
    1079         IssmDouble* watercolumn = xNew<IssmDouble>(numnodes);
    1080         element->GetInputListOnNodes(watercolumn,WatercolumnEnum);
    1081         for(is=0;is<numsegments;is++) watercolumn[is]+=drainrate_column[is];
    1082 
    1083         /* Feed updated water column back into model */
    1084         element->AddInput(WatercolumnEnum,watercolumn,element->GetElementType());
    1085 
    1086         xDelete<int>(pairindices);
    1087         xDelete<IssmDouble>(drainrate_column);
    1088         xDelete<IssmDouble>(drainrate_element);
    1089         xDelete<IssmDouble>(watercolumn);
     1018        femmodel->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
     1019
     1020        /*depth-integrate the drained water fraction */
     1021        femmodel->parameters->SetParam(WaterfractionDrainageEnum,InputToDepthaverageInEnum);
     1022        femmodel->parameters->SetParam(WaterfractionDrainageIntegratedEnum,InputToDepthaverageOutEnum);
     1023        depthaverage_core(femmodel);
     1024        femmodel->parameters->SetParam(WaterfractionDrainageIntegratedEnum,InputToExtrudeEnum);
     1025        extrudefrombase_core(femmodel);
     1026        /*multiply depth-average by ice thickness*/
     1027        for(i=0;i<femmodel->elements->Size();i++){
     1028                element=xDynamicCast<Element*>(femmodel->elements->GetObjectByOffset(i));
     1029                numnodes=element->GetNumberOfNodes();
     1030                IssmDouble* drainage_int= xNew<IssmDouble>(numnodes);
     1031                IssmDouble* thicknesses= xNew<IssmDouble>(numnodes);
     1032
     1033                element->GetInputListOnNodes(drainage_int,WaterfractionDrainageIntegratedEnum);
     1034                element->GetInputListOnNodes(thicknesses,ThicknessEnum);
     1035                for(k=0;k<numnodes;k++){
     1036                        drainage_int[k]*=thicknesses[k];
     1037                }
     1038                element->AddInput(WaterfractionDrainageIntegratedEnum, drainage_int, element->GetElementType());
     1039
     1040                xDelete<IssmDouble>(drainage_int);
     1041                xDelete<IssmDouble>(thicknesses);
     1042        }
     1043
     1044        /*update water column*/
     1045        for(i=0;i<femmodel->elements->Size();i++){
     1046                element=xDynamicCast<Element*>(femmodel->elements->GetObjectByOffset(i));
     1047                /* Check if ice in element */
     1048                if(!element->IsIceInElement()) continue;
     1049                if(!element->IsOnBase()) continue;
     1050
     1051                numnodes=element->GetNumberOfNodes();
     1052                IssmDouble* watercolumn= xNew<IssmDouble>(numnodes);
     1053                IssmDouble* drainage_int= xNew<IssmDouble>(numnodes);
     1054                element->GetInputListOnNodes(watercolumn,WatercolumnEnum);
     1055                element->GetInputListOnNodes(drainage_int,WaterfractionDrainageIntegratedEnum);
     1056
     1057                element->BasalNodeIndices(&numbasalnodes,&basalnodeindices,element->GetElementType());
     1058                for(k=0;k<numbasalnodes;k++){
     1059                        watercolumn[basalnodeindices[k]]+=dt*drainage_int[basalnodeindices[k]];
     1060                }
     1061                element->AddInput(WatercolumnEnum, watercolumn, element->GetElementType());
     1062
     1063                xDelete<IssmDouble>(watercolumn);
     1064                xDelete<IssmDouble>(drainage_int);
     1065        }
     1066        xDelete<int>(basalnodeindices);
     1067}/*}}}*/
     1068void                            EnthalpyAnalysis::DrainageUpdateEnthalpy(FemModel* femmodel){/*{{{*/
     1069
     1070        int i,k,numnodes;
     1071        IssmDouble dt;
     1072        Element* element= NULL;
     1073        femmodel->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
     1074
     1075        for(i=0;i<femmodel->elements->Size();i++){
     1076                element=xDynamicCast<Element*>(femmodel->elements->GetObjectByOffset(i));
     1077                numnodes=element->GetNumberOfNodes();
     1078                IssmDouble* enthalpies= xNew<IssmDouble>(numnodes);
     1079                IssmDouble* pressures= xNew<IssmDouble>(numnodes);
     1080                IssmDouble* temperatures= xNew<IssmDouble>(numnodes);
     1081                IssmDouble* waterfractions= xNew<IssmDouble>(numnodes);
     1082                IssmDouble* drainage= xNew<IssmDouble>(numnodes);
     1083
     1084                element->GetInputListOnNodes(enthalpies,EnthalpyEnum);
     1085                element->GetInputListOnNodes(pressures,PressureEnum);
     1086                element->GetInputListOnNodes(temperatures,TemperatureEnum);
     1087                element->GetInputListOnNodes(waterfractions,WaterfractionEnum);
     1088                element->GetInputListOnNodes(drainage,WaterfractionDrainageEnum);
     1089
     1090                for(k=0;k<numnodes;k++){
     1091                        waterfractions[k]-=dt*drainage[k];
     1092                        element->ThermalToEnthalpy(&enthalpies[k], temperatures[k], waterfractions[k], pressures[k]);
     1093                }
     1094                element->AddInput(WaterfractionEnum,waterfractions,element->GetElementType());
     1095                element->AddInput(EnthalpyEnum,enthalpies,element->GetElementType());
     1096
     1097                xDelete<IssmDouble>(enthalpies);
     1098                xDelete<IssmDouble>(pressures);
     1099                xDelete<IssmDouble>(temperatures);
     1100                xDelete<IssmDouble>(waterfractions);
     1101                xDelete<IssmDouble>(drainage);
     1102        }
    10901103}/*}}}*/
    10911104IssmDouble     EnthalpyAnalysis::EnthalpyDiffusionParameter(Element* element,IssmDouble enthalpy,IssmDouble pressure){/*{{{*/
  • issm/trunk-jpl/src/c/analyses/EnthalpyAnalysis.h

    r18930 r21721  
    3636                ElementVector*    CreatePVectorShelf(Element* element);
    3737                static void       DrainWaterfraction(FemModel* femmodel);
    38                 static void       DrainWaterfraction(Element* element, IssmDouble* pdrainrate_element);
    39                 static void       DrainWaterfractionIcecolumn(Element* element);
     38                static void       ComputeWaterfractionDrainage(FemModel* femmodel);
     39                static void       DrainageUpdateWatercolumn(FemModel* femmodel);
     40                static void       DrainageUpdateEnthalpy(FemModel* femmodel);
    4041                static IssmDouble EnthalpyDiffusionParameter(Element* element,IssmDouble enthalpy,IssmDouble pressure);
    4142                static IssmDouble EnthalpyDiffusionParameterVolume(Element* element,int enthalpy_enum);
  • issm/trunk-jpl/src/c/classes/Elements/Element.h

    r21720 r21721  
    5959                /*bool               AllActive(void);*/
    6060                /*bool               AnyActive(void);*/
    61                 void               BasalNodeIndices(int* pnumindices,int** pindices,int finiteelement){_error_("not implemented yet");};
    6261                void               ComputeLambdaS(void);
    6362                void               ComputeNewDamage();
     
    177176                virtual void       AddInput(int input_enum, IssmDouble* values, int interpolation_enum)=0;
    178177                virtual void       AverageOntoPartition(Vector<IssmDouble>* partition_contributions,Vector<IssmDouble>* partition_areas,IssmDouble* vertex_response,IssmDouble* qmu_part)=0;
     178                virtual void             BasalNodeIndices(int* pnumindices,int** pindices,int finiteelement){_error_("not implemented yet");};
    179179                virtual void       CalvingRateDev(void){_error_("not implemented yet");};
    180180                virtual void        CalvingRateLevermann(void)=0;
  • issm/trunk-jpl/src/c/shared/Enum/EnumDefinitions.h

    r21709 r21721  
    265265        StrainRateperpendicularEnum,
    266266        StrainRateeffectiveEnum,
     267        EffectiveViscosityEnum,
    267268        MaterialsRhoIceEnum,
    268269        MaterialsRhoSeawaterEnum,
     
    539540        TransientInputEnum,
    540541        WaterfractionEnum,
     542        WaterfractionDrainageEnum,
     543        WaterfractionDrainageIntegratedEnum,
    541544        WatercolumnEnum,
    542545        ViscousHeatingEnum,
  • issm/trunk-jpl/src/c/shared/Enum/EnumToStringx.cpp

    r21709 r21721  
    271271                case StrainRateperpendicularEnum : return "StrainRateperpendicular";
    272272                case StrainRateeffectiveEnum : return "StrainRateeffective";
     273                case EffectiveViscosityEnum : return "EffectiveViscosity";
    273274                case MaterialsRhoIceEnum : return "MaterialsRhoIce";
    274275                case MaterialsRhoSeawaterEnum : return "MaterialsRhoSeawater";
     
    537538                case TransientInputEnum : return "TransientInput";
    538539                case WaterfractionEnum : return "Waterfraction";
     540                case WaterfractionDrainageEnum : return "WaterfractionDrainage";
     541                case WaterfractionDrainageIntegratedEnum : return "WaterfractionDrainageIntegrated";
    539542                case WatercolumnEnum : return "Watercolumn";
    540543                case ViscousHeatingEnum : return "ViscousHeating";
  • issm/trunk-jpl/src/c/shared/Enum/StringToEnumx.cpp

    r21709 r21721  
    277277              else if (strcmp(name,"StrainRateperpendicular")==0) return StrainRateperpendicularEnum;
    278278              else if (strcmp(name,"StrainRateeffective")==0) return StrainRateeffectiveEnum;
     279              else if (strcmp(name,"EffectiveViscosity")==0) return EffectiveViscosityEnum;
    279280              else if (strcmp(name,"MaterialsRhoIce")==0) return MaterialsRhoIceEnum;
    280281              else if (strcmp(name,"MaterialsRhoSeawater")==0) return MaterialsRhoSeawaterEnum;
     
    382383              else if (strcmp(name,"SmbNumRequestedOutputs")==0) return SmbNumRequestedOutputsEnum;
    383384              else if (strcmp(name,"SmbRequestedOutputs")==0) return SmbRequestedOutputsEnum;
    384               else if (strcmp(name,"SmbIsInitialized")==0) return SmbIsInitializedEnum;
    385385         else stage=4;
    386386   }
    387387   if(stage==4){
    388               if (strcmp(name,"SmbDzini")==0) return SmbDziniEnum;
     388              if (strcmp(name,"SmbIsInitialized")==0) return SmbIsInitializedEnum;
     389              else if (strcmp(name,"SmbDzini")==0) return SmbDziniEnum;
    389390              else if (strcmp(name,"SmbDini")==0) return SmbDiniEnum;
    390391              else if (strcmp(name,"SmbReini")==0) return SmbReiniEnum;
     
    505506              else if (strcmp(name,"AndroidFrictionCoefficient")==0) return AndroidFrictionCoefficientEnum;
    506507              else if (strcmp(name,"ResetPenalties")==0) return ResetPenaltiesEnum;
    507               else if (strcmp(name,"SurfaceAbsVelMisfit")==0) return SurfaceAbsVelMisfitEnum;
    508508         else stage=5;
    509509   }
    510510   if(stage==5){
    511               if (strcmp(name,"SurfaceArea")==0) return SurfaceAreaEnum;
     511              if (strcmp(name,"SurfaceAbsVelMisfit")==0) return SurfaceAbsVelMisfitEnum;
     512              else if (strcmp(name,"SurfaceArea")==0) return SurfaceAreaEnum;
    512513              else if (strcmp(name,"SurfaceAverageVelMisfit")==0) return SurfaceAverageVelMisfitEnum;
    513514              else if (strcmp(name,"SurfaceLogVelMisfit")==0) return SurfaceLogVelMisfitEnum;
     
    549550              else if (strcmp(name,"TransientInput")==0) return TransientInputEnum;
    550551              else if (strcmp(name,"Waterfraction")==0) return WaterfractionEnum;
     552              else if (strcmp(name,"WaterfractionDrainage")==0) return WaterfractionDrainageEnum;
     553              else if (strcmp(name,"WaterfractionDrainageIntegrated")==0) return WaterfractionDrainageIntegratedEnum;
    551554              else if (strcmp(name,"Watercolumn")==0) return WatercolumnEnum;
    552555              else if (strcmp(name,"ViscousHeating")==0) return ViscousHeatingEnum;
     
    626629              else if (strcmp(name,"Outputdefinition26")==0) return Outputdefinition26Enum;
    627630              else if (strcmp(name,"Outputdefinition27")==0) return Outputdefinition27Enum;
    628               else if (strcmp(name,"Outputdefinition28")==0) return Outputdefinition28Enum;
    629               else if (strcmp(name,"Outputdefinition29")==0) return Outputdefinition29Enum;
    630               else if (strcmp(name,"Outputdefinition30")==0) return Outputdefinition30Enum;
    631631         else stage=6;
    632632   }
    633633   if(stage==6){
    634               if (strcmp(name,"Outputdefinition31")==0) return Outputdefinition31Enum;
     634              if (strcmp(name,"Outputdefinition28")==0) return Outputdefinition28Enum;
     635              else if (strcmp(name,"Outputdefinition29")==0) return Outputdefinition29Enum;
     636              else if (strcmp(name,"Outputdefinition30")==0) return Outputdefinition30Enum;
     637              else if (strcmp(name,"Outputdefinition31")==0) return Outputdefinition31Enum;
    635638              else if (strcmp(name,"Outputdefinition32")==0) return Outputdefinition32Enum;
    636639              else if (strcmp(name,"Outputdefinition33")==0) return Outputdefinition33Enum;
     
    749752              else if (strcmp(name,"ToolkitsOptionsStrings")==0) return ToolkitsOptionsStringsEnum;
    750753              else if (strcmp(name,"QmuErrName")==0) return QmuErrNameEnum;
    751               else if (strcmp(name,"QmuInName")==0) return QmuInNameEnum;
    752               else if (strcmp(name,"QmuOutName")==0) return QmuOutNameEnum;
    753               else if (strcmp(name,"Regular")==0) return RegularEnum;
    754754         else stage=7;
    755755   }
    756756   if(stage==7){
    757               if (strcmp(name,"Scaled")==0) return ScaledEnum;
     757              if (strcmp(name,"QmuInName")==0) return QmuInNameEnum;
     758              else if (strcmp(name,"QmuOutName")==0) return QmuOutNameEnum;
     759              else if (strcmp(name,"Regular")==0) return RegularEnum;
     760              else if (strcmp(name,"Scaled")==0) return ScaledEnum;
    758761              else if (strcmp(name,"Separate")==0) return SeparateEnum;
    759762              else if (strcmp(name,"Sset")==0) return SsetEnum;
     
    872875              else if (strcmp(name,"SpcTransient")==0) return SpcTransientEnum;
    873876              else if (strcmp(name,"StringArrayParam")==0) return StringArrayParamEnum;
    874               else if (strcmp(name,"StringParam")==0) return StringParamEnum;
    875               else if (strcmp(name,"Seg")==0) return SegEnum;
    876               else if (strcmp(name,"SegInput")==0) return SegInputEnum;
    877877         else stage=8;
    878878   }
    879879   if(stage==8){
    880               if (strcmp(name,"Tria")==0) return TriaEnum;
     880              if (strcmp(name,"StringParam")==0) return StringParamEnum;
     881              else if (strcmp(name,"Seg")==0) return SegEnum;
     882              else if (strcmp(name,"SegInput")==0) return SegInputEnum;
     883              else if (strcmp(name,"Tria")==0) return TriaEnum;
    881884              else if (strcmp(name,"TriaInput")==0) return TriaInputEnum;
    882885              else if (strcmp(name,"Tetra")==0) return TetraEnum;
     
    995998              else if (strcmp(name,"P1P1")==0) return P1P1Enum;
    996999              else if (strcmp(name,"P1P1GLS")==0) return P1P1GLSEnum;
    997               else if (strcmp(name,"MINI")==0) return MINIEnum;
    998               else if (strcmp(name,"MINIcondensed")==0) return MINIcondensedEnum;
    999               else if (strcmp(name,"TaylorHood")==0) return TaylorHoodEnum;
    10001000         else stage=9;
    10011001   }
    10021002   if(stage==9){
    1003               if (strcmp(name,"LATaylorHood")==0) return LATaylorHoodEnum;
     1003              if (strcmp(name,"MINI")==0) return MINIEnum;
     1004              else if (strcmp(name,"MINIcondensed")==0) return MINIcondensedEnum;
     1005              else if (strcmp(name,"TaylorHood")==0) return TaylorHoodEnum;
     1006              else if (strcmp(name,"LATaylorHood")==0) return LATaylorHoodEnum;
    10041007              else if (strcmp(name,"XTaylorHood")==0) return XTaylorHoodEnum;
    10051008              else if (strcmp(name,"OneLayerP4z")==0) return OneLayerP4zEnum;
Note: See TracChangeset for help on using the changeset viewer.