1 /**********************************************************
2  * Version $Id$
3  *********************************************************/
4 
5 ///////////////////////////////////////////////////////////
6 //                                                       //
7 //                         SAGA                          //
8 //                                                       //
9 //      System for Automated Geoscientific Analyses      //
10 //                                                       //
11 //                     Tool Library                      //
12 //                     grid_analysis                     //
13 //                                                       //
14 //-------------------------------------------------------//
15 //                                                       //
16 //              Grid_Iterative_Truncation.cpp            //
17 //                                                       //
18 //                 Copyright (C) 2020 by                 //
19 //                    Volker Wichmann                    //
20 //                                                       //
21 //-------------------------------------------------------//
22 //                                                       //
23 // This file is part of 'SAGA - System for Automated     //
24 // Geoscientific Analyses'. SAGA is free software; you   //
25 // can redistribute it and/or modify it under the terms  //
26 // of the GNU General Public License as published by the //
27 // Free Software Foundation, either version 2 of the     //
28 // License, or (at your option) any later version.       //
29 //                                                       //
30 // SAGA is distributed in the hope that it will be       //
31 // useful, but WITHOUT ANY WARRANTY; without even the    //
32 // implied warranty of MERCHANTABILITY or FITNESS FOR A  //
33 // PARTICULAR PURPOSE. See the GNU General Public        //
34 // License for more details.                             //
35 //                                                       //
36 // You should have received a copy of the GNU General    //
37 // Public License along with this program; if not, see   //
38 // <http://www.gnu.org/licenses/>.                       //
39 //                                                       //
40 //-------------------------------------------------------//
41 //                                                       //
42 //    e-mail:     wichmann@laserdata                     //
43 //                                                       //
44 //    contact:    Volker Wichmann                        //
45 //                LASERDATA GmbH                         //
46 //                Management and analysis of             //
47 //                laserscanning data                     //
48 //                Innsbruck, Austria                     //
49 //                                                       //
50 ///////////////////////////////////////////////////////////
51 
52 //---------------------------------------------------------
53 
54 
55 ///////////////////////////////////////////////////////////
56 //														 //
57 //														 //
58 //														 //
59 ///////////////////////////////////////////////////////////
60 
61 //---------------------------------------------------------
62 #include "Grid_Iterative_Truncation.h"
63 
64 
65 ///////////////////////////////////////////////////////////
66 //														 //
67 //														 //
68 //														 //
69 ///////////////////////////////////////////////////////////
70 
71 //-----------------------------------------------------------
CGrid_Iterative_Truncation(void)72 CGrid_Iterative_Truncation::CGrid_Iterative_Truncation(void)
73 {
74 	Set_Name		(_TL("Iterative Truncation"));
75 
76 	Set_Author		("V. Wichmann (c) 2020");
77 
78 	Parameters.Set_Description(_TW(
79 		"The tool allows one to perform an iterative truncation to a target average. This operation "
80         "iteratively removes the highest values from the input grid until the average of all grid values "
81         "matches the user-specified target average. Instead of simply removing the highest cell values, "
82         "these values can also be replaced by a substitute value.\n"
83 		"An example application is surface soil cleanup, where the highest soil contaminant concentrations "
84         "are removed until targeted post-remediation concentrations are reached. In this case, the "
85         "substitute value would be set to the concentration of clean fill.\n\n"
86 	));
87 
88 
89     Parameters.Add_Grid("",
90 		"INPUT"		, _TL("Input"),
91 		_TL("Grid to analyse."),
92 		PARAMETER_INPUT
93 	);
94 
95 	Parameters.Add_Grid("",
96 		"REMOVED"	, _TL("Removed Cells"),
97 		_TL("Output grid showing the removed cells (1/NoData)."),
98 		PARAMETER_OUTPUT, true, SG_DATATYPE_Char
99 	);
100 
101 	Parameters.Add_Grid("",
102 		"OUTPUT"	, _TL("Output"),
103 		_TL("The modified input grid."),
104 		PARAMETER_OUTPUT_OPTIONAL
105 	);
106 
107     Parameters.Add_Double("",
108         "TARGET", _TL("Target Average"),
109         _TL("The target average."),
110         100.0
111     );
112 
113 	Parameters.Add_Choice("",
114 		"METHOD"	, _TL("Method"),
115 		_TL("Choose a mode of operation."),
116 		CSG_String::Format("%s|%s",
117 			_TL("remove cell values"),
118 			_TL("replace cell values")
119 		),	0
120 	);
121 
122 	Parameters.Add_Double("METHOD",
123 		"SUBSTITUTE", _TL("Substitute Value"),
124 		_TL("The value with which the removed cell values are replaced."),
125 		0.0
126 	);
127 }
128 
129 
130 ///////////////////////////////////////////////////////////
131 //														 //
132 ///////////////////////////////////////////////////////////
133 
134 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)135 int CGrid_Iterative_Truncation::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
136 {
137 	if(	pParameter->Cmp_Identifier("METHOD") )
138 	{
139 		pParameters->Set_Enabled("SUBSTITUTE", pParameter->asInt() == 1);
140 	}
141 
142 	return( 1 );
143 }
144 
145 
146 ///////////////////////////////////////////////////////////
147 //														 //
148 ///////////////////////////////////////////////////////////
149 
150 //---------------------------------------------------------
On_Execute(void)151 bool CGrid_Iterative_Truncation::On_Execute(void)
152 {
153 
154     CSG_Grid    *pInput		= Parameters("INPUT")->asGrid();
155     CSG_Grid    *pRemoved	= Parameters("REMOVED")->asGrid();
156     CSG_Grid    *pOutput	= Parameters("OUTPUT")->asGrid();
157     double      dTarget     = Parameters("TARGET")->asDouble();
158 	int         iMethod		= Parameters("METHOD")->asInt();
159     double      dSubstitute  = Parameters("SUBSTITUTE")->asDouble();
160     double      dSum        = 0.0;
161     sLong       iCells      = 0;
162 
163 
164     //-------------------------------------------------
165     pRemoved->Assign_NoData();
166 
167     if( pOutput != NULL )
168     {
169         pOutput->Assign(pInput);
170     }
171 
172     //-------------------------------------------------
173     for(int y=0; y<Get_NY() && Set_Progress(y); y++)
174     {
175         for(int x=0; x<Get_NX(); x++)
176         {
177             if( !pInput->is_NoData(x, y) )
178             {
179                 dSum += pInput->asDouble(x, y);
180                 iCells++;
181             }
182         }
183     }
184 
185 
186     //-------------------------------------------------
187     if( !pInput->Set_Index() )
188     {
189         Error_Set(_TL("index creation failed"));
190 
191         return( false );
192     }
193 
194     int     x, y;
195     double  dAverage = dSum / iCells;
196     bool    bReached = false;
197 
198     Message_Fmt("\n%s: %.2f", _TL("Average of input grid"), dAverage);
199 
200 
201     //-------------------------------------------------
202 	for(sLong n=0; n<Get_NCells() && Set_Progress_NCells(n); n++)
203 	{
204         if( dAverage <= dTarget )
205         {
206             Message_Fmt("\n%s: %.2f", _TL("Target average reached"), dAverage);
207             bReached = true;
208             break;
209         }
210 
211 		if( pInput->Get_Sorted(n, x, y) )
212         {
213             pRemoved->Set_Value(x, y, 1.0);
214 
215             switch (iMethod)
216             {
217                 default:
218                 case 0:
219                 {
220                     if( pOutput != NULL )
221                     {
222                         pOutput->Set_NoData(x, y);
223                     }
224 
225                     dSum -= pInput->asDouble(x, y);
226                     iCells--;
227                     break;
228                 }
229                 case 1:
230                 {
231                     if( pOutput != NULL )
232                     {
233                         pOutput->Set_Value(x, y, dSubstitute);
234                     }
235 
236                     dSum = dSum - pInput->asDouble(x, y) + dSubstitute;
237                     break;
238                 }
239             }
240 
241             if( iCells > 0 )
242             {
243                 dAverage = dSum / iCells;
244             }
245         }
246     }
247 
248 
249     //-----------------------------------------------------
250     if( !bReached )
251     {
252         Message_Fmt("\n%s: %.2f", _TL("Target average NOT reached"), dAverage);
253         Error_Fmt("\n%s: %.2f", _TL("Target average NOT reached"), dAverage);
254 
255         return( false );
256     }
257 
258 	return( true );
259 }
260 
261 
262 ///////////////////////////////////////////////////////////
263 //														 //
264 //														 //
265 //														 //
266 ///////////////////////////////////////////////////////////
267 
268 //---------------------------------------------------------
269