unit erg_types;

interface

uses classes, SysUtils;

//The record directly corresponds to text in the files

type TExtraTagsRecord = record
  TagNames: TStringList;
  TagValues: TStringList;
end;

TRecordWithExtraTags = class
  public
    name:              String;
    ExtraTagsRecord:   TExtraTagsRecord;
    constructor Create;
    procedure setExtraTagsRecord(ExtraTagsRecord: TExtraTagsRecord);
end;

const
    FORBIDDEN_TAGNAMES: array [1..2] of string = ('name', 'element');


type TErgConstant = class(TRecordWithExtraTags)
//  name:           String;  //Fortran constant name
  value:          Real;
  dependsOn:      String;  //whether this constant varies locally, default="none", other possible values: "xyz", "xyzt"
  minval:         Real;    //minimum value for variation
  maxval:         Real;    //maximum value for variation
  varphase:       Integer; //phase in which this constant is allowed to vary (default=1)
  valueString:    String;
  description:    String;  //description including unit
  comment:        String;  //e.g. how exact this constant is, literature,...
  myIsSelected:   Boolean; //whether this is needed to calculate selected processes
  myIsMissingInDocumentation: Boolean; //whether this will be hidden in the documentation because it is identical to its siblings (for vector constants)
  myDescriptionInDocumentation: String; //if it has siblings which are hidden, this will be noted in this string which replaces the original description
  valUnit:        String;  // unit of the constant
end;

type TErgElement = class(TRecordWithExtraTags)
  //name:           String;  //e.g. "N"
  description:    String;  //e.g. "nitrogen"
  comment:        String;  //e.g. how exact this constant is, literature,...
  isColored:      Integer; //0 uncolored; 1 colored
  hasColoredCopies:   Integer; // TODO this element is colored or a colored version of this element exists
  parentElement:  Integer;
end;

type TErgTracerContent=record
  element:        String;  //e.g. "N"
  amount:         String;  //either name of ErgConstant or real number,
                           //describes how many element units are contained in one tracer unit
  myElementNum:   Integer;
  myAmount:       Real;
end;

