Skip to content
Anatoliy Yermakov edited this page May 14, 2024 · 6 revisions

NPKTools

Logo

NPKTools is developed on the .NET platform and helps adjust the ratios of various fertilizers to achieve the desired PPM (parts per million) profile. Additionally, it is capable of calculating the PPM of a mixture of fertilizers.

Features:

NPKTools.Optimizer

  • The Optimizer is composed of three main components: an adapter, a mapper, and a solver. It takes a nutrient target in NPK values, a list of available fertilizers, and specific precision settings as inputs to calculate the optimal fertilizer mix. Here's how the flow works with these components:
  • Mapper: This component converts the high-level nutrient targets and the list of available fertilizers into a structured optimization problem. It translates real-world data about fertilizers and nutrient requirements into mathematical variables, constraints, and objectives suitable for optimization. After the solver processes these, the mapper also translates the optimized mathematical solution back into practical terms, specifying exact quantities of each fertilizer to use.
  • Solver: Once the optimization problem is defined, this component uses mathematical algorithms to find the best combination of fertilizers. The solver processes the variables and constraints set by the mapper to minimize or maximize the objective function, typically focusing on cost efficiency or nutrient precision.
  • Adapter: Acts as the bridge between the domain-specific data (fertilizers and nutrient targets) and the optimization tools. It takes the problem as defined by the mapper, passes it to the solver for optimization, and then interprets the output from the solver back into a practical solution, detailing the specific amounts of each fertilizer to use to achieve the nutrient targets.
  • Together, these components ensure that the FertilizerOptimizer effectively integrates and processes the inputs to produce an optimized fertilizer mix that meets the specified NPK goals with the required precision.

NPKTools.PpmCalc

  • The PpmCalculationService is a component in the NPKOptimizer software that calculates the concentration of various nutrients in parts per million (ppm) when a specified collection of fertilizers is diluted in a given volume of water. This service is essential for users who need to understand the nutrient composition of their fertilizer solutions to ensure optimal plant growth.
  • Key Functions: Nutrient Calculation: It computes the ppm concentrations of major and minor plant nutrients including nitrogen (in forms of nitrate, ammonium, and amine), phosphorus, potassium, magnesium, sulfur, calcium, and trace elements such as iron, copper, manganese, zinc, boron, molybdenum, chlorine, silicon, selenium, and sodium. Flexible Dilution: Users can specify the volume of water in liters for the dilution process. This flexibility allows for accurate adjustment of nutrient concentrations based on different watering needs or systems.

NPKTools.Optimizer.Preset

  • FertilizerOptimizationService is an preconfigured version of the FertilizerOptimizer. It includes:
  • 17 basic types of macronutrient fertilizers combined into 18 different sets to optimize the selection process.
  • 17 types of micronutrient fertilizers grouped into four main sets: basic, sulfate, nitrate, and chelated.
  • During the selection of macronutrient fertilizers, the service conducts two searches: in the first, sulfur is accounted for as specified, while the second search excludes sulfur coefficients to expand the possible options.

NPKTools.Optimizer.PpmTargetParser

  • Project primarily focuses on parsing strings that represent the concentration of various elements in parts per million (ppm) and converting them into structured PpmTarget objects which can be further processed or analyzed within the system. The NPKTools.Optimizer.PpmTargetParser project is designed as a specialized component within the NPKTools suite, aimed at interpreting and transforming user input into actionable data models.
Telegram Bot QR Code

Developers

This tool was developed by Anatoliy Yermakov.

Special thanks to Artem Frolov for his invaluable assistance and guidance in the development of this project.

Installation:

The modules of the NPKTools suite, including NPKTools.Optimizer, NPKTools.PpmCalc, NPKTools.Optimizer.Preset, and NPKTools.Optimizer.PpmTargetParser, are available as NuGet packages. You can install these packages via NuGet Package Manager in Visual Studio or via the command line interface (CLI) as follows: Using Visual Studio

