Skip to content

Commit

Permalink
Merge pull request #185 from prabhuramachandran/misc-fixes
Browse files Browse the repository at this point in the history
Misc fixes
  • Loading branch information
prabhuramachandran committed Mar 18, 2019
2 parents 28ed5b7 + 34f8cb6 commit 521551e
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 62 deletions.
23 changes: 20 additions & 3 deletions pysph/examples/dam_break_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
By default the simulation runs for 6 seconds of simulation time.
"""

import numpy as np

from pysph.base.kernels import WendlandQuintic
from pysph.examples._db_geometry import DamBreak3DGeometry
from pysph.solver.application import Application
Expand All @@ -26,27 +28,42 @@
gamma = 7.0
alpha = 0.5
beta = 0.0
c0 = 10.0 * np.sqrt(2.0 * 9.81 * 0.55)


class DamBreak3D(Application):
def initialize(self):
def add_user_options(self, group):
group.add_argument(
'--dx', action='store', type=float, dest='dx', default=dx,
help='Particle spacing.'
)

def consume_user_options(self):
dx = self.options.dx
self.dx = dx
self.geom = DamBreak3DGeometry(
dx=dx, nboundary_layers=nboundary_layers, hdx=hdx, rho0=ro
)
self.co = 10.0 * self.geom.get_max_speed(g=9.81)

def create_scheme(self):
s = WCSPHScheme(
['fluid'], ['boundary'], dim=dim, rho0=ro, c0=self.co,
['fluid'], ['boundary'], dim=dim, rho0=ro, c0=c0,
h0=h0, hdx=hdx, gz=-9.81, alpha=alpha, beta=beta, gamma=gamma,
hg_correction=True, tensile_correction=True
)
return s

def configure_scheme(self):
s = self.scheme
kernel = WendlandQuintic(dim=dim)
h0 = self.dx * hdx
s.configure(h0=h0)
dt = 0.25*h0/(1.1 * self.co)
s.configure_solver(
kernel=kernel, integrator_cls=EPECIntegrator, tf=tf, dt=dt,
adaptive_timestep=True, n_damp=50
)
return s

def create_particles(self):
return self.geom.create_particles()
Expand Down
13 changes: 11 additions & 2 deletions pysph/solver/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,10 @@ def _setup_logging(self):
filename = self.fname + '.log'

if len(filename) > 0:
# This is needed if the application is launched twice,
# as in that case, the old handlers must be removed.
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
lfn = os.path.join(self.output_dir, filename)
format = '%(levelname)s|%(asctime)s|%(name)s|%(message)s'
logging.basicConfig(
Expand Down Expand Up @@ -1333,10 +1337,15 @@ def _write_info(self, filename, **kw):
def _log_solver_info(self, solver):
sep = '-'*70

pa_info = {p.name: p.get_number_of_particles()
for p in solver.particles}
particle_info = '\n '.join(
['%s: %d' % (p.name, len(p.gid)) for p in solver.particles]
['%s: %d' % (k, v) for k, v in pa_info.items()]
)
p_msg = 'No of particles:\n%s\n %s\n%s' % (sep, particle_info, sep)
total = sum(pa_info.values())
if len(pa_info) > 1:
particle_info += '\n Total: %d' % total
p_msg = '%s\nNo of particles:\n %s\n%s' % (sep, particle_info, sep)
self._message(p_msg)

kernel_name = solver.kernel.__class__.__name__
Expand Down
4 changes: 2 additions & 2 deletions pysph/solver/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pysph.sph.acceleration_eval import make_acceleration_evals
from pysph.sph.sph_compiler import SPHCompiler

from pysph.solver.utils import FloatPBar, load, dump
from pysph.solver.utils import ProgressBar, load, dump

import logging
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -415,7 +415,7 @@ def solve(self, show_progress=True):
show = False
else:
show = show_progress
bar = FloatPBar(self.t, self.tf, show=show)
bar = ProgressBar(self.t, self.tf, show=show)
self._epsilon = EPSILON*self.tf

# Initial solution
Expand Down
155 changes: 100 additions & 55 deletions pysph/solver/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,41 @@
"""

# standard imports
import numpy
import sys
import os
import sys
import time

import numpy

import pysph
from pysph.solver.output import load, dump, output_formats # noqa: 401
from pysph.solver.output import gather_array_data as _gather_array_data

HAS_PBAR = True
ASCII_FMT = " 123456789#"
try:
import progressbar
except ImportError:
HAS_PBAR = False
uni_chr = unichr
except NameError:
uni_chr = chr
UTF_FMT = u" " + u''.join(map(uni_chr, range(0x258F, 0x2587, -1)))