type TErgTracer = class(TRecordWithExtraTags)
  //name:           String;  //fortran variable name
  description:       String;  //e.g. "flaggelates"
  comment:        String;  //e.g. "represents phytoplankton from ...mym to ...mym"
  solubility:     String;  //solubility [mol/kg/Pa] for gasses, specify the name of an auxiliary variable with vertLoc=WAT or SUR, default=0 meaning no exchange with the atmosphere
  schmidtNumber:  String;  //Schmidt number [1] for gasses, specify the name of an auxiliary variable with vertLoc=WAT or SUR, default=0 meaning no exchange with the atmosphere
  gasName:        String;  //Name of an auxiliary variable containing the dissolved gas concentration in the surface layer, e.g. "co2" for tracer "dic". Default="" meaning it is the tracer itself.
  molarMass:      String;  //molar mass of the gas [g/mol], used for surface flux calculation. Default=0.0
  initValue:      String;  //initial value, default="0.0", set "useInitValue" to 1 to use it
  useInitValue:   Integer; //1=use "initValue" as initial concentration, 0=do not (default)
  contents:       Array of TErgTracerContent;  //what elements are contained in one tracer unit
  verticalDistribution: String; //Name of an auxiliary variable proportional to which the vertical distribution of the tracer is assumed. Relevant for vertLoc=FIS only. Default='1.0'
  vertSpeed:      String;  //fortran formula for vertical speed in m/day, default="0"
  vertDiff:       String;  //fortran formula for vertical speed in m2/s2, default="0"
  opacity:        String;  //fortran formula for opacity (for light limitation), default="0"
  vertLoc:        Integer; //0=z-dependent, 1=benthos, 2=surface, 3=pseudo-3d tracer
  isInPorewater:  Integer; //1=dissolved species which is also present in porewater, 0=not (particulate species) (default)
  isPositive:     Integer; //0=may be negative, 1=always positive
  isMixed:        Integer; //1=mixed with neighbour cells if negative, 0=not, default=isPositive
  isCombined:     Integer; //1=combined tracer that accumulates several virtual tracers in one variable, its contents are tracers rather than elements; 0=not (default)
  isStiff:        Integer; //0=not stiff (default); 1=stiff, use Patankar method if concentration declines; 2=stiff, always use modified Patankar method
  childOf:        String;  //e.g. red_N_in_flag has childOf=flag, default="none"
  dimension:      Integer; //how many instances of this tracer exist, e.g. a tracer named "cod" with dimension=2 exists as "cod_$cod" which is "cod_1" and "cod_2", default=0
  massLimits:     String;  //semicolon-seperated string of (dimension-1) fortran expressions for mass limits for stage-resolving models [mmol], default=""
  atmosDep:       Integer; //0=no atmospheric deposition (default), 1=atmospheric deposition
  riverDep:       Integer; //0=no river deposition, 1=river deposition (default)
  isOutput:       Integer; //1=output occurs in model results (default); 0=only internal use
  isActive:       Integer; //1=active (default); 0=tracer is only virtual (source or sink for mass conservation)
  molDiff:        String;  //molecular diffusivity in pore water, use the name of a vertLoc=SED auxiliary variable, default="0.0"
  tracerAbove:    String;  //name of corresponding tracer in the compartment above, default="none" (e.g. "det" (in water column) if we are "benth_det")
  tracerBelow:    String;  //name of corresponding tracer in the compartment below, default="none" (e.g. "nit" (in water column) if we are "surf_nit")
  longname:       String;  //long name (e.g. 'nitrate' for 'nit'); should be used in cf conventions; <standardname>=stdname_prefix+longname+stdname_suffix
  stdname_prefix: String;  //prefix for the cf-convention standardname; <standardname>=stdname_prefix+longname+stdname_suffix
  stdname_suffix: String;  //suffix for the cf-convention standardname; <standardname>=stdname_prefix+longname+stdname_suffix
  outputUnit:     String;  //unit inserted by the <unit>-tag; should be in accordance with cf-conventions
  myChildOf:      Integer; //the number of the tracer of childOf
  myTracerAbove:  Integer; //the number of the tracer of tracerAbove
  myTracerBelow:  Integer; //the number of the tracer of tracerBelow
  numChildren:    Integer; // the number of children this tracer has
  myRateList:     Array of String;
  myVertspeedValue: Real; //the value of VertSpeed, or, if it cannot be found out, zero.
  myOpacityValue: Real; //the value of opacity, or, if it cannot be found out, zero.
  myCalcBeforeZIntegral: integer; //1=needed for calculation of an auxiliary variable with isZIntegral=1. This value is set automatically.
  myIsSelected:   Boolean; //whether this is needed to calculate selected processes, or changed by them
end;

type tErgAuxiliary = class(TRecordWithExtraTags)
  //name:           String;  //fortran variable name
  temp:           Array[1..9] of String; //temp1, ..., temp9 are temporary variables which are calculated first and then used in "formula".
  formula:        String;  //fortran formula
  calcAfterProcesses: integer; //1=calculate this auxiliary variable after all process have been calculated. 0=calculate it before (default).
  description:    String;  //description: what is calculated here
  comment:        String;  //e.g. a literature reference
  iterations:     Integer; //how often this auxiliary variable is calculated in an iterative loop, default=0
  iterInit:       String;  //the initial value in the iterative loop, default='0.0'
  vertLoc:        Integer; //0=z-dependent, 1=benthos, 2=surface
  isOutput:       Integer; //1=output occurs in model results; 0=only internal use (default)
  isUsedElsewhere:Integer; //1=store it to access it from outside the biomodule; 0=only internal use (default)
  isZGradient:    Integer; //1=is a vertical gradient of a tracer, 0=is not (default). If 1 "formula" must be the name of the tracer, which must have vertLoc=WAT. Setting isZGradient to 1 requires vertLoc=WAT.
  isZIntegral:    Integer; //1=is a vertical integral (of value times density) of a tracer or an auxiliary variable, 0=is not (default). If 1 "formula" must be the name of the tracer, which must have vertLoc=WAT. Setting isZIntegral to 1 requires vertLoc=WAT.
  myCalcBeforeZIntegral: integer; //1=needed for calculation of another auxiliary variable with isZIntegral=1. This value is set automatically.
  myIsSelected:   Boolean; //whether this is needed to calculate selected processes
  myIsMissingInDocumentation: Boolean; //whether this will be hidden in the documentation because it is identical to its siblings (for vector constants)
  myDescriptionInDocumentation: String; //if it has siblings which are hidden, this will be noted in this string which replaces the original description
  valUnit:           String;  // unit of the auxiliary variable