Open your solution in Visual Studio. Go to Solution Explorer, right-click on your project, and select Manage NuGet Packages. Search for the following packages:

  • NPKTools.Optimizer
  • NPKTools.PpmCalc
  • NPKTools.Optimizer.Preset
  • NPKTools.Optimizer.PpmTargetParser

Install needed package by selecting it from the list and clicking Install.

License:

This project is licensed under the MIT License.

Code Coverage:

The project maintains a high standard of code quality with 99% unit test coverage, ensuring that the features perform as expected and are reliable under various scenarios.

Roadmap:

NPKTools.Optimizer ✔ Completed.

Description: This feature calculates the best combination of fertilizers from a provided collection based on fertilizer attributes and the desired ppm (parts per million) profile. This process optimizes nutrient delivery for specific agricultural needs.

NPKTools.PpmCalc ✔ Completed.

Description: This function computes the PPM (parts per million) of nutrients in a given mixture of fertilizers, taking into account the weights of the fertilizers and the volume of liquid in which they will be dissolved. This is crucial for ensuring the accuracy of nutrient delivery according to the specified agricultural requirements.

NPKTools.Optimizer.Preset: ✔ Completed.

Description: A preconfigured version featuring over 40 fertilizers, built using Fertilizer Composition, and more than 20 fertilizer blending scenarios.

NPKTools.Optimizer.PpmTargetParser ✔ Completed.

Installation, Configuration and Usage

NPKTools.Optimizer

Direct Instantiation

To manually instantiate the components without using DI, use the following example:

// Creating instances manually without DI
    IOptimizationProblemSolver solver = new GoogleOrToolsOptimizationSolver();
    IOptimizationProblemMapper mapper = new OptimizationProblemMapper();
    IFertilizerOptimizer optimizer = new FertilizerOptimizationAdapter(solver, mapper);

Using Dependency Injection For integrating these components into a project that supports Dependency Injection, such as an ASP.NET Core application, configure your services in the Startup.cs or a similar configuration file as follows:

public void ConfigureServices(IServiceCollection services)
{
// Registering services in the DI container
    services.AddSingleton<IOptimizationProblemSolver, GoogleOrToolsOptimizationSolver>();
    services.AddSingleton<IOptimizationProblemMapper, OptimizationProblemMapper>();
    services.AddSingleton<FertilizerOptimizationAdapter>();
}

Example usage

// Setup the optimizer
IOptimizationProblemSolver solver = new GoogleOrToolsOptimizationSolver();
IOptimizationProblemMapper mapper = new OptimizationProblemMapper();
IFertilizerOptimizer optimizer = new FertilizerOptimizationAdapter(solver, mapper);

// Define your PPM target for optimization
PpmTarget target = new PpmTargetBuilder()
    .AddN(150)
    .AddP(50)
    .AddK(200)
    .AddMg(60)
    .AddCa(60)
    .AddS(80)
    .Build();

// Configure the solution finder settings
SolutionFinderSettings settings = new SolutionFinderSettingsBuilder()
    .AddN(1)
    .AddP(1)
    .AddK(1)
    .AddCa(1)
    .AddMg(1)
    .AddS(1)
    .AddCl(1)
    .Build();

// Create a list of fertilizers for optimization
IList<FertilizerOptimizationModel> collection = new List<FertilizerOptimizationModel>()
{
    new FertilizerBuilder().AddNo3(11.863).AddCaNonChelated(16.972).Build(),
    new FertilizerBuilder().AddNo3(13.854).AddK(38.672).Build(),
    new FertilizerBuilder().AddNo3(17.499).AddNh4(17.499).Build(),
    new FertilizerBuilder().AddMgNonChelated(9.861).AddS(13.008).Build(),
    new FertilizerBuilder().AddP(22.761).AddK(28.731).Build(),
    new FertilizerBuilder().AddS(18.401).AddK(44.874).Build(),
    new FertilizerBuilder().AddMgNonChelated(9.479).AddNo3(10.925).Build(),
    new FertilizerBuilder().AddS(18.969).AddMnNonChelated(32.506).Build()
};