def _supports_unicode(fp):
# Taken somewhat from the tqdm package.
if not hasattr(fp, 'encoding'):
return False
else:
encoding = fp.encoding
try:
u'\u2588\u2589'.encode(encoding)
except UnicodeEncodeError:
return False
except Exception:
try:
return encoding.lower().startswith('utf-') or ('U8' == encoding)
except:
return False
else:
return True


def check_array(x, y):
Expand Down Expand Up @@ -50,61 +72,84 @@ def get_array_by_name(arrays, name):
return array


class PBar(object):
"""A simple wrapper around the progressbar so it works if a user has
it installed or not.
"""
def __init__(self, maxval, show=True):
bar = None
def fmt_time(time):
mm, ss = divmod(time, 60)
hh, mm = divmod(mm, 60)
if hh > 0:
s = "%d:%02d:%02d" % (hh, mm, ss)
else:
s = "%02d:%02.1f" % (mm, ss)
return s


class ProgressBar(object):
def __init__(self, ti, tf, show=True, file=None, ascii=False):
if file is None:
self.file = sys.stdout
self.ti = ti
self.tf = tf
self.t = 0.0
self.dt = 1.0
self.start = time.time()
self.count = 0
self.maxval = maxval
self.iter_inc = 1
self.show = show
if HAS_PBAR and show:
widgets = [progressbar.Percentage(), ' ', progressbar.Bar(),
progressbar.ETA()]
bar = progressbar.ProgressBar(widgets=widgets,
maxval=maxval, fd=sys.stdout).start()
elif show:
sys.stdout.write('\r0%')
if show:
sys.stdout.flush()
self.bar = bar

def update(self, delta=1):
self.count += delta
if self.bar is not None:
self.bar.update(self.count)
elif self.show:
sys.stdout.write('\r%d%%' % int(self.count*100/self.maxval))
self.ascii = ascii
if not ascii and not _supports_unicode(self.file):
self.ascii = True
if not self.file.isatty():
self.show = False
self.display()

def _fmt_bar(self, percent, width):
chars = ASCII_FMT if self.ascii else UTF_FMT
nsyms = len(chars) - 1
tens, ones = divmod(int(percent/100 * width * nsyms), nsyms)
end = chars[ones] if ones > 0 else ''
return (chars[-1]*tens + end).ljust(width)

def _fmt_iters(self, iters):
if iters < 1e3:
s = '%d' % iters
elif iters < 1e6:
s = '%.1fk' % (iters/1e3)
elif iters < 1e9:
s = '%.1fM' % (iters/1e6)
return s

def display(self):
if self.show:
sys.stdout.flush()
elapsed = time.time() - self.start
if self.t > 0:
eta = (self.tf - self.t)/self.t * elapsed
else:
eta = 0.0
percent = int(round(self.t/self.tf*100))
bar = self._fmt_bar(percent, 20)
secsperit = elapsed/self.count if self.count > 0 else 0
out = ('{percent:3}%|{bar}|'
' {iters}it | {time:.1e}s [{elapsed}<{eta} | '
'{secsperit:.3f}s/it]').format(
bar=bar, percent=percent, iters=self._fmt_iters(self.count),
time=self.t, elapsed=fmt_time(elapsed), eta=fmt_time(eta),
secsperit=secsperit
)
self.file.write('\r%s' % out.ljust(70))
self.file.flush()

def update(self, t, iter_inc=1):
'''Set the current time and update the number of iterations.
'''
self.dt = t - self.t
self.iter_inc = iter_inc
self.count += iter_inc
self.t = t
self.display()

def finish(self):
if self.bar is not None:
self.bar.finish()
elif self.show:
sys.stdout.write('\r100%\n')
self.display()
if self.show:
sys.stdout.flush()


class FloatPBar(object):
def __init__(self, t_initial, t_final, show=True):
self.ticks = 1000
self.bar = PBar(self.ticks, show)
self.t_initial = t_initial
self.t_final = t_final
self.t_diff = t_final - t_initial

def update(self, time):
expected_count = int((time - self.t_initial)/self.t_diff*self.ticks)
expected_count = min(expected_count, self.ticks)
diff = max(expected_count - self.bar.count, 0)
if diff > 0:
self.bar.update(diff)

def finish(self):
self.bar.finish()
self.file.write('\n')


##############################################################################
Expand Down

0 comments on commit 521551e

Please sign in to comment.