elec-1.00
 All Classes Namespaces Files Functions Variables Macros
elecWorld.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 /* This file is part of rl-lib
4  *
5  * Copyright (C) 2010, Herve FREZZA-BUET
6  *
7  * Author : Herve Frezza-Buet
8  *
9  * Contributor :
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public
13  * License (GPL) as published by the Free Software Foundation; either
14  * version 3 of the License, or any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  *
25  * Contact : Herve.Frezza-Buet@supelec.fr
26  *
27  */
28 
29 #include <list>
30 #include <iterator>
31 #include <vector>
32 #include <map>
33 #include <algorithm>
34 #include <iterator>
35 #include <limits>
36 #include <elecConductor.hpp>
37 #include <elecParticle.hpp>
38 #include <cstddef>
39 
40 namespace elec {
41  class World {
42  private:
43  class Connector : public elec::conductor::Disk {
44  public:
45  Connector(const elec::Point& C,
46  double R,
47  double r)
48  : elec::conductor::Disk(C,R,r) {}
49  virtual bool inside(const elec::Point& p) {
50  double dist = elec::d(center,p);
51  return .05 < dist && dist <= radius;
52  }
53  };
54 
55  std::vector<elec::conductor::Metal*> _conductors;
56  std::list<elec::Particle> _particles; // Don't use a vector here, due to push_back reallocation.
57  std::vector<elec::Particle*> _protons;
58  std::vector<elec::Particle*> _electrons;
59  elec::Point _min, _max;
60  unsigned int nb_p, nb_e;
61  unsigned int nb_part;
62  unsigned int nb_cond;
63  bool has_generator;
64  Connector cathode, anode;
65  double ddp;
66 
67  elec::conductor::Metal* owner(const elec::Point& p) {
68  elec::conductor::Metal* res = nullptr;
69  for(auto it = _conductors.begin();
70  it != _conductors.end() && res == nullptr;
71  ++it)
72  if((*it)->inside(p))
73  res = *it;
74  return res;
75  }
76 
77 
78  public:
79 
80  World() : _conductors(), _particles(), _protons(), _electrons(),
81  nb_p(0), nb_e(0), nb_part(0), nb_cond(0), has_generator(false),
82  cathode({0,0},0,1), anode({0,0},0,1),
83  ddp(0) {
84  _min = {std::numeric_limits<double>::max(),std::numeric_limits<double>::max()};
85  _max = {std::numeric_limits<double>::lowest(),std::numeric_limits<double>::lowest()};
86  }
87 
91  void set_generator(const elec::Point& cathode_pos,
92  const elec::Point& anode_pos,
93  double radius, double voltage) {
94  has_generator = true;
95  cathode.radius = radius;
96  anode.radius = radius;
97  cathode.center = cathode_pos;
98  anode.center = anode_pos;
99  ddp = voltage;
100 
101  *this += cathode;
102  *this += anode;
103  }
104 
105  const std::list<elec::Particle>& particles() {return _particles;}
106 
113  conductor.idf = _conductors.size();
114  _conductors.push_back(&conductor);
115  auto bbox = conductor.bounding_box();
116  if(bbox.first.x < _min.x) _min.x = bbox.first.x;
117  if(bbox.first.y < _min.y) _min.y = bbox.first.y;
118  if(bbox.second.x > _max.x) _max.x = bbox.second.x;
119  if(bbox.second.y > _max.y) _max.y = bbox.second.y;
120  return *this;
121  }
122 
123  void add_electron(const elec::Point& pos) {
124  _particles.push_back(elec::electron(pos));
125  ++nb_e;
126  }
127 
128  void add_proton(const elec::Point& pos) {
129  _particles.push_back(elec::proton(pos));
130  ++nb_p;
131  }
132 
137  void add_protons() {
138  double delta = 1/(double)elecPROTONS_PER_UNIT;
139  elec::Point pos;
140  for(pos.x = _min.x; pos.x <= _max.x; pos.x+=delta)
141  for(pos.y = _min.y; pos.y <= _max.y; pos.y+=delta)
142  if(in_new_conductors(pos))
143  add_proton(pos);
144  }
145 
150  void add_electrons(unsigned int nb) {
151  for(unsigned int i=0; i<nb; ++i) {
152  elec::Point pos = elec::uniform(_min,_max);
153  while(!in_new_conductors(pos))
154  pos = elec::uniform(_min,_max);
155  add_electron(pos);
156  }
157  }
158 
163  auto it = _particles.begin();
164  for(std::advance(it,nb_part); it != _particles.end(); ++it) {
165  auto& p = *it;
166  if(p.q > 0)
167  _protons.push_back(&p);
168  else
169  _electrons.push_back(&p);
170  }
171  nb_cond = _conductors.size();
172  nb_part += nb_p + nb_e;
173 
174  nb_p = 0;
175  nb_e = 0;
176  // _min = {std::numeric_limits<double>::max(),std::numeric_limits<double>::max()};
177  // _max = {std::numeric_limits<double>::lowest(),std::numeric_limits<double>::lowest()};
178  }
179 
184  unsigned int nb_protons() {return nb_p;}
185 
186 
192  void sim(double dt, unsigned int nb_splits) {
193  std::random_shuffle(_electrons.begin(), _electrons.end());
194  unsigned int nb = _electrons.size();
195  unsigned int first = 0;
196  unsigned int last;
197  for(unsigned int i = 1; i <= nb_splits; ++i, first = last) {
198  last = (unsigned int)(nb*i/(double)(nb_splits)+.5);
199  sim_partial(dt,_electrons.begin() + first, _electrons.begin() + last);
200  }
201 
202  if(has_generator)
203  update_generator();
204  }
205 
206  private:
207 
208  bool in_new_conductors(const elec::Point& p) {
209  auto cond_ptr = owner(p);
210  return cond_ptr != nullptr
211  && cond_ptr->idf >= nb_cond;
212  }
213 
214  std::vector<elec::Particle*> source_electrons;
215  void update_generator() {
216  // Let us compute the potentials at both sides.
217  double V_plus = elec::V(_particles.begin(), _particles.end(), cathode.center);
218  double V_minus = elec::V(_particles.begin(), _particles.end(), anode.center);
219  double DV = V_plus - V_minus;
220  double EXTRA_V = ddp - DV;
221 
222  Connector* source;
223  Connector* dest;
224  double* V_source;
225  double* V_dest;
226  if(EXTRA_V > 0) {
227  // we need to extract electrons from the cathode to the anode.
228  source = &cathode;
229  dest = &anode;
230  V_source = &V_plus;
231  V_dest = &V_minus;
232  }
233  else {
234  // we need to extract electrons from the anode to the cathode.
235  source = &anode;
236  dest = &cathode;
237  V_source = &V_minus;
238  V_dest = &V_plus;
239  }
240 
241  auto dest_bb = dest->bounding_box();
242 
243  // Let us first regulate the potential by transferring electrons
244  // from source to destination.
245 
246  // We first need to identify the electrons in the source.
247  source_electrons.clear();
248  for(auto e_ptr : _electrons)
249  if(source->inside(e_ptr->pos))
250  source_electrons.push_back(e_ptr);
251  std::random_shuffle(source_electrons.begin(),source_electrons.end());
252 
253  double delta = std::fabs(ddp - (V_plus - V_minus));
254  double delta_prev = delta+1;
255  for(auto it = source_electrons.begin(); it != source_electrons.end() && (delta < delta_prev); ++it) {
256  // Let us choose a random position in dest.
257  elec::Point pos = dest->center;
258  while(!(dest->inside(pos)))
259  pos = elec::uniform(dest_bb.first,dest_bb.second);
260 
261  elec::Particle& e = *(*it);
262  (*V_source) -= elec::V(e,source->center); // Remove from source
263  (*V_dest) -= elec::V(e,dest->center);
264  e.pos = pos;
265  e.speed = 0;
266  (*V_source) += elec::V(e,source->center); // add to dest;
267  (*V_dest) += elec::V(e,dest->center);
268  delta_prev = delta;
269  delta = std::fabs(ddp - (V_plus - V_minus));
270  }
271 
272  // Let us add the remaining electrons at dest
273  while(delta < delta_prev) {
274  elec::Point pos = dest->center;
275  while(!(dest->inside(pos)))
276  pos = elec::uniform(dest_bb.first,dest_bb.second);
277  add_electron(pos);
278  auto e = elec::electron(pos);
279  (*V_source) += elec::V(e,source->center); // add to dest;
280  (*V_dest) += elec::V(e,dest->center);
281  delta_prev = delta;
282  delta = std::fabs(ddp - (V_plus - V_minus));
283  }
285  }
286 
287 
288  void sim_partial(double dt,
289  std::vector<elec::Particle*>::iterator begin,
290  std::vector<elec::Particle*>::iterator end) {
291  std::vector<elec::Point> electrons_field; // at considered electrons
292  std::vector<elec::Point> protons_field; // at considered electrons
293  elec::E_(_electrons.begin(), _electrons.end(),
294  begin,end,
295  std::back_inserter(electrons_field),
296  [](const elec::Particle* p) -> const elec::Particle& {return *p;},
297  [](const elec::Particle* p) -> const elec::Point& {return p->pos;});
298  elec::E_(_protons.begin(), _protons.end(),
299  begin,end,
300  std::back_inserter(protons_field),
301  [](const elec::Particle* p) -> const elec::Particle& {return *p;},
302  [](const elec::Particle* p) -> const elec::Point& {return p->pos;});
303  auto pf = protons_field.begin();
304  auto ef = electrons_field.begin();
305  for(auto it = begin; it != end; ++it, ++pf, ++ef) {
306  elec::Particle& electron = *(*(it));
307  elec::Point force = -(*pf + *ef)*elecFORCE_COEF;
308 
309  auto conductor = owner(electron.pos);
310  if(conductor != nullptr) {
311  // Let us compute the friction.
312  force += conductor->friction(electron);
313 
314  // Let us apply the dynamics law.
315  electron.speed += force*dt/elecELECTROM_MASS;
316  if(electron.speed*electron.speed > elecMAX_SPEED*elecMAX_SPEED)
317  electron.speed = (*electron.speed)*elecMAX_SPEED;
318  elec::Point dp = electron.speed*dt;
319  electron.pos += dp*dt;
320  }
321  else {
322  // this is the Frenet Coordinates
323  elec::Point T = *(-(*pf));
324  elec::Point S = {-T.y, T.x};
325 
326  // We have to keep only the tangential component.
327  elec::Point speed = electron.speed + force*dt/elecELECTROM_MASS;
328  electron.speed = S*(speed*S);
329 
330  // We put the particle back to the conductor (ignoring the speed computation).
331  electron.pos += T*elecISOLATION_COEF+electron.speed*dt;
332  }
333  }
334  }
335  };
336 }
Definition: elecParticle.hpp:36
double V(const Particle &p, const Point &at)
Definition: elecParticle.hpp:134
void add_proton(const elec::Point &pos)
Definition: elecWorld.hpp:128
#define elecFORCE_COEF
Definition: elecParams.hpp:30
unsigned int nb_protons()
Definition: elecWorld.hpp:184
Point E_(const Iter &begin, const Iter &end, const Point &at, const PartOf &part_of)
Definition: elecParticle.hpp:94
void add_electron(const elec::Point &pos)
Definition: elecWorld.hpp:123
virtual std::pair< elec::Point, elec::Point > bounding_box() const =0
const std::list< elec::Particle > & particles()
Definition: elecWorld.hpp:105
ddp(0)
Definition: elecWorld.hpp:83
void add_protons()
Definition: elecWorld.hpp:137
World & operator+=(elec::conductor::Metal &conductor)
Definition: elecWorld.hpp:112
Point speed
Definition: elecParticle.hpp:38
#define elecISOLATION_COEF
Definition: elecParams.hpp:37
Particle electron(const Point &pos)
Definition: elecParticle.hpp:66
Definition: elecPoint.hpp:35
#define elecELECTROM_MASS
Definition: elecParams.hpp:32
void set_generator(const elec::Point &cathode_pos, const elec::Point &anode_pos, double radius, double voltage)
Definition: elecWorld.hpp:91
#define elecMAX_SPEED
Definition: elecParams.hpp:36
Definition: elecWorld.hpp:41
Point pos
Definition: elecParticle.hpp:38
unsigned int idf
Definition: elecConductor.hpp:43
World()
Definition: elecWorld.hpp:80
Definition: elecConductor.hpp:40
double y
Definition: elecPoint.hpp:37
void sim(double dt, unsigned int nb_splits)
Definition: elecWorld.hpp:192
#define elecPROTONS_PER_UNIT
Definition: elecParams.hpp:31
double d(const Point &A, const Point &B)
Definition: elecPoint.hpp:136
Point uniform(const Point &A, const Point &B)
Definition: elecPoint.hpp:125
void end_of_particles()
Definition: elecWorld.hpp:162
double x
Definition: elecPoint.hpp:37
void add_electrons(unsigned int nb)
Definition: elecWorld.hpp:150
Particle proton(const Point &pos)
Definition: elecParticle.hpp:70
Definition: elecConductor.hpp:77