Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F62510027
adimensional_system_solver.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, May 13, 17:08
Size
13 KB
Mime Type
text/x-c
Expires
Wed, May 15, 17:08 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
17656571
Attached To
rSPECMICP SpecMiCP / ReactMiCP
adimensional_system_solver.cpp
View Options
/*-------------------------------------------------------
- Module : specmicp
- File : reduced_system_solver
- Author : Fabien Georget
Copyright (c) 2014, Fabien Georget <fabieng@princeton.edu>, Princeton University
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Princeton University nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------*/
#include "micpsolver/micpsolver.hpp"
#include "adimensional_system_solver.hpp"
#include "specmicp/adimensional/adimensional_system_solution.hpp"
#include "adimensional_system_pcfm.hpp"
#include "utils/log.hpp"
namespace
specmicp
{
// constructor
// -----------
AdimensionalSystemSolver
::
AdimensionalSystemSolver
(
RawDatabasePtr
data
,
const
AdimensionalSystemConstraints
&
constraints
,
AdimensionalSystemSolverOptions
options
)
:
OptionsHandler
<
AdimensionalSystemSolverOptions
>
(
options
),
m_data
(
data
),
m_system
(
std
::
make_shared
<
AdimensionalSystem
>
(
data
,
constraints
,
options
.
system_options
)),
m_var
(
Vector
::
Zero
(
data
->
nb_component
+
data
->
nb_mineral
))
{}
AdimensionalSystemSolver
::
AdimensionalSystemSolver
(
RawDatabasePtr
data
,
const
AdimensionalSystemConstraints
&
constraints
,
const
AdimensionalSystemSolution
&
previous_solution
,
AdimensionalSystemSolverOptions
options
)
:
OptionsHandler
<
AdimensionalSystemSolverOptions
>
(
options
),
m_data
(
data
),
m_system
(
std
::
make_shared
<
AdimensionalSystem
>
(
data
,
constraints
,
previous_solution
,
options
.
system_options
)),
m_var
(
Vector
::
Zero
(
data
->
nb_component
+
data
->
nb_mineral
))
{}
AdimensionalSystemSolution
AdimensionalSystemSolver
::
get_raw_solution
(
Vector
&
x
)
{
set_true_variable_vector
(
x
);
return
m_system
->
get_solution
(
x
,
m_var
);
}
// Solving the system
// ------------------
micpsolver
::
MiCPPerformance
AdimensionalSystemSolver
::
solve
(
Vector
&
x
,
bool
init
)
{
m_system
->
set_units
(
get_options
().
units_set
);
if
(
init
)
{
m_system
->
reasonable_starting_guess
(
x
);
if
(
get_options
().
use_pcfm
)
{
run_pcfm
(
x
);
}
}
else
if
(
get_options
().
force_pcfm
)
{
run_pcfm
(
x
);
}
set_true_variable_vector
(
x
);
micpsolver
::
MiCPPerformance
perf
=
solve_system
();
int
cnt
=
0
;
while
(
perf
.
return_code
<
micpsolver
::
MiCPSolverReturnCode
::
Success
// != micpsolver::MiCPSolverReturnCode::ResidualMinimized
and
get_options
().
allow_restart
and
cnt
<
3
)
{
WARNING
<<
"Failed to solve the system ! Return code :"
<<
(
int
)
perf
.
return_code
<<
". We shake it up and start again"
;
const
scalar_t
save_penalization_factor
=
get_options
().
solver_options
.
penalization_factor
;
const
scalar_t
save_factor_descent
=
get_options
().
solver_options
.
factor_descent_condition
;
const
bool
save_scaling
=
get_options
().
solver_options
.
use_scaling
;
get_options
().
solver_options
.
factor_descent_condition
*=
1e-2
;
get_options
().
solver_options
.
use_scaling
=
true
;
if
(
save_penalization_factor
==
1
)
get_options
().
solver_options
.
penalization_factor
=
0.8
;
set_return_vector
(
x
);
m_system
->
reasonable_restarting_guess
(
x
);
if
(
get_options
().
use_pcfm
or
get_options
().
force_pcfm
)
run_pcfm
(
x
);
set_true_variable_vector
(
x
);
micpsolver
::
MiCPPerformance
perf2
=
solve_system
();
get_options
().
solver_options
.
penalization_factor
=
save_penalization_factor
;
get_options
().
solver_options
.
factor_descent_condition
=
save_factor_descent
;
get_options
().
solver_options
.
use_scaling
=
save_scaling
;
perf
+=
perf2
;
++
cnt
;
}
if
(
perf
.
return_code
>
micpsolver
::
MiCPSolverReturnCode
::
NotConvergedYet
)
set_return_vector
(
x
);
return
perf
;
}
micpsolver
::
MiCPPerformance
AdimensionalSystemSolver
::
solve_system
()
{
micpsolver
::
MiCPSolver
<
AdimensionalSystem
>
solver
(
m_system
);
solver
.
set_options
(
get_options
().
solver_options
);
solver
.
solve
(
m_var
);
return
solver
.
get_perfs
();
}
// Variables management
// ---------------------
void
AdimensionalSystemSolver
::
set_true_variable_vector
(
const
Vector
&
x
)
{
const
std
::
vector
<
index_t
>&
non_active_component
=
m_system
->
get_non_active_component
();
if
((
non_active_component
.
size
()
==
0
)
and
(
m_system
->
ideq_surf
()
!=
no_equation
))
{
// we still copy the data, if we failed to solve the problem, we can restart
if
(
m_system
->
is_active_component
(
0
))
m_var
=
x
;
// direct copy
else
m_var
=
x
.
block
(
1
,
0
,
x
.
rows
()
-
1
,
1
);
for
(
int
i
=
0
;
i
<
m_var
.
rows
();
++
i
)
{
if
(
m_var
(
i
)
==
-
HUGE_VAL
)
// check for previously undefined value
{
m_var
(
i
)
=
m_system
->
get_options
().
new_component_concentration
;
}
}
}
else
// remove the dof that are not part of the problem
{
uindex_t
new_i
=
0
;
if
(
m_system
->
is_active_component
(
0
))
{
m_var
(
0
)
=
x
(
m_system
->
dof_water
());
++
new_i
;
}
for
(
index_t
i:
m_data
->
range_aqueous_component
())
{
auto
it
=
std
::
find
(
non_active_component
.
begin
(),
non_active_component
.
end
(),
i
);
if
(
it
!=
non_active_component
.
end
())
continue
;
scalar_t
value
=
x
(
m_system
->
dof_component
(
i
));
if
(
value
==
-
HUGE_VAL
)
// check for previously undefined value
{
value
=
m_system
->
get_options
().
new_component_concentration
;
}
m_var
(
new_i
)
=
value
;
++
new_i
;
}
if
(
m_system
->
ideq_surf
()
!=
no_equation
)
{
m_var
(
new_i
)
=
x
(
m_system
->
dof_surface
());
++
new_i
;
}
for
(
index_t
m:
m_data
->
range_mineral
())
{
bool
to_keep
=
true
;
for
(
auto
it
=
non_active_component
.
begin
();
it
!=
non_active_component
.
end
();
++
it
)
{
if
(
m_data
->
nu_mineral
(
m
,
*
it
)
!=
0
)
to_keep
=
false
;
}
if
(
to_keep
)
{
m_var
(
new_i
)
=
x
(
m_system
->
dof_mineral
(
m
));
++
new_i
;
}
}
m_var
.
conservativeResize
(
new_i
);
specmicp_assert
(
new_i
==
(
unsigned
)
m_system
->
total_variables
());
}
}
void
AdimensionalSystemSolver
::
set_return_vector
(
Vector
&
x
)
{
const
std
::
vector
<
index_t
>&
non_active_component
=
m_system
->
get_non_active_component
();
if
(
non_active_component
.
size
()
==
0
and
m_system
->
ideq_surf
()
!=
no_equation
)
// shortcut
{
if
(
m_system
->
is_active_component
(
0
))
x
=
m_var
;
//direct copy
else
x
.
block
(
1
,
0
,
x
.
rows
()
-
1
,
1
)
=
m_var
;
// at that point we should have the correct solution
}
else
{
uindex_t
new_i
=
0
;
if
(
m_system
->
is_active_component
(
0
))
{
x
(
m_system
->
dof_water
())
=
m_var
(
new_i
);
++
new_i
;
}
else
{
x
(
m_system
->
dof_water
())
=
m_system
->
saturation_water
(
x
);
}
for
(
index_t
i:
m_data
->
range_aqueous_component
())
{
auto
it
=
std
::
find
(
non_active_component
.
begin
(),
non_active_component
.
end
(),
i
);
if
(
it
!=
non_active_component
.
end
())
{
x
(
m_system
->
dof_component
(
i
))
=
-
HUGE_VAL
;
continue
;
}
x
(
m_system
->
dof_component
(
i
))
=
m_var
(
new_i
)
;
++
new_i
;
}
if
(
m_system
->
ideq_surf
()
!=
no_equation
)
{
x
(
m_system
->
dof_surface
())
=
m_var
(
new_i
);
++
new_i
;
}
else
x
(
m_system
->
dof_surface
())
=
-
HUGE_VAL
;
for
(
index_t
m:
m_data
->
range_mineral
())
{
bool
to_keep
=
true
;
for
(
const
index_t
&
k:
non_active_component
)
{
if
(
m_data
->
nu_mineral
(
m
,
k
)
!=
0.0
)
to_keep
=
false
;
}
if
(
to_keep
)
{
x
(
m_system
->
dof_mineral
(
m
))
=
m_var
(
new_i
);
++
new_i
;
}
else
{
x
(
m_system
->
dof_mineral
(
m
))
=
0.0
;
}
}
}
}
// PCFM
// ----
void
AdimensionalSystemSolver
::
run_pcfm
(
Vector
&
x
)
{
DEBUG
<<
"Start PCFM initialization."
;
// we set up the true variable
set_true_variable_vector
(
x
);
// The residual is computed to have some point of comparison
Vector
residuals
(
m_system
->
total_variables
());
residuals
.
setZero
();
m_system
->
get_residuals
(
m_var
,
residuals
);
const
scalar_t
res_0
=
residuals
.
norm
();
// the pcfm iterations are executed
AdimensionalSystemPCFM
pcfm_solver
(
m_system
);
PCFMReturnCode
retcode
=
pcfm_solver
.
solve
(
m_var
);
// Check the answer
if
(
retcode
<
PCFMReturnCode
::
Success
)
{
// small prograss is still good enough
m_system
->
get_residuals
(
m_var
,
residuals
);
const
scalar_t
final_residual
=
residuals
.
norm
();
DEBUG
<<
"Final pcfm residuals : "
<<
final_residual
<<
" <? "
<<
res_0
;
if
(
std
::
isfinite
(
final_residual
)
and
final_residual
<
res_0
)
retcode
=
PCFMReturnCode
::
Success
;
}
// if we did a good job, use the solution as initial state
if
(
retcode
==
PCFMReturnCode
::
Success
)
{
DEBUG
<<
"Successful PCFM iterations."
;
set_return_vector
(
x
);
}
else
// we reset
{
DEBUG
<<
"Unsuccessful PCFM iterations. The problem is reset to the initial state."
;
set_true_variable_vector
(
x
);
m_system
->
set_secondary_variables
(
m_var
);
}
}
// Initialisation of variables
// ---------------------------
void
AdimensionalSystemSolver
::
initialise_variables
(
Vector
&
x
,
scalar_t
volume_fraction_water
,
std
::
map
<
std
::
string
,
scalar_t
>
log_molalities
,
std
::
map
<
std
::
string
,
scalar_t
>
volume_fraction_minerals
,
scalar_t
log_free_sorption_site_concentration
)
{
m_system
->
reasonable_starting_guess
(
x
);
database
::
Database
database
(
m_data
);
if
(
volume_fraction_water
<
0
or
volume_fraction_water
>
1
)
{
WARNING
<<
"Initial guess for the volume fraction of water is not between 0 and 1"
;
}
x
(
m_system
->
dof_water
())
=
volume_fraction_water
;
for
(
auto
pair:
log_molalities
)
{
index_t
idc
=
database
.
component_label_to_id
(
pair
.
first
);
if
(
idc
==
no_species
or
idc
==
0
)
{
throw
std
::
invalid_argument
(
"This is not an aqueous component : "
+
pair
.
first
);
}
if
(
pair
.
second
>
0
)
{
WARNING
<<
"Initial molality for : "
<<
pair
.
first
<<
"is bigger than 1 molal."
;
}
x
(
m_system
->
dof_component
(
idc
))
=
pair
.
second
;
}
for
(
auto
pair:
volume_fraction_minerals
)
{
index_t
idm
=
database
.
mineral_label_to_id
(
pair
.
first
);
if
(
idm
==
no_species
)
{
throw
std
::
invalid_argument
(
"This is not a mineral at equilibrium : "
+
pair
.
first
);
}
if
(
pair
.
second
<
0
or
pair
.
second
>
1
)
{
WARNING
<<
"Initial volume fraction for : "
<<
pair
.
first
<<
"is not between 0 and 1."
;
}
x
(
m_system
->
dof_mineral
(
idm
))
=
pair
.
second
;
}
if
(
log_free_sorption_site_concentration
!=
0.0
)
x
(
m_system
->
dof_surface
())
=
log_free_sorption_site_concentration
;
}
void
AdimensionalSystemSolver
::
initialise_variables
(
Vector
&
x
,
scalar_t
volume_fraction_water
,
scalar_t
log_molalities
)
{
m_system
->
reasonable_starting_guess
(
x
);
if
(
volume_fraction_water
<
0
or
volume_fraction_water
>
1
)
{
WARNING
<<
"Initial guess for the volume fraction of water is not between 0 and 1"
;
}
x
(
m_system
->
dof_water
())
=
volume_fraction_water
;
if
(
log_molalities
>
0
)
{
WARNING
<<
"Initial molality for : "
<<
log_molalities
<<
"is bigger than 1 molal."
;
}
x
.
segment
(
1
,
m_data
->
nb_component
-
1
).
setConstant
(
log_molalities
);
}
void
AdimensionalSystemSolver
::
initialise_variables
(
Vector
&
x
,
scalar_t
volume_fraction_water
,
scalar_t
log_molalities
,
scalar_t
log_free_sorption_site_concentration
)
{
initialise_variables
(
x
,
volume_fraction_water
,
log_molalities
);
x
(
m_system
->
dof_surface
())
=
log_free_sorption_site_concentration
;
}
}
// end namespace specmicp
Event Timeline
Log In to Comment