end;

type tErgProcessIO=record
  tracer:         String;  //fortran variable name for the rate
  amount:         String;  //either name of ErgConstant or real number,
                           //describes how many tracer units are created/destroyed.
  myTracerNum:    Integer;
  myAmount:       Real;
end;

type tErgProcessRepaint=record
  oldColor:       String;  //name of old color or "all"
  element:        String;  //name of Element or "all"
  newColor:       String;  //name of new color or "none"

  myElementNum:   Integer;     //-2=all
end;

type tErgLimitation=record
  limitationType: String; //HARD, MM, MMQ, IVLEV, IVLEVQ, LIN, TANH
  tracer:         String; //name of limiting tracer
  value:          String; //thresold value

  myTracerNum:    Integer; //number of limiting tracer
  myIsSelected:   Boolean; //whether this is needed to calculate selected processes
end;

type tErgProcessLimitation=record
  limitationNum:  Integer;   //index in array "limitations[i]"
  tracerIsSmall:  Integer;   //0=o2 > o2_lim (default), 1=o2 < o2_lim
  elseProcess:    String;    //which process takes place instead if this limitation gets active

  myElseProcessNum: Integer; //number of process that takes place otherwise
  myElseProcessRatio: String; //ratio of process speed between replacement process and original process, default='' meaning 1
end;

type tErgProcess = class(TRecordWithExtraTags)
  //name:           String;  //fortran variable name for the process turnover
  description:       String;  //e.g. "grazing of zooplankton"
  turnover:       String;  //fortran formula for calculating the turnover
  comment:        String;  //comment
  input:          Array of tErgProcessIO;
  output:         Array of tErgProcessIO;
  repaint:        Array of tErgProcessRepaint;
  limitations:    Array of tErgProcessLimitation;
  feedingEfficiency: String; //Name of an auxiliary variable with values 0..1 which tells how much of the food in a certain depth is available for the predator. Relevant for vertLoc=FIS only. Default='1.0'
  vertLoc:        Integer; //0=z-dependent, 1=benthos, 2=surface
  processType:    String;  //type of process, e.g. "propagation"
  isOutput:       Integer; //1=output occurs in model results; 0=only internal use (default)
  isActive:       Integer; //1=active (default); 0=process is switched off
  myIsInPorewater:Integer; //whether a process with vertLoc=WAT can take place in the pore water - it cannot if one of its tracers has isInPorewater=0
  myIsStiff:      Integer; //if a tracer in input has isStiff<>0, myIsStiff is set to that value
  myStiffTracerNum: Integer; // -1 by default, but the number of the consumed stiff tracer, if one exists.
  myStiffFactor:  String; // the patankar factor with which the stiff process is multiplied, otherwise "1.0".
  myIsSelected:   Boolean; //false=not selected (default); true=selected to see which tracers, auxiliaries and constants it needs and which tracers it modifies
  myIsMissingInDocumentation: Boolean; //whether this will be hidden in the documentation because it is identical to its siblings (for vector constants)
  myDescriptionInDocumentation: String; //if it has siblings which are hidden, this will be noted in this string which replaces the original description
end;

type tErgCElement = class(TRecordWithExtraTags)
  element:         String;  //e.g. "N"
  color:           String;  //e.g. "red"
  description:     String;  //e.g. "nitrogen from Oder river"
  isTracer:        String;  //1=summed up in an additional tracer, 0=not; isAging=1 overrides this to isTracer=1
  isAging:         String;  //0=not aging, 1=aging
  atmosDep:        Integer; //1=atmospheric deposition possible, 0=not
  riverDep:        Integer; //1=river deposition possible, 0=not
  longname_prefix: String;  // prefix to be prepended to a tracer's longname when painted; '' is default
  longname_suffix: String;  // suffix to be appended to a tracer's longname when painted; '' is default (longname gets same suffix as name)
  comment:         String;  //e.g. how exact this constant is, literature,...
  duplicatedTracers: String; //"all" (default) or a semicolon-separated list of tracer names

  myIsTracer:      Integer;
  myIsAging:       Integer;
  myElementNum:    Integer;