// Optimize the solution
Solution solution = optimizer.Optimize(target, collection, settings);

NPKTools.PpmCalc

Direct Instantiation

For direct instantiation without using Dependency Injection, follow this example:

// Manual instantiation of PpmCalculationService
IPpmCalculationService ppmCalculationService = new PpmCalculationService();

Using Dependency Injection For projects that support Dependency Injection, such as ASP.NET Core applications, configure your services in the Startup.cs or a similar configuration file:

public void ConfigureServices(IServiceCollection services)
{
    // Registering PpmCalculationService in the DI container
    services.AddSingleton<IPpmCalculationService, PpmCalculationService>();
}

Example Usage

Here's how you can use the PpmCalculationService to calculate nutrient concentrations:

IPpmCalculationService ppmCalculationService = new PpmCalculationService();

IList<Fertilizer> fertilizers = new List<Fertilizer>
{
    new FertilizerBuilder()
        .AddWeight(0.589)
        .AddNo3(11.863)
        .AddCaNonChelated(16.972)
        .Build(),

    new FertilizerBuilder()
        .AddWeight(0.137)
        .AddNo3(17.499)
        .AddNh4(17.499)
        .Build(),

    new FertilizerBuilder()
        .AddWeight(0.325)
        .AddMgNonChelated(9.861)
        .AddS(13.008)
        .Build(),

    new FertilizerBuilder()
        .AddWeight(0.22)
        .AddP(22.761)
        .AddK(28.731)
        .Build(),

    new FertilizerBuilder()
        .AddWeight(0.305)
        .AddS(18.401)
        .AddK(44.874)
        .Build(),

    new FertilizerBuilder()
        .AddWeight(0.295)
        .AddMgNonChelated(9.479)
        .AddNo3(10.925)
        .Build(),

    new FertilizerBuilder()
        .AddFeNonChelated(20.088)
        .AddS(11.532)
        .AddWeight(0.01)
        .Build(),

    new FertilizerBuilder()
        .AddS(12.841)
        .AddCuNonChelated(25.451)
        .AddWeight(0.0002)
        .Build(),

    new FertilizerBuilder()
        .AddS(18.969)
        .AddMnNonChelated(32.506)
        .AddWeight(0.0017)
        .Build(),

    new FertilizerBuilder()
        .AddS(17.866)
        .AddZnNonChelated(36.433)
        .AddWeight(0.0009)
        .Build(),

    new FertilizerBuilder()
        .AddB(17.483)
        .AddWeight(0.0016)
        .Build(),

    new FertilizerBuilder()
        .AddNa(19.003)
        .AddMo(39.656)
        .AddWeight(0.000126)
        .Build(),

    new FertilizerBuilder()
        .AddCaNonChelated(18.295)
        .AddCl(32.364)
        .AddWeight(3.09E-05)
        .Build(),

    new FertilizerBuilder()
        .AddSi(23.009)
        .AddNa(37.669)
        .AddWeight(4.346E-05)
        .Build(),

    new FertilizerBuilder()
        .AddSe(41.795)
        .AddNa(24.335)
        .AddWeight(2.393E-05)
        .Build()
};

Ppm actualPpm = ppmCalculationService.CalculatePpm(fertilizers, 2);  

NPKTools.Optimizer.Preset

Direct Instantiation

To manually instantiate the components without using DI, use the following example:

// Creating instances manually without DI
        IOptimizationProblemSolver solver = new GoogleOrToolsOptimizationSolver();
        IOptimizationProblemMapper mapper = new OptimizationProblemMapper();
        IFertilizerOptimizer optimizer = new FertilizerOptimizationAdapter(solver, mapper);
        IFertilizerBundleRepository bundles = new FertilizerBundleRepository();        
        IFertilizerOptimizationsService = new FertilizerOptimizationService(optimizer, bundles);

Using Dependency Injection For integrating these components into a project that supports Dependency Injection, such as an ASP.NET Core application, configure your services in the Startup.cs or a similar configuration file as follows:

public void ConfigureServices(IServiceCollection services)
{
    // Registering services in the DI container
    services.AddSingleton<IOptimizationProblemSolver, GoogleOrToolsOptimizationSolver>();
    services.AddSingleton<IOptimizationProblemMapper, OptimizationProblemMapper>();
    services.AddSingleton<IFertilizerOptimizer, FertilizerOptimizationAdapter>();
    services.AddSingleton<IFertilizerBundleRepository, FertilizerBundleRepository>();
    services.AddSingleton<IFertilizerOptimizationService, FertilizerOptimizationService>();
}

Example usage

// Creating instances manually without DI
IOptimizationProblemSolver solver = new GoogleOrToolsOptimizationSolver();
IOptimizationProblemMapper mapper = new OptimizationProblemMapper();
IFertilizerOptimizer optimizer = new FertilizerOptimizationAdapter(solver, mapper);
IFertilizerBundleRepository bundles = new FertilizerBundleRepository();
IFertilizerOptimizationsService fertilizerOptimizationsService = new FertilizerOptimizationService(optimizer, bundles);

// Define your PPM target for optimization
PpmTarget target = new PpmTargetBuilder()
    .AddN(150)
    .AddP(50)
    .AddK(200)
    .AddMg(60)
    .AddCa(60)
    .AddS(80)
    .Build();

// Set the options for matching the macro elements precisely
SolutionFinderSettings settings = new SolutionFinderSettingsBuilder()
    .AddN(1)
    .AddP(1)
    .AddK(1)
    .AddCa(1)
    .AddMg(1)
    .AddS(1)
    .AddCl(1)
    .Build();

// Finding macro solutions based on the specified target
Solutions macroSolutions = fertilizerOptimizationsService.FindMacroSolutions(target);

// Finding micro solutions with a different target
PpmTarget microTarget = new PpmTargetBuilder()
    .AddFe(2)
    .AddCu(0.05)
    .AddMn(0.55)
    .AddZn(0.33)
    .AddB(0.28)
    .AddMo(0.05)
    .AddSi(0.01)
    .AddSe(0.01)
    .Build();

Solutions microSolutions = fertilizerOptimizationsService.FindMicroSolutions(microTarget);

// Combine both macro and micro nutrient optimizations
(Solutions Macro, Solutions Micro) results = fertilizerOptimizationsService.FindSolutions(new PpmTargetBuilder()
    .AddN(150)
    .AddP(50)
    .AddK(200)
    .AddMg(60)
    .AddCa(100)
    .AddS(100)
    .AddFe(2)
    .AddCu(0.05)
    .AddMn(0.55)
    .AddZn(0.33)
    .AddB(0.28)
    .AddMo(0.05)
    .AddCl(0.01)
    .AddSi(0.01)
    .AddSe(0.01)
    .Build());

// You can now access results.Macro and results.Micro for specific optimizations

NPKTools.Optimizer.PpmTargetParser

Direct Instantiation

To manually instantiate the components without using DI, use the following example:

using NPKTools.Optimizer.PpmTargetParser;
using NPKTools.Core.Domain.PpmTarget;

// Manually creating an instance of PpmTargetParser without DI
PpmTargetParser ppmTargetParser = new PpmTargetParser();

Using Dependency Injection For integrating these components into a project that supports Dependency Injection, such as an ASP.NET Core application, configure your services in the Startup.cs or a similar configuration file as follows:

public void ConfigureServices(IServiceCollection services)
{
// Registering services in the DI container
    services.AddSingleton<IPpmTargetParser, PpmTargetParser>();
}

Example usage

 string input = "N=150, P=50, K=200, Ca=40, Mg=30";
 try
 {
    PpmTarget target = ppmTargetParser.Parse(input);
    Console.WriteLine("Parsing successful! Target values are set.");
 }
 catch (Exception ex)
 {
    Console.WriteLine($"Error parsing input: {ex.Message}");
 }

Dependencies

NPKOptimizer

NPKOptimizer.Tests

Contact Information: