chemmisol 0.1
Loading...
Searching...
No Matches
solver.h
Go to the documentation of this file.
1#ifndef CHEMMISOL_SOLVER_H
2#define CHEMMISOL_SOLVER_H
3
4#include "system.h"
5#include <list>
6#include <random>
7#include <complex>
8
15namespace chemmisol {
16 class ChemicalSystem;
17
21 namespace solver {
29 typedef std::vector<double> X;
30 typedef std::vector<std::complex<double>> CX;
37 typedef std::vector<std::vector<double>> M;
38 typedef std::vector<std::vector<std::complex<double>>> CM;
39
45 template<typename X, typename M>
46 class F {
47 public:
52 static const std::size_t INVALID_INDEX;
53 private:
54 typedef typename X::value_type T;
55 const ChemicalSystem& system;
56 std::size_t x_size;
57 std::size_t f_x_size;
58 std::size_t reaction_offset;
59 std::vector<std::size_t> components_indexes;
60 std::vector<std::size_t> species_indexes;
61 std::vector<std::size_t> revert_species_indexes;
62 X fixed_activities;
63
64 public:
65
72 F(const ChemicalSystem& system);
73
74 std::size_t xSize() const {
75 return x_size;
76 }
77
97 X reducedActivities() const;
98
114 X completeActivities(const X& reduced_activities) const;
115
127 const std::vector<std::size_t>& componentsIndexes() const {
128 return components_indexes;
129 }
130
142 std::size_t reactionOffset() const {
143 return reaction_offset;
144 }
145
157 const std::vector<std::size_t>& speciesIndexes() const {
158 return species_indexes;
159 }
160
204 X f(const X& reduced_activities) const;
205
216 M df(const X& reduced_activities) const;
217 };
218
219 template<typename X, typename M>
220 const std::size_t F<X, M>::INVALID_INDEX = -1;
221
222 template<typename X, typename M>
223 F<X, M>::F(const ChemicalSystem& system) :
224 system(system),
225 x_size(system.getSpecies().size()),
226 f_x_size(system.getComponents().size()
227 + system.getReactions().size()),
228 reaction_offset(system.getComponents().size()),
229 components_indexes(system.getComponents().size()),
230 species_indexes(system.getSpecies().size()),
231 fixed_activities(system.getComponents().size()) {
232 for(const auto& component : system.getComponents())
233 components_indexes[component->getIndex()] = component->getIndex();
234 for(const auto& species : system.getSpecies())
235 species_indexes[species->getIndex()]
236 = species->getIndex();
237
238 std::vector<std::size_t> species_offsets(system.getSpecies().size());
239 for(const auto& component : system.getComponents()) {
240 CHEM_LOGV(6) << "C:" << component->getSpecies()->getName();
241 if(component->isFixed()) {
242 fixed_activities[component->getIndex()]
243 = component->getSpecies()->activity();
244 --x_size;
245 --f_x_size;
246 --reaction_offset;
247 // This component index cannot be used
248 components_indexes[component->getIndex()] = INVALID_INDEX;
249 for(
250 std::size_t i = component->getIndex()+1;
251 i < components_indexes.size(); i++) {
252 --components_indexes[i];
253 }
254 // This species index cannot be used
255 species_indexes[component->getSpecies()->getIndex()] = INVALID_INDEX;
256 for(
257 std::size_t i = component->getSpecies()->getIndex()+1;
258 i < species_indexes.size(); i++) {
259 --species_indexes[i];
260 ++species_offsets[i];
261 }
262 }
263 }
264
265 revert_species_indexes.resize(x_size);
266 for(const auto& species : system.getSpecies()) {
267 if(species_indexes[species->getIndex()] != INVALID_INDEX)
268 revert_species_indexes[species_indexes[species->getIndex()]]
269 = species_indexes[species->getIndex()]+species_offsets[species->getIndex()];
270 }
271 }
272
273 template<typename X, typename M>
275 X x(x_size);
276 for(const auto& species : system.getSpecies())
277 if(species_indexes[species->getIndex()] != INVALID_INDEX)
278 x[species_indexes[species->getIndex()]] = species->activity();
279 return x;
280 }
281
282 template<typename X, typename M>
283 X F<X, M>::completeActivities(const X& reduced_activities) const {
284 X complete_activities(system.getSpecies().size());
285 for(const auto& component : system.getComponents())
286 if(component->isFixed())
287 complete_activities[component->getSpecies()->getIndex()]
288 = component->getSpecies()->activity();
289 for(std::size_t i = 0; i < reduced_activities.size(); i++) {
290 complete_activities[revert_species_indexes[i]]
291 = reduced_activities[i];
292 }
293 return complete_activities;
294 }
295
296 template<typename X, typename M>
297 X F<X, M>::f(const X& activities) const {
298 X f_x(f_x_size);
299 // Complete activities vector with an entry for each species, so
300 // that it is compatible with ChemicalSystem::massConservationLaw()
301 // and ChemicalSystem::distanceToEquilibrium().
302 // TODO: improve this, too many copies for nothing.
303 X complete_activities = completeActivities(activities);
304 {
305 X mass_conservation_results(system.getComponents().size());
306 // Actual total quantity of each component
307 system.massConservationLaw(
308 complete_activities, mass_conservation_results);
309 for(std::size_t i = 0; i < mass_conservation_results.size(); i++) {
310 if(components_indexes[i] != INVALID_INDEX)
311 f_x[components_indexes[i]] = mass_conservation_results[i];
312 }
313 }
314
315 for(const auto& reaction : system.getReactions()) {
316 f_x[reaction_offset+reaction->getIndex()]
317 = system.distanceToEquilibrium(complete_activities, *reaction);
318 }
319 return f_x;
320 }
321
322 template<typename X, typename M>
323 M F<X, M>::df(const X& activities) const {
324 M jacobian(f_x_size);
325 std::vector<std::size_t> component_offsets;
326
327 // Begin mass conservation law equations
328 for(auto& component : system.getComponents()) {
329 if(components_indexes[component->getIndex()] != INVALID_INDEX) {
330 auto& d_f = jacobian[components_indexes[component->getIndex()]];
331 d_f.resize(x_size);
332 d_f[species_indexes[component->getSpecies()->getIndex()]] = 1.0;
333 }
334 }
335 for(const auto& reaction : system.getReactions()) {
336 // Species produced by this reaction
337 const ChemicalSpeciesReagent& species
338 = system.getSpeciesReagent(*reaction);
339 // The index of the species produced by the reaction is
340 // necessarily valid.
341 for(const auto& reagent : system.getComponentReagents(*reaction)) {
342 if(components_indexes[reagent.component->getIndex()] != INVALID_INDEX)
343 jacobian
344 [components_indexes[reagent.component->getIndex()]]
345 [species_indexes[species.species->getIndex()]]
346 = reagent.coefficient/(-species.coefficient);
347 }
348 }
349 // End mass conservation law equations
350
351 // Begin equilibrium equations
352 for(const auto& reaction : system.getReactions()) {
353 auto& d_f = jacobian[reaction_offset + reaction->getIndex()];
354 d_f.resize(x_size);
355 // dx_species: activity variable from which the current reaction
356 // d_f is derived
357 for(const auto& dx_species : system.getSpecies()) {
358 // No derivative to compute for fixed species (that
359 // correspond to invalid indexes)
360 if(species_indexes[dx_species->getIndex()] != INVALID_INDEX) {
361 d_f[species_indexes[dx_species->getIndex()]] = 0.0;
362 T d_reactives = -reaction->getK();
363 T d_products = 1.0;
364 double species_coefficient_in_reactions;
365 bool species_in_reaction = false;
366
367 // Process the produced species
368 const auto& reagent = system.getSpeciesReagent(*reaction);
369 if(reagent.species == dx_species.get()) {
370 // The current reagent is the variable from which
371 // d_f is derived
372 species_coefficient_in_reactions = reagent.coefficient;
373 species_in_reaction = true;
374 } else {
375 // The produced reagent cannot be fixed (currently)
376 // so it necessarily corresponds to a valid index
377 if(activities[species_indexes[reagent.species->getIndex()]] != 0.0) {
378 if(reagent.coefficient < 0.0) {
379 d_products *= std::pow(
380 activities[species_indexes[reagent.species->getIndex()]],
381 -reagent.coefficient
382 );
383 } else {
384 d_reactives *= std::pow(
385 activities[species_indexes[reagent.species->getIndex()]],
386 reagent.coefficient
387 );
388 }
389 } else {
390 if(reagent.coefficient < 0.0) {
391 d_products = 0.0;
392 } else {
393 d_reactives = 0.0;
394 }
395 }
396 }
397
398 // Process reaction components
399 for(const auto& reagent : system.getComponentReagents(*reaction)) {
400 if(reagent.component->getSpecies() == dx_species.get()) {
401 species_coefficient_in_reactions = reagent.coefficient;
402 species_in_reaction = true;
403 } else {
404 T species_activity = 0.0;
405 if(species_indexes[reagent.component->getSpecies()->getIndex()] != INVALID_INDEX) {
406 species_activity = activities[species_indexes[reagent.component->getSpecies()->getIndex()]];
407 } else {
408 species_activity = fixed_activities[reagent.component->getIndex()];
409 }
410 if(species_activity != 0.0) {
411 if(reagent.coefficient < 0.0) {
412 d_products *= std::pow(
413 species_activity,
414 -reagent.coefficient
415 );
416 } else {
417 d_reactives *= std::pow(
418 species_activity,
419 reagent.coefficient
420 );
421 }
422 } else {
423 if(reagent.coefficient < 0.0) {
424 d_products = 0.0;
425 } else {
426 d_reactives = 0.0;
427 }
428 }
429 }
430 }
431 // If the species is not in the reaction,
432 // d_f/dx_species = 0.0
433 if(species_in_reaction) {
434 std::size_t index = species_indexes[dx_species->getIndex()];
435 T activity = activities[index];
436 // d x^a/dx = a * x^(a-1)
437 if(species_coefficient_in_reactions < 0)
438 d_f[index] = -species_coefficient_in_reactions
439 * std::pow(
440 activity,
441 -species_coefficient_in_reactions-1
442 ) * d_products;
443 else
444 d_f[index] = species_coefficient_in_reactions
445 * std::pow(
446 activity,
447 species_coefficient_in_reactions-1
448 ) * d_reactives;
449 }
450 }
451 }
452 }
453 // End equilibrium equations
454 return jacobian;
455 }
456
457 class Solver {
458 public:
459 virtual X solve(const ChemicalSystem& system) const = 0;
460
461 virtual ~Solver() {
462 }
463 };
464
465 class AbsoluteNewton : public Solver {
466 public:
476 X solve(const ChemicalSystem& system) const override;
477 };
478
479 class G {
480 private:
481 const ChemicalSystem& system;
482 const CX a;
483 const CX b;
484 template<typename R>
485 static CX gen_random(R&& random_generator, std::size_t n);
486
487 public:
488 template<typename R>
489 G(
490 const ChemicalSystem& system,
491 std::size_t n,
492 R&& random_generator);
493
494 CX g(const CX& reduced_activities) const;
495 CM dg(const CX& reduced_activities) const;
496 std::list<CX> init_values() const;
497 };
498
500 public:
501 template<typename R>
502 HomotopyContinuation(R&& random_generator);
503
504 X solve(const ChemicalSystem& system) const override;
505 };
506
507 template<typename R>
508 CX G::gen_random(R&& random_generator, std::size_t n) {
509 std::uniform_real_distribution<double> rd(-1, 1);
510 CX x(n);
511 for(auto& _x : x)
512 _x = rd(random_generator);
513 return x;
514 }
515
516 template<typename R>
517 G::G(
518 const ChemicalSystem& system,
519 std::size_t n,
520 R&& random_generator) :
521 system(system),
522 a(gen_random(random_generator, n)),
523 b(gen_random(random_generator, n)) {
524 }
525
529 extern AbsoluteNewton default_solver;
530 }
531}
532#endif /*CHEMMISOL_SOLVER_H*/
std::size_t getIndex() const
Definition species.h:70
Definition system.h:196
const ChemicalSpecies & getSpecies(const std::string &name) const
const std::vector< std::unique_ptr< ChemicalComponent > > & getComponents() const
Definition system.h:661
Definition solver.h:465
X solve(const ChemicalSystem &system) const override
Definition solver.h:46
const std::vector< std::size_t > & componentsIndexes() const
Definition solver.h:127
M df(const X &reduced_activities) const
Definition solver.h:323
const std::vector< std::size_t > & speciesIndexes() const
Definition solver.h:157
std::size_t reactionOffset() const
Definition solver.h:142
X completeActivities(const X &reduced_activities) const
Definition solver.h:283
F(const ChemicalSystem &system)
Definition solver.h:223
X f(const X &reduced_activities) const
Definition solver.h:297
static const std::size_t INVALID_INDEX
Definition solver.h:52
X reducedActivities() const
Definition solver.h:274
Definition solver.h:479
Definition solver.h:457
#define CHEM_LOGV(VERBOSE_LEVEL)
Definition logging.h:26
AbsoluteNewton default_solver
std::vector< std::vector< double > > M
Definition solver.h:37
std::vector< double > X
Definition solver.h:29
Definition chemmisol.h:31
Definition system.h:60
double coefficient
Definition system.h:64
ChemicalSpecies * species
Definition system.h:68