end;

type TErgModelInfo=class(TRecordWithExtraTags)
  //name:           String;  //model name or abbreviation
  version:        String;  //model Version
  description:    String;  //long version of the model name
  author:         String;  //author(s) of the model
  contact:        String;  //e.g. e-mail adress of the author
  templatePath:   String;  //path to the code template files
  outputPath:     String;  //path where to write the output files
  autoLimitProcesses:Integer;//1=add limitations to all processes that stop them when one of their precursors with isPositive=1 becomes zero (default); 0=do not
  autoMassClassProp:Integer; //0=manual mass-class propagation processes (default); 1=mass-class propagation when upper mass limit is reached; 2=advanced propagation; 3=age-class propagation at beginning of each year
  autoSplitColors:  Integer; //1=split tracers and processes according to colored elements (default); 0=do not
  autoSortMoving:   Integer; //1=automatically sort tracers (not vertically moving first, then vertically moving ones)
  debugMode:        Integer; //1=debug mode (output of all values); 0=output only of those values with output=1 (default)
  autoWrapF:        Integer; //1=auto-wrap too long lines in all files with ".f" or ".F" extension (default); 0=do not
  autoWrapF90:      Integer; //1=auto-wrap too long lines in all files with ".f90" or ".F90" extension; 0=do not (default)
  autoUnixOutput:   Integer; //1=enforce Unix line-feed output on Windows systems; 0=do not (default)
  RealSuffixF90:    String;  //append a suffix (e.g. _8) to all real values which do not yet contain a suffix; do not include the underscore here; default='' meaning no suffix is added.
  ageEpsilon:     String;  //small value used for preventing zero division for age calculation; default="1.0e-15"
  inactiveProcessTypes: String; //semicolon-separated list of process types that are switched off, e.g. because they are considered in the host model
  numPhysicalParametersVarying: Integer; //how many physical parameters are allowed to vary in an inverse-modelling approach, default=0
  mySelectedProcessType: String; //typically an empty string; when output is generated separated by process type, this will store the currently active one
  conversionFactorSED: String; //factor to convert between vertLoc=WAT and vertLoc=SED tracers, default="(cgt_cellheight*cgt_density)"
  conversionFactorSUR: String; //factor to convert between vertLoc=WAT and vertLoc=SUR tracers, default="(cgt_cellheight*cgt_density)"
  comment: String;
end;

//procedure initErgExtraTags(var e: TErgExtraTags);
procedure initErgConstant(var c: TErgConstant);
procedure initErgElement(var e: TErgElement);
procedure initErgTracerContent(var tc: TErgTracerContent);
procedure initErgTracer(var t: TErgTracer);
procedure initErgAuxiliary(var a: TErgAuxiliary);
procedure initErgProcessIO(var pio: TErgProcessIO);
procedure initErgProcessRepaint(var prp: TErgProcessRepaint);
procedure initErgProcess(var p: TErgProcess);
procedure initErgCElement(var ce: TErgCElement);
procedure initErgModelinfo(var m: TErgModelInfo);

//procedure copyErgExtraTags(q: tErgExtraTags; var e: TErgExtraTags);
procedure copyErgConstant(q: tErgConstant; var c: TErgConstant);
procedure copyErgElement(q: tErgElement; var e: TErgElement);
procedure copyErgTracerContent(q: tErgTracerContent; var tc: TErgTracerContent);
procedure copyErgTracer(q: tErgTracer; var t: TErgTracer);
procedure copyErgAuxiliary(q: tErgAuxiliary; var a: TErgAuxiliary);
procedure copyErgProcessIO(q: tErgProcessIO; var pio: TErgProcessIO);
procedure copyErgProcessRepaint(q: tErgProcessRepaint; var prp: TErgProcessRepaint);
procedure copyErgProcess(q: tErgProcess; var p: TErgProcess);
procedure copyErgCElement(q: tErgCElement; var ce: TErgCElement);
procedure copyErgModelinfo(q: tErgModelInfo; var m: TErgModelInfo);
procedure copyExtraTagsRecord(q: TExtraTagsRecord; var c: TExtraTagsRecord);

function validTagName(TagName: String): boolean;

implementation

function validTagName(TagName: String): boolean;
var
  i_forbid: integer;
begin
  for i_forbid := 1 to Length(FORBIDDEN_TAGNAMES) do
    if FORBIDDEN_TAGNAMES[i_forbid] = lowercase(TagName) then
      EXIT(FALSE);
  EXIT(TRUE);
end;

//This function is the same for all derived classes
procedure TRecordWithExtraTags.setExtraTagsRecord(ExtraTagsRecord: TExtraTagsRecord);
begin
  Self.ExtraTagsRecord := ExtraTagsRecord;
end;

constructor TRecordWithExtraTags.Create;
begin
  FreeAndNil(ExtraTagsRecord.TagNames);
  FreeAndNil(ExtraTagsRecord.TagValues);
  ExtraTagsRecord.TagNames := TStringList.Create;
  ExtraTagsRecord.TagValues := TStringList.Create;
end;

procedure initErgConstant(var c: TErgConstant);
begin
  c := TErgConstant.Create;

  c.name:='';
  c.value:=0;
  c.dependsOn:='none';
  c.minval:=-1e20;
  c.maxval:=-1e20;
  c.varphase:=1;
  c.valueString:='';
  c.description:='';
  c.comment:='';
  c.myIsSelected:=false;
  c.myIsMissingInDocumentation:=false;
  c.myDescriptionInDocumentation:='';
  c.valUnit:='';
end;

procedure initErgElement(var e: TErgElement);
begin
  e := TErgElement.Create;
  e.name:='';
  e.description:='';
  e.comment:='';
  e.isColored:=0;
  e.hasColoredCopies:=0;
  e.parentElement:=-1;
end;

procedure initErgTracerContent(var tc: TErgTracerContent);
begin
  tc.element:='';
  tc.amount:='0';
end;

procedure initErgTracer(var t: TErgTracer);
begin
  t := TErgTracer.Create;

  t.name:='';
  t.description:='';
  t.comment:='';
  t.solubility:='0';
  t.schmidtNumber:='0';
  t.gasName:='';
  t.molarMass:='0.0';
  t.initValue:='0.0';
  t.useInitValue:=0;
  setLength(t.contents,0);
  t.verticalDistribution:='1.0';
  t.vertSpeed:='0';
  t.vertDiff:='0';
  t.opacity:='0';
  t.vertLoc:=0;
  t.isInPorewater:=0;
  t.isPositive:=1;
  t.isMixed:=1;
  t.isCombined:=0;
  t.isStiff:=0;
  t.childOf:='none';
  t.myChildOf:=-1;
  t.dimension:=0;
  t.massLimits:='';
  t.atmosDep:=0;
  t.riverDep:=1;
  t.isOutput:=1;
  t.isActive:=1;
  t.molDiff:='0.0';
  t.tracerAbove:='none';
  t.tracerBelow:='none';
  t.longname:=t.name;
  t.stdname_prefix:='concentration_of_';
  t.stdname_suffix:='';
  t.outputUnit:='';
  t.myTracerAbove:=-1;
  t.myTracerBelow:=-1;
  t.numChildren:=0;
  setLength(t.myRateList,0);
  t.myCalcBeforeZIntegral:=0;
  t.myIsSelected:=false;
end;

procedure initErgAuxiliary(var a: TErgAuxiliary);
var
  i: Integer;
begin
  a := TErgAuxiliary.Create;

  a.name:='';
  for i:=1 to 9 do
    a.temp[i]:='';
  a.formula:='0';
  a.calcAfterProcesses:=0;
  a.iterations:=0;
  a.iterInit:='0.0';
  a.description:='';
  a.comment:='';
  a.vertLoc:=0;
  a.isOutput:=0;
  a.isUsedElsewhere:=0;
  a.isZGradient:=0;
  a.isZIntegral:=0;
  a.myCalcBeforeZIntegral:=0;
  a.myIsSelected:=false;
  a.myIsMissingInDocumentation:=false;
  a.myDescriptionInDocumentation:='';
  a.valUnit:='';
