Validating components
Advanced topic - requires coding skills
Validation ensures that all parameters (public properties) are provided within desired ranges and that there are no warnings resulting from issues with the building of the simulation tree. This is designed to alert the user to potential problems before running the simulation. All validation errors and warnings are written to the Summary table of the data store and are displayed in the Messages section of the CLEM component information area.
APSIM does not currently provide a means of validating models before a simulation is run, so CLEM provides this functionality by performing a number of checks on all children of a CLEM component.

Validation is performed before the simulation starts and after the CLEMInitialiseResource and CLEMInitialiseActivity events as these may initialise resources needed for custom validation (see Events).

Validation is performed in ZoneClem.cs in the OnCLEMValidate() method subscribed to the CLEMValidate event of the CLEM Events component. This method tracks and reports all errors and warnings as an exception handled by APSIM.
The private Validate(Model model, string, Modelpath) method is used to perform validation and recursively step through all children below the ZoneCLEM component.
This method also formats all warning and error message strings for display with the CLEM message presenter.
This method uses the Validator.TryValidateObject() method to perform all validation on each model


Validation will be performed on any public property of components (APSIM IModel) based on validation attributes provided in the code
/// <summary>
/// Age in years.
/// </summary>
[Description("Initial Age")]
[Required, GreaterThanEqualValue(0)]
public double InitialAge { get; set; }
The example above states that this property is required and cannot be blank. The value supplied must also be greater than or equal to 0. This will produce default errors for these validations if they fail. The validation attributes can also include a custom message (ErrorMessage="example message").
All Microsoft validation attributes are available as well as the following custom versions:

The GreaterThanValue(value) attribute allows you to set a minimum value the property must be greater than

The GreaterThanEqualValue(value) attribute allows you to set a minimum value for the property

The LessThanValue(value) attribute allows you to set a maximum value the property must be less than

The LessThanEqualValue(value) attribute allows you to set a maximum value for the property

The GreaterThan(compareToFieldName) attribute allows you to ensure the value set is greater than another set value

The GreaterThanEqual(compareToFieldName) attribute allows you to ensure the value set is greater than or equal to another set value

The DateGreaterThan(dateToCompareFieldName) attribute allows you to ensure that the date value set for the property is greater than another set date

The Percentage attribute allows you to ensure that the value set is a valid percentage (0-100)

The Proportion attribute allows you to ensure that the value set is a valid proportion (0-1)

The Month attribute allows you to ensure that the value set is a valid month index (1-12)

The ArrayItemCount(int arrayItems) attribute ensures that the correct number of values is provided for an array

Any component implementing the IValidatableObject interface will provide the means of performing custom validation checks
/// <summary>
/// Validate component
/// </summary>
/// <param name="validationContext"></param>
/// <returns>List of validation errors</returns>
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if( criteria to check )
{
string[] memberNames = new string[] { ThisModelTypeAsString };
results.Add(new ValidationResult($"There was an error in this activity {this.Name}", memberNames));
}
return results;
}
This approach allows you to check for known issues and report errors. This will be performed after the CLEMInitialiseActivity and CLEMInitialiseActivity events have been performed.
You can add as many checks and logic to this section as is needed. This also allows you to ensure the component contains the correct children (now handled as an attribute) and the user has set everything up as expected.