end;

procedure initErgProcessIO(var pio: TErgProcessIO);
begin
  pio.tracer:='';
  pio.amount:='1';
end;

procedure initErgProcessRepaint(var prp: TErgProcessRepaint);
begin
  prp.oldColor:='all';
  prp.element:='all';
  prp.newColor:='none';
  prp.myElementNum:=-1;
end;

procedure initErgProcess(var p: TErgProcess);
begin
  p := TErgProcess.Create;

  p.name:='';
  p.description:='';
  p.turnover:='0';
  p.comment:='';
  setLength(p.input,0);
  setLength(p.output,0);
  setLength(p.repaint,0);
  setLength(p.limitations,0);
  p.feedingEfficiency:='1.0';
  p.vertLoc:=0;
  p.processType:='standard';
  p.isOutput:=0;
  p.isActive:=1;
  p.myIsSelected:=false;
  p.myIsMissingInDocumentation:=false;
  p.myDescriptionInDocumentation:='';
end;

procedure initErgCElement(var ce: TErgCElement);
begin
  ce := TErgCElement.Create;
  ce.element:='';
  ce.name:=ce.element;
  ce.color:='';
  ce.description:='';
  ce.isTracer:='0';
  ce.isAging:='0';
  ce.atmosDep:=0;
  ce.riverDep:=0;
  ce.longname_prefix:='';
  ce.longname_suffix:='';
  ce.duplicatedTracers:='all';
  ce.myElementNum:=-1;
  ce.myIsAging:=0;
  ce.myIsTracer:=0;
  ce.comment:='';
end;

procedure initErgModelInfo(var m: TErgModelInfo);
begin
  m := TErgModelInfo.Create;

  m.name:='';
  m.version:='';
  m.description:='';
  m.author:='';
  m.contact:='';
  m.templatePath:='';
  m.outputPath:='';
  m.autoLimitProcesses:=1;
  m.autoMassClassProp:=0;
  m.autoSplitColors:=1;
  m.autoSortMoving:=0;
  m.debugMode:=0;
  m.autoWrapF:=1;
  m.autoWrapF90:=0;
  m.RealSuffixF90:='';
  m.autoUnixOutput:=0;
  m.ageEpsilon:='1.0e-20';
  m.inactiveProcessTypes:='';
  m.numPhysicalParametersVarying:=0;
  m.mySelectedProcessType:='';
  m.conversionFactorSED:='(cgt_cellheigt*cgt_density)';
  m.conversionFactorSUR:='(cgt_cellheigt*cgt_density)';
  m.comment:='';
end;

//******** copying routines follow *****************************************//

procedure copyExtraTagsRecord(q: TExtraTagsRecord; var c: TExtraTagsRecord);
var
  i_tag: Integer;
begin
  if not Assigned(q.TagNames) then
    q.TagNames := TStringList.Create;
  if not Assigned(q.TagValues) then
    q.TagValues := TStringList.Create;

  if Assigned(c.TagNames) then
    c.TagNames.Free;
  c.TagNames := TStringList.Create;

  if Assigned(c.TagValues) then
    c.TagValues.Free;
  c.TagValues := TStringList.Create;

  for i_tag := 0 to q.TagNames.Count -1 do
  begin
    c.TagNames.Add( q.TagNames[i_tag] );
    c.TagValues.Add( q.TagValues[i_tag] );
  end;
end;

procedure copyErgConstant(q: tErgConstant; var c: TErgConstant);
begin
  c.name:=q.name;
  c.value:=q.value;
  c.dependsOn:=q.dependsOn;
  c.minval:=q.minval;
  c.maxval:=q.maxval;
  c.varphase:=q.varphase;
  c.valueString:=q.valueString;
  c.description:=q.description;
  c.comment:=q.comment;
  c.myIsSelected:=q.myIsSelected;
  c.myIsMissingInDocumentation:=q.myIsMissingInDocumentation;
  c.myDescriptionInDocumentation:=q.myDescriptionInDocumentation;
  c.valUnit:=q.valUnit;

  copyExtraTagsRecord(q.ExtraTagsRecord, c.ExtraTagsRecord);
end;

procedure copyErgElement(q: tErgElement; var e: TErgElement);
begin
  e.name:=q.name;
  e.description:=q.description;
  e.comment:=q.comment;
  e.isColored:=q.isColored;
  e.hasColoredCopies:=q.hasColoredCopies;
  e.parentElement:=q.parentElement;

  copyExtraTagsRecord(q.ExtraTagsRecord, e.ExtraTagsRecord);
end;

procedure copyErgTracerContent(q: tErgTracerContent; var tc: TErgTracerContent);
begin
  tc.element:=q.element;
  tc.amount:=q.amount;
end;

procedure copyErgTracer(q: tErgTracer; var t: TErgTracer);
var i: Integer;
begin
  t.name:=q.name;
  t.description:=q.description;
  t.comment:=q.comment;
  t.solubility:=q.solubility;
  t.schmidtNumber:=q.schmidtNumber;
  t.gasName:=q.gasName;
  t.molarMass:=q.molarMass;
  t.initValue:=q.initValue;
  t.useInitValue:=q.useInitValue;
  setLength(t.contents,length(q.contents));
  for i:=0 to length(q.contents)-1 do
    copyErgTracerContent(q.contents[i],t.contents[i]);
  t.verticalDistribution:=q.verticalDistribution;
  t.vertSpeed:=q.vertSpeed;
  t.vertDiff:=q.vertDiff;
  t.opacity:=q.opacity;
  t.vertLoc:=q.vertLoc;
  t.isInPorewater:=q.isInPorewater;
  t.isPositive:=q.isPositive;
  t.isMixed:=q.isMixed;
  t.isCombined:=q.isCombined;
  t.isStiff:=q.isStiff;
  t.childOf:=q.childOf;
  t.myChildOf:=q.myChildOf;
  t.dimension:=q.dimension;
  t.massLimits:=q.massLimits;
  t.atmosDep:=q.atmosDep;
  t.riverDep:=q.riverDep;
  t.isOutput:=q.isOutput;
  t.isActive:=q.isActive;
  t.molDiff:=q.molDiff;
  t.tracerAbove:=q.tracerAbove;
  t.tracerBelow:=q.tracerBelow;
  t.longname:=q.longname;
  t.stdname_prefix:=q.stdname_prefix;
  t.stdname_suffix:=q.stdname_suffix;
  t.outputUnit:=q.outputUnit;
  t.myTracerAbove:=q.myTracerAbove;
  t.myTracerBelow:=q.myTracerBelow;
  t.numChildren:=q.numChildren;
  setLength(t.myRateList,length(q.myRateList));
  for i:=0 to length(q.myRateList)-1 do
    t.myRateList[i]:=q.myRateList[i];
  t.myCalcBeforeZIntegral:=q.myCalcBeforeZIntegral;
  t.myIsSelected:=q.myIsSelected;
  copyExtraTagsRecord(q.ExtraTagsRecord, t.ExtraTagsRecord);
end;

procedure copyErgAuxiliary(q: tErgAuxiliary; var a: TErgAuxiliary);
var
  i: Integer;
begin
  a.name:=q.name;
  for i:=1 to 9 do
    a.temp[i]:=q.temp[i];
  a.formula:=q.formula;
  a.calcAfterProcesses:=q.calcAfterProcesses;
  a.iterations:=q.iterations;
  a.iterInit:=q.iterInit;
  a.description:=q.description;
  a.comment:=q.comment;
  a.vertLoc:=q.vertLoc;
  a.isOutput:=q.isOutput;
  a.isUsedElsewhere:=q.isUsedElsewhere;
  a.isZGradient:=q.isZGradient;
  a.isZIntegral:=q.isZIntegral;
  a.myCalcBeforeZIntegral:=q.myCalcBeforeZIntegral;
  a.myIsSelected:=q.myIsSelected;
  a.myIsMissingInDocumentation:=q.myIsMissingInDocumentation;
  a.myDescriptionInDocumentation:=q.myDescriptionInDocumentation;
  a.valUnit:=q.valUnit;
  copyExtraTagsRecord(q.ExtraTagsRecord, a.ExtraTagsRecord);
end;

procedure copyErgProcessIO(q: tErgProcessIO; var pio: TErgProcessIO);
begin
  pio.tracer:=q.tracer;
  pio.amount:=q.amount;
end;

procedure copyErgProcessRepaint(q: tErgProcessRepaint; var prp: TErgProcessRepaint);
begin
  prp.oldColor:=q.oldColor;
  prp.element:=q.element;
  prp.newColor:=q.newColor;
  prp.myElementNum:=q.myElementNum;
end;

procedure copyErgProcess(q: tErgProcess; var p: TErgProcess);
var i: Integer;
begin
  p.name:=q.name;
  p.description:=q.description;
  p.turnover:=q.turnover;
  p.comment:=q.comment;
  setLength(p.input,length(q.input));
  for i:=0 to length(q.input)-1 do
    copyErgProcessIO(q.input[i],p.input[i]);
  setLength(p.output,length(q.output));
  for i:=0 to length(q.output)-1 do
    copyErgProcessIO(q.output[i],p.output[i]);
  setLength(p.repaint,length(q.repaint));
  for i:=0 to length(q.repaint)-1 do
    copyErgProcessRepaint(q.repaint[i],p.repaint[i]);
  setLength(p.limitations,length(q.limitations));
  for i:=0 to length(q.limitations)-1 do
    p.limitations[i]:=q.limitations[i];
  p.feedingEfficiency:=q.feedingEfficiency;
  p.vertLoc:=q.vertLoc;
  p.processType:=q.processType;
  p.isOutput:=q.isOutput;
  p.isActive:=q.isActive;
  p.myIsSelected:=q.myIsSelected;
  p.myIsMissingInDocumentation:=q.myIsMissingInDocumentation;
  p.myDescriptionInDocumentation:=q.myDescriptionInDocumentation;
  copyExtraTagsRecord(q.ExtraTagsRecord, p.ExtraTagsRecord);
end;

procedure copyErgCElement(q: tErgCElement; var ce: TErgCElement);
begin
  ce.element:=q.element;
  ce.name := ce.element;
  ce.color:=q.color;
  ce.description:=q.description;
  ce.isTracer:=q.isTracer;
  ce.isAging:=q.isAging;
  ce.atmosDep:=q.atmosDep;
  ce.riverDep:=q.riverDep;
  ce.longname_prefix:=q.longname_prefix;
  ce.longname_suffix:=q.longname_suffix;
  ce.duplicatedTracers:=q.duplicatedTracers;
  ce.myElementNum:=q.myElementNum;
  ce.myIsAging:=q.myIsAging;
  ce.myIsTracer:=q.myIsTracer;
  ce.comment:=q.comment;
  copyExtraTagsRecord(q.ExtraTagsRecord, ce.ExtraTagsRecord);
end;

procedure copyErgModelinfo(q: tErgModelInfo; var m: TErgModelInfo);
begin
  m.name:=q.name;
  m.version:=q.version;
  m.description:=q.description;
  m.author:=q.author;
  m.contact:=q.contact;
  m.templatePath:=q.templatePath;
  m.outputPath:=q.outputPath;
  m.autoLimitProcesses:=q.autoLimitProcesses;
  m.autoMassClassProp:=q.autoMassClassProp;
  m.autoSplitColors:=q.autoSplitColors;
  m.autoSortMoving:=q.autoSortMoving;
  m.debugMode:=q.debugMode;
  m.autoWrapF:=q.autoWrapF;
  m.autoWrapF90:=q.autoWrapF90;
  m.autoUnixOutput:=q.autoUnixOutput;
  m.ageEpsilon:=q.ageEpsilon;
  m.inactiveProcessTypes:=q.inactiveProcessTypes;
  m.numPhysicalParametersVarying:=q.numPhysicalParametersVarying;
  m.mySelectedProcessType:=q.mySelectedProcessType;
  m.comment:=q.comment;
  m.conversionFactorSED:=q.conversionFactorSED;
  m.conversionFactorSUR:=q.conversionFactorSUR;
  copyExtraTagsRecord(q.ExtraTagsRecord, m.ExtraTagsRecord);
end;

